1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 127 PetscInt *sStart, *sEnd; 128 PetscViewerVTKFieldType *ft; 129 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 130 DMLabel depthLabel, ctLabel; 131 132 PetscFunctionBegin; 133 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 134 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 135 PetscCall(DMGetCoordinateDim(dm, &cdim)); 136 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 137 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 138 if (field >= 0) { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 140 } else { 141 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 142 } 143 144 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 145 PetscCall(DMPlexGetDepth(dm, &depth)); 146 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 147 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 148 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 149 const DMPolytopeType ict = (DMPolytopeType)c; 150 PetscInt dep; 151 152 if (ict == DM_POLYTOPE_FV_GHOST) continue; 153 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 154 if (pStart >= 0) { 155 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 156 if (dep != depth - cellHeight) continue; 157 } 158 if (field >= 0) { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 160 } else { 161 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 162 } 163 } 164 165 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 166 *types = 0; 167 168 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 169 if (globalvcdof[c]) ++(*types); 170 } 171 172 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 173 t = 0; 174 if (globalvcdof[DM_NUM_POLYTOPES]) { 175 sStart[t] = vStart; 176 sEnd[t] = vEnd; 177 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 178 ++t; 179 } 180 181 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 182 if (globalvcdof[c]) { 183 const DMPolytopeType ict = (DMPolytopeType)c; 184 185 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 186 sStart[t] = cStart; 187 sEnd[t] = cEnd; 188 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 189 ++t; 190 } 191 } 192 193 if (!*types) { 194 if (field >= 0) { 195 const char *fieldname; 196 197 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 199 } else { 200 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 201 } 202 } 203 204 *ssStart = sStart; 205 *ssEnd = sEnd; 206 *sft = ft; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 211 { 212 PetscFunctionBegin; 213 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 218 { 219 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 220 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 221 222 PetscFunctionBegin; 223 *ft = PETSC_VTK_INVALID; 224 PetscCall(DMGetCoordinateDim(dm, &cdim)); 225 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 226 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 228 if (field >= 0) { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 231 } else { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 234 } 235 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 PetscDS ds; 277 PetscDraw draw = NULL; 278 PetscDrawLG lg; 279 Vec coordinates; 280 const PetscScalar *coords, **sol; 281 PetscReal *vals; 282 PetscInt *Nc; 283 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 284 char **names; 285 286 PetscFunctionBegin; 287 PetscCall(DMGetDS(dm, &ds)); 288 PetscCall(PetscDSGetNumFields(ds, &Nf)); 289 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 290 PetscCall(PetscDSGetComponents(ds, &Nc)); 291 292 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 293 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 294 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 295 296 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 297 for (i = 0, l = 0; i < n; ++i) { 298 const char *vname; 299 300 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 301 for (f = 0; f < Nf; ++f) { 302 PetscObject disc; 303 const char *fname; 304 char tmpname[PETSC_MAX_PATH_LEN]; 305 306 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 307 /* TODO Create names for components */ 308 for (c = 0; c < Nc[f]; ++c, ++l) { 309 PetscCall(PetscObjectGetName(disc, &fname)); 310 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 312 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 313 PetscCall(PetscStrallocpy(tmpname, &names[l])); 314 } 315 } 316 } 317 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 318 /* Just add P_1 support for now */ 319 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 for (v = vStart; v < vEnd; ++v) { 324 PetscScalar *x, *svals; 325 326 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 327 for (i = 0; i < n; ++i) { 328 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 329 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 330 } 331 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 332 } 333 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 334 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 335 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 336 PetscCall(PetscFree3(sol, names, vals)); 337 338 PetscCall(PetscDrawLGDraw(lg)); 339 PetscCall(PetscDrawLGDestroy(&lg)); 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 343 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 344 { 345 DM dm; 346 347 PetscFunctionBegin; 348 PetscCall(VecGetDM(u, &dm)); 349 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 350 PetscFunctionReturn(PETSC_SUCCESS); 351 } 352 353 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 354 { 355 DM dm; 356 PetscSection s; 357 PetscDraw draw, popup; 358 DM cdm; 359 PetscSection coordSection; 360 Vec coordinates; 361 const PetscScalar *array; 362 PetscReal lbound[3], ubound[3]; 363 PetscReal vbound[2], time; 364 PetscBool flg; 365 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 366 const char *name; 367 char title[PETSC_MAX_PATH_LEN]; 368 369 PetscFunctionBegin; 370 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 371 PetscCall(VecGetDM(v, &dm)); 372 PetscCall(DMGetCoordinateDim(dm, &dim)); 373 PetscCall(DMGetLocalSection(dm, &s)); 374 PetscCall(PetscSectionGetNumFields(s, &Nf)); 375 PetscCall(DMGetCoarsenLevel(dm, &level)); 376 PetscCall(DMGetCoordinateDM(dm, &cdm)); 377 PetscCall(DMGetLocalSection(cdm, &coordSection)); 378 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 379 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 380 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 381 382 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 383 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 384 385 PetscCall(VecGetLocalSize(coordinates, &N)); 386 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 387 PetscCall(PetscDrawClear(draw)); 388 389 /* Could implement something like DMDASelectFields() */ 390 for (f = 0; f < Nf; ++f) { 391 DM fdm = dm; 392 Vec fv = v; 393 IS fis; 394 char prefix[PETSC_MAX_PATH_LEN]; 395 const char *fname; 396 397 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 398 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 399 400 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 401 else prefix[0] = '\0'; 402 if (Nf > 1) { 403 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 404 PetscCall(VecGetSubVector(v, fis, &fv)); 405 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 406 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 407 } 408 for (comp = 0; comp < Nc; ++comp, ++w) { 409 PetscInt nmax = 2; 410 411 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 412 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 413 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 414 PetscCall(PetscDrawSetTitle(draw, title)); 415 416 /* TODO Get max and min only for this component */ 417 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 418 if (!flg) { 419 PetscCall(VecMin(fv, NULL, &vbound[0])); 420 PetscCall(VecMax(fv, NULL, &vbound[1])); 421 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 422 } 423 424 PetscCall(PetscDrawGetPopup(draw, &popup)); 425 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 426 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 427 PetscCall(VecGetArrayRead(fv, &array)); 428 for (c = cStart; c < cEnd; ++c) { 429 DMPolytopeType ct; 430 PetscScalar *coords = NULL, *a = NULL; 431 const PetscScalar *coords_arr; 432 PetscBool isDG; 433 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 434 435 PetscCall(DMPlexGetCellType(dm, c, &ct)); 436 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 437 if (a) { 438 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 439 color[1] = color[2] = color[3] = color[0]; 440 } else { 441 PetscScalar *vals = NULL; 442 PetscInt numVals, va; 443 444 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 445 if (!numVals) { 446 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 447 continue; 448 } 449 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 450 switch (numVals / Nc) { 451 case 1: /* P1 Clamped Segment Prism */ 452 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 453 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 454 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 455 break; 456 case 3: /* P1 Triangle */ 457 case 4: /* P1 Quadrangle */ 458 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 459 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 460 break; 461 case 6: /* P2 Triangle */ 462 case 8: /* P2 Quadrangle */ 463 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 464 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 465 break; 466 default: 467 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 468 } 469 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 470 } 471 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 switch (numCoords) { 473 case 6: 474 case 12: /* Localized triangle */ 475 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 476 break; 477 case 8: 478 case 16: /* Localized quadrilateral */ 479 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 480 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 481 } else { 482 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 483 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 484 } 485 break; 486 default: 487 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 488 } 489 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 490 } 491 PetscCall(VecRestoreArrayRead(fv, &array)); 492 PetscCall(PetscDrawFlush(draw)); 493 PetscCall(PetscDrawPause(draw)); 494 PetscCall(PetscDrawSave(draw)); 495 } 496 if (Nf > 1) { 497 PetscCall(VecRestoreSubVector(v, fis, &fv)); 498 PetscCall(ISDestroy(&fis)); 499 PetscCall(DMDestroy(&fdm)); 500 } 501 } 502 PetscFunctionReturn(PETSC_SUCCESS); 503 } 504 505 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 506 { 507 DM dm; 508 PetscDraw draw; 509 PetscInt dim; 510 PetscBool isnull; 511 512 PetscFunctionBegin; 513 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 514 PetscCall(PetscDrawIsNull(draw, &isnull)); 515 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 516 517 PetscCall(VecGetDM(v, &dm)); 518 PetscCall(DMGetCoordinateDim(dm, &dim)); 519 switch (dim) { 520 case 1: 521 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 522 break; 523 case 2: 524 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 525 break; 526 default: 527 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 528 } 529 PetscFunctionReturn(PETSC_SUCCESS); 530 } 531 532 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 533 { 534 DM dm; 535 Vec locv; 536 const char *name; 537 PetscSection section; 538 PetscInt pStart, pEnd; 539 PetscInt numFields; 540 PetscViewerVTKFieldType ft; 541 542 PetscFunctionBegin; 543 PetscCall(VecGetDM(v, &dm)); 544 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 545 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 546 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 547 PetscCall(VecCopy(v, locv)); 548 PetscCall(DMGetLocalSection(dm, §ion)); 549 PetscCall(PetscSectionGetNumFields(section, &numFields)); 550 if (!numFields) { 551 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 552 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 553 } else { 554 PetscInt f; 555 556 for (f = 0; f < numFields; f++) { 557 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 558 if (ft == PETSC_VTK_INVALID) continue; 559 PetscCall(PetscObjectReference((PetscObject)locv)); 560 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 561 } 562 PetscCall(VecDestroy(&locv)); 563 } 564 PetscFunctionReturn(PETSC_SUCCESS); 565 } 566 567 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 568 { 569 DM dm; 570 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 571 572 PetscFunctionBegin; 573 PetscCall(VecGetDM(v, &dm)); 574 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 575 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 576 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 577 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 578 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 579 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 580 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 581 PetscInt i, numFields; 582 PetscObject fe; 583 PetscBool fem = PETSC_FALSE; 584 Vec locv = v; 585 const char *name; 586 PetscInt step; 587 PetscReal time; 588 589 PetscCall(DMGetNumFields(dm, &numFields)); 590 for (i = 0; i < numFields; i++) { 591 PetscCall(DMGetField(dm, i, NULL, &fe)); 592 if (fe->classid == PETSCFE_CLASSID) { 593 fem = PETSC_TRUE; 594 break; 595 } 596 } 597 if (fem) { 598 PetscObject isZero; 599 600 PetscCall(DMGetLocalVector(dm, &locv)); 601 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 602 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 603 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 604 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 605 PetscCall(VecCopy(v, locv)); 606 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 607 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 608 } 609 if (isvtk) { 610 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 611 } else if (ishdf5) { 612 #if defined(PETSC_HAVE_HDF5) 613 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 614 #else 615 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 616 #endif 617 } else if (isdraw) { 618 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 619 } else if (isglvis) { 620 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 621 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 622 PetscCall(VecView_GLVis(locv, viewer)); 623 } else if (iscgns) { 624 #if defined(PETSC_HAVE_CGNS) 625 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 626 #else 627 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 628 #endif 629 } 630 if (fem) { 631 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 632 PetscCall(DMRestoreLocalVector(dm, &locv)); 633 } 634 } else { 635 PetscBool isseq; 636 637 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 638 if (isseq) PetscCall(VecView_Seq(v, viewer)); 639 else PetscCall(VecView_MPI(v, viewer)); 640 } 641 PetscFunctionReturn(PETSC_SUCCESS); 642 } 643 644 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 645 { 646 DM dm; 647 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 648 649 PetscFunctionBegin; 650 PetscCall(VecGetDM(v, &dm)); 651 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 652 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 653 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 654 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 655 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 657 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 658 if (isvtk || isdraw || isglvis || iscgns) { 659 Vec locv; 660 PetscObject isZero; 661 const char *name; 662 663 PetscCall(DMGetLocalVector(dm, &locv)); 664 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 665 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 666 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 667 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 668 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 669 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 670 PetscCall(VecView_Plex_Local(locv, viewer)); 671 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 672 PetscCall(DMRestoreLocalVector(dm, &locv)); 673 /* Call flush for proper logging of VecView timings */ 674 if (isvtk) PetscCall(PetscViewerFlush(viewer)); 675 } else if (ishdf5) { 676 #if defined(PETSC_HAVE_HDF5) 677 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 678 #else 679 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 680 #endif 681 } else if (isexodusii) { 682 #if defined(PETSC_HAVE_EXODUSII) 683 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 684 #else 685 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 686 #endif 687 } else { 688 PetscBool isseq; 689 690 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 691 if (isseq) PetscCall(VecView_Seq(v, viewer)); 692 else PetscCall(VecView_MPI(v, viewer)); 693 } 694 PetscFunctionReturn(PETSC_SUCCESS); 695 } 696 697 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 698 { 699 DM dm; 700 MPI_Comm comm; 701 PetscViewerFormat format; 702 Vec v; 703 PetscBool isvtk, ishdf5; 704 705 PetscFunctionBegin; 706 PetscCall(VecGetDM(originalv, &dm)); 707 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 708 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 709 PetscCall(PetscViewerGetFormat(viewer, &format)); 710 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 711 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 712 if (format == PETSC_VIEWER_NATIVE) { 713 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 714 /* this need a better fix */ 715 if (dm->useNatural) { 716 if (dm->sfNatural) { 717 const char *vecname; 718 PetscInt n, nroots; 719 720 PetscCall(VecGetLocalSize(originalv, &n)); 721 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 722 if (n == nroots) { 723 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 724 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 725 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 726 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 727 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 728 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 729 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 730 } else v = originalv; 731 } else v = originalv; 732 733 if (ishdf5) { 734 #if defined(PETSC_HAVE_HDF5) 735 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 736 #else 737 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 738 #endif 739 } else if (isvtk) { 740 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 741 } else { 742 PetscBool isseq; 743 744 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 745 if (isseq) PetscCall(VecView_Seq(v, viewer)); 746 else PetscCall(VecView_MPI(v, viewer)); 747 } 748 if (v != originalv) PetscCall(VecDestroy(&v)); 749 PetscFunctionReturn(PETSC_SUCCESS); 750 } 751 752 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 753 { 754 DM dm; 755 PetscBool ishdf5; 756 757 PetscFunctionBegin; 758 PetscCall(VecGetDM(v, &dm)); 759 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 760 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 761 if (ishdf5) { 762 DM dmBC; 763 Vec gv; 764 const char *name; 765 766 PetscCall(DMGetOutputDM(dm, &dmBC)); 767 PetscCall(DMGetGlobalVector(dmBC, &gv)); 768 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 769 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 770 PetscCall(VecLoad_Default(gv, viewer)); 771 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 772 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 773 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 774 } else PetscCall(VecLoad_Default(v, viewer)); 775 PetscFunctionReturn(PETSC_SUCCESS); 776 } 777 778 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 779 { 780 DM dm; 781 PetscBool ishdf5, isexodusii, iscgns; 782 783 PetscFunctionBegin; 784 PetscCall(VecGetDM(v, &dm)); 785 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 786 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 787 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 788 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 789 if (ishdf5) { 790 #if defined(PETSC_HAVE_HDF5) 791 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 792 #else 793 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 794 #endif 795 } else if (isexodusii) { 796 #if defined(PETSC_HAVE_EXODUSII) 797 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 798 #else 799 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 800 #endif 801 } else if (iscgns) { 802 #if defined(PETSC_HAVE_CGNS) 803 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 804 #else 805 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 806 #endif 807 } else PetscCall(VecLoad_Default(v, viewer)); 808 PetscFunctionReturn(PETSC_SUCCESS); 809 } 810 811 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 812 { 813 DM dm; 814 PetscViewerFormat format; 815 PetscBool ishdf5; 816 817 PetscFunctionBegin; 818 PetscCall(VecGetDM(originalv, &dm)); 819 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 820 PetscCall(PetscViewerGetFormat(viewer, &format)); 821 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 822 if (format == PETSC_VIEWER_NATIVE) { 823 if (dm->useNatural) { 824 if (dm->sfNatural) { 825 if (ishdf5) { 826 #if defined(PETSC_HAVE_HDF5) 827 Vec v; 828 const char *vecname; 829 830 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 831 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 832 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 833 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 834 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 835 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 836 PetscCall(VecDestroy(&v)); 837 #else 838 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 839 #endif 840 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 841 } 842 } else PetscCall(VecLoad_Default(originalv, viewer)); 843 } 844 PetscFunctionReturn(PETSC_SUCCESS); 845 } 846 847 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 848 { 849 PetscSection coordSection; 850 Vec coordinates; 851 DMLabel depthLabel, celltypeLabel; 852 const char *name[4]; 853 const PetscScalar *a; 854 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 855 856 PetscFunctionBegin; 857 PetscCall(DMGetDimension(dm, &dim)); 858 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 859 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 860 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 861 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 862 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 863 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 864 PetscCall(VecGetArrayRead(coordinates, &a)); 865 name[0] = "vertex"; 866 name[1] = "edge"; 867 name[dim - 1] = "face"; 868 name[dim] = "cell"; 869 for (c = cStart; c < cEnd; ++c) { 870 PetscInt *closure = NULL; 871 PetscInt closureSize, cl, ct; 872 873 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 874 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 875 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 876 PetscCall(PetscViewerASCIIPushTab(viewer)); 877 for (cl = 0; cl < closureSize * 2; cl += 2) { 878 PetscInt point = closure[cl], depth, dof, off, d, p; 879 880 if ((point < pStart) || (point >= pEnd)) continue; 881 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 882 if (!dof) continue; 883 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 884 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 885 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 886 for (p = 0; p < dof / dim; ++p) { 887 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 888 for (d = 0; d < dim; ++d) { 889 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 890 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 891 } 892 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 893 } 894 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 895 } 896 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 897 PetscCall(PetscViewerASCIIPopTab(viewer)); 898 } 899 PetscCall(VecRestoreArrayRead(coordinates, &a)); 900 PetscFunctionReturn(PETSC_SUCCESS); 901 } 902 903 typedef enum { 904 CS_CARTESIAN, 905 CS_POLAR, 906 CS_CYLINDRICAL, 907 CS_SPHERICAL 908 } CoordSystem; 909 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 910 911 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 912 { 913 PetscInt i; 914 915 PetscFunctionBegin; 916 if (dim > 3) { 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 918 } else { 919 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 920 921 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 922 switch (cs) { 923 case CS_CARTESIAN: 924 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 925 break; 926 case CS_POLAR: 927 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 928 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 929 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 930 break; 931 case CS_CYLINDRICAL: 932 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 933 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 934 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 935 trcoords[2] = coords[2]; 936 break; 937 case CS_SPHERICAL: 938 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 939 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 940 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 941 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 942 break; 943 } 944 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 945 } 946 PetscFunctionReturn(PETSC_SUCCESS); 947 } 948 949 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 950 { 951 DM_Plex *mesh = (DM_Plex *)dm->data; 952 DM cdm, cdmCell; 953 PetscSection coordSection, coordSectionCell; 954 Vec coordinates, coordinatesCell; 955 PetscViewerFormat format; 956 957 PetscFunctionBegin; 958 PetscCall(PetscViewerGetFormat(viewer, &format)); 959 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 960 const char *name; 961 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 962 PetscInt pStart, pEnd, p, numLabels, l; 963 PetscMPIInt rank, size; 964 965 PetscCall(DMGetCoordinateDM(dm, &cdm)); 966 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 967 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 968 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 969 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 970 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 971 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 972 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 973 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 974 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 975 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 976 PetscCall(DMGetDimension(dm, &dim)); 977 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 978 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 979 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 980 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 981 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 982 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 983 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 984 for (p = pStart; p < pEnd; ++p) { 985 PetscInt dof, off, s; 986 987 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 988 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 989 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 990 } 991 PetscCall(PetscViewerFlush(viewer)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 993 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 994 for (p = pStart; p < pEnd; ++p) { 995 PetscInt dof, off, c; 996 997 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 998 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 999 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])); 1000 } 1001 PetscCall(PetscViewerFlush(viewer)); 1002 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1003 if (coordSection && coordinates) { 1004 CoordSystem cs = CS_CARTESIAN; 1005 const PetscScalar *array, *arrayCell = NULL; 1006 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 1007 PetscMPIInt rank; 1008 const char *name; 1009 1010 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1011 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1012 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1013 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1014 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1015 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1016 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1017 pStart = PetscMin(pvStart, pcStart); 1018 pEnd = PetscMax(pvEnd, pcEnd); 1019 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1022 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1023 1024 PetscCall(VecGetArrayRead(coordinates, &array)); 1025 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1026 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1027 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1028 for (p = pStart; p < pEnd; ++p) { 1029 PetscInt dof, off; 1030 1031 if (p >= pvStart && p < pvEnd) { 1032 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1033 PetscCall(PetscSectionGetOffset(coordSection, 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, &array[off])); 1037 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1038 } 1039 } 1040 if (cdmCell && p >= pcStart && p < pcEnd) { 1041 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1042 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1043 if (dof) { 1044 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1045 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1046 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1047 } 1048 } 1049 } 1050 PetscCall(PetscViewerFlush(viewer)); 1051 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1052 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1053 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1054 } 1055 PetscCall(DMGetNumLabels(dm, &numLabels)); 1056 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1057 for (l = 0; l < numLabels; ++l) { 1058 DMLabel label; 1059 PetscBool isdepth; 1060 const char *name; 1061 1062 PetscCall(DMGetLabelName(dm, l, &name)); 1063 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1064 if (isdepth) continue; 1065 PetscCall(DMGetLabel(dm, name, &label)); 1066 PetscCall(DMLabelView(label, viewer)); 1067 } 1068 if (size > 1) { 1069 PetscSF sf; 1070 1071 PetscCall(DMGetPointSF(dm, &sf)); 1072 PetscCall(PetscSFView(sf, viewer)); 1073 } 1074 if (mesh->periodic.face_sfs) 1075 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1076 PetscCall(PetscViewerFlush(viewer)); 1077 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1078 const char *name, *color; 1079 const char *defcolors[3] = {"gray", "orange", "green"}; 1080 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1081 char lname[PETSC_MAX_PATH_LEN]; 1082 PetscReal scale = 2.0; 1083 PetscReal tikzscale = 1.0; 1084 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1085 double tcoords[3]; 1086 PetscScalar *coords; 1087 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; 1088 PetscMPIInt rank, size; 1089 char **names, **colors, **lcolors; 1090 PetscBool flg, lflg; 1091 PetscBT wp = NULL; 1092 PetscInt pEnd, pStart; 1093 1094 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1095 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1096 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1097 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1098 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1099 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1100 PetscCall(DMGetDimension(dm, &dim)); 1101 PetscCall(DMPlexGetDepth(dm, &depth)); 1102 PetscCall(DMGetNumLabels(dm, &numLabels)); 1103 numLabels = PetscMax(numLabels, 10); 1104 numColors = 10; 1105 numLColors = 10; 1106 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1107 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1108 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1109 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1110 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1111 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1112 n = 4; 1113 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1114 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1115 n = 4; 1116 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1117 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1118 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1119 if (!useLabels) numLabels = 0; 1120 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1121 if (!useColors) { 1122 numColors = 3; 1123 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1124 } 1125 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1126 if (!useColors) { 1127 numLColors = 4; 1128 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1129 } 1130 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1131 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1132 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1133 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1134 if (depth < dim) plotEdges = PETSC_FALSE; 1135 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1136 1137 /* filter points with labelvalue != labeldefaultvalue */ 1138 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1139 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1140 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1141 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1142 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1143 if (lflg) { 1144 DMLabel lbl; 1145 1146 PetscCall(DMGetLabel(dm, lname, &lbl)); 1147 if (lbl) { 1148 PetscInt val, defval; 1149 1150 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1151 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1152 for (c = pStart; c < pEnd; c++) { 1153 PetscInt *closure = NULL; 1154 PetscInt closureSize; 1155 1156 PetscCall(DMLabelGetValue(lbl, c, &val)); 1157 if (val == defval) continue; 1158 1159 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1160 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1161 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1162 } 1163 } 1164 } 1165 1166 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1167 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1168 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1170 \\documentclass[tikz]{standalone}\n\n\ 1171 \\usepackage{pgflibraryshapes}\n\ 1172 \\usetikzlibrary{backgrounds}\n\ 1173 \\usetikzlibrary{arrows}\n\ 1174 \\begin{document}\n")); 1175 if (size > 1) { 1176 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1177 for (p = 0; p < size; ++p) { 1178 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1179 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1180 } 1181 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1182 } 1183 if (drawHasse) { 1184 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1185 1186 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1187 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1188 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1189 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1190 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1191 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1192 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1193 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1194 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1195 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1196 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1197 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1198 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1199 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1200 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1201 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1202 } 1203 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1204 1205 /* Plot vertices */ 1206 PetscCall(VecGetArray(coordinates, &coords)); 1207 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1208 for (v = vStart; v < vEnd; ++v) { 1209 PetscInt off, dof, d; 1210 PetscBool isLabeled = PETSC_FALSE; 1211 1212 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1213 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1214 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1215 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1216 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1217 for (d = 0; d < dof; ++d) { 1218 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1219 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1220 } 1221 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1222 if (dim == 3) { 1223 PetscReal tmp = tcoords[1]; 1224 tcoords[1] = tcoords[2]; 1225 tcoords[2] = -tmp; 1226 } 1227 for (d = 0; d < dof; ++d) { 1228 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1229 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1230 } 1231 if (drawHasse) color = colors[0 % numColors]; 1232 else color = colors[rank % numColors]; 1233 for (l = 0; l < numLabels; ++l) { 1234 PetscInt val; 1235 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1236 if (val >= 0) { 1237 color = lcolors[l % numLColors]; 1238 isLabeled = PETSC_TRUE; 1239 break; 1240 } 1241 } 1242 if (drawNumbers[0]) { 1243 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1244 } else if (drawColors[0]) { 1245 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1246 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1247 } 1248 PetscCall(VecRestoreArray(coordinates, &coords)); 1249 PetscCall(PetscViewerFlush(viewer)); 1250 /* Plot edges */ 1251 if (plotEdges) { 1252 PetscCall(VecGetArray(coordinates, &coords)); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1254 for (e = eStart; e < eEnd; ++e) { 1255 const PetscInt *cone; 1256 PetscInt coneSize, offA, offB, dof, d; 1257 1258 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1259 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1260 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1261 PetscCall(DMPlexGetCone(dm, e, &cone)); 1262 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1263 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1264 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1265 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1266 for (d = 0; d < dof; ++d) { 1267 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1268 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1269 } 1270 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1271 if (dim == 3) { 1272 PetscReal tmp = tcoords[1]; 1273 tcoords[1] = tcoords[2]; 1274 tcoords[2] = -tmp; 1275 } 1276 for (d = 0; d < dof; ++d) { 1277 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1278 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1279 } 1280 if (drawHasse) color = colors[1 % numColors]; 1281 else color = colors[rank % numColors]; 1282 for (l = 0; l < numLabels; ++l) { 1283 PetscInt val; 1284 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1285 if (val >= 0) { 1286 color = lcolors[l % numLColors]; 1287 break; 1288 } 1289 } 1290 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1291 } 1292 PetscCall(VecRestoreArray(coordinates, &coords)); 1293 PetscCall(PetscViewerFlush(viewer)); 1294 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1295 } 1296 /* Plot cells */ 1297 if (dim == 3 || !drawNumbers[1]) { 1298 for (e = eStart; e < eEnd; ++e) { 1299 const PetscInt *cone; 1300 1301 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1302 color = colors[rank % numColors]; 1303 for (l = 0; l < numLabels; ++l) { 1304 PetscInt val; 1305 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1306 if (val >= 0) { 1307 color = lcolors[l % numLColors]; 1308 break; 1309 } 1310 } 1311 PetscCall(DMPlexGetCone(dm, e, &cone)); 1312 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1313 } 1314 } else { 1315 DMPolytopeType ct; 1316 1317 /* Drawing a 2D polygon */ 1318 for (c = cStart; c < cEnd; ++c) { 1319 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1320 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1321 if (DMPolytopeTypeIsHybrid(ct)) { 1322 const PetscInt *cone; 1323 PetscInt coneSize, e; 1324 1325 PetscCall(DMPlexGetCone(dm, c, &cone)); 1326 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1327 for (e = 0; e < coneSize; ++e) { 1328 const PetscInt *econe; 1329 1330 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1331 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)); 1332 } 1333 } else { 1334 PetscInt *closure = NULL; 1335 PetscInt closureSize, Nv = 0, v; 1336 1337 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1338 for (p = 0; p < closureSize * 2; p += 2) { 1339 const PetscInt point = closure[p]; 1340 1341 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1342 } 1343 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1344 for (v = 0; v <= Nv; ++v) { 1345 const PetscInt vertex = closure[v % Nv]; 1346 1347 if (v > 0) { 1348 if (plotEdges) { 1349 const PetscInt *edge; 1350 PetscInt endpoints[2], ne; 1351 1352 endpoints[0] = closure[v - 1]; 1353 endpoints[1] = vertex; 1354 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1355 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1356 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1357 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1358 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1359 } 1360 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1361 } 1362 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1363 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1364 } 1365 } 1366 } 1367 for (c = cStart; c < cEnd; ++c) { 1368 double ccoords[3] = {0.0, 0.0, 0.0}; 1369 PetscBool isLabeled = PETSC_FALSE; 1370 PetscScalar *cellCoords = NULL; 1371 const PetscScalar *array; 1372 PetscInt numCoords, cdim, d; 1373 PetscBool isDG; 1374 1375 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1376 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1377 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1378 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1379 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1380 for (p = 0; p < numCoords / cdim; ++p) { 1381 for (d = 0; d < cdim; ++d) { 1382 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1383 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1384 } 1385 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1386 if (cdim == 3) { 1387 PetscReal tmp = tcoords[1]; 1388 tcoords[1] = tcoords[2]; 1389 tcoords[2] = -tmp; 1390 } 1391 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1392 } 1393 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1394 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1395 for (d = 0; d < cdim; ++d) { 1396 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1397 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1398 } 1399 if (drawHasse) color = colors[depth % numColors]; 1400 else color = colors[rank % numColors]; 1401 for (l = 0; l < numLabels; ++l) { 1402 PetscInt val; 1403 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1404 if (val >= 0) { 1405 color = lcolors[l % numLColors]; 1406 isLabeled = PETSC_TRUE; 1407 break; 1408 } 1409 } 1410 if (drawNumbers[dim]) { 1411 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1412 } else if (drawColors[dim]) { 1413 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1414 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1415 } 1416 if (drawHasse) { 1417 int height = 0; 1418 1419 color = colors[depth % numColors]; 1420 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1422 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1424 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1425 1426 if (depth > 2) { 1427 color = colors[1 % numColors]; 1428 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1429 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1430 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1431 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1433 } 1434 1435 color = colors[1 % numColors]; 1436 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1437 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1438 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1439 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1440 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1441 1442 color = colors[0 % numColors]; 1443 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1444 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1445 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1446 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1447 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1448 1449 for (p = pStart; p < pEnd; ++p) { 1450 const PetscInt *cone; 1451 PetscInt coneSize, cp; 1452 1453 PetscCall(DMPlexGetCone(dm, p, &cone)); 1454 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1455 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1456 } 1457 } 1458 PetscCall(PetscViewerFlush(viewer)); 1459 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1460 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1461 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1462 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1463 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1464 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1465 PetscCall(PetscFree3(names, colors, lcolors)); 1466 PetscCall(PetscBTDestroy(&wp)); 1467 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1468 Vec cown, acown; 1469 VecScatter sct; 1470 ISLocalToGlobalMapping g2l; 1471 IS gid, acis; 1472 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1473 MPI_Group ggroup, ngroup; 1474 PetscScalar *array, nid; 1475 const PetscInt *idxs; 1476 PetscInt *idxs2, *start, *adjacency, *work; 1477 PetscInt64 lm[3], gm[3]; 1478 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1479 PetscMPIInt d1, d2, rank; 1480 1481 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1482 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1483 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1484 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1485 #endif 1486 if (ncomm != MPI_COMM_NULL) { 1487 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1488 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1489 d1 = 0; 1490 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1491 nid = d2; 1492 PetscCallMPI(MPI_Group_free(&ggroup)); 1493 PetscCallMPI(MPI_Group_free(&ngroup)); 1494 PetscCallMPI(MPI_Comm_free(&ncomm)); 1495 } else nid = 0.0; 1496 1497 /* Get connectivity */ 1498 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1499 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1500 1501 /* filter overlapped local cells */ 1502 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1503 PetscCall(ISGetIndices(gid, &idxs)); 1504 PetscCall(ISGetLocalSize(gid, &cum)); 1505 PetscCall(PetscMalloc1(cum, &idxs2)); 1506 for (c = cStart, cum = 0; c < cEnd; c++) { 1507 if (idxs[c - cStart] < 0) continue; 1508 idxs2[cum++] = idxs[c - cStart]; 1509 } 1510 PetscCall(ISRestoreIndices(gid, &idxs)); 1511 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1512 PetscCall(ISDestroy(&gid)); 1513 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1514 1515 /* support for node-aware cell locality */ 1516 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1517 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1518 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1519 PetscCall(VecGetArray(cown, &array)); 1520 for (c = 0; c < numVertices; c++) array[c] = nid; 1521 PetscCall(VecRestoreArray(cown, &array)); 1522 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1523 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1524 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1525 PetscCall(ISDestroy(&acis)); 1526 PetscCall(VecScatterDestroy(&sct)); 1527 PetscCall(VecDestroy(&cown)); 1528 1529 /* compute edgeCut */ 1530 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1531 PetscCall(PetscMalloc1(cum, &work)); 1532 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1533 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1534 PetscCall(ISDestroy(&gid)); 1535 PetscCall(VecGetArray(acown, &array)); 1536 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1537 PetscInt totl; 1538 1539 totl = start[c + 1] - start[c]; 1540 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1541 for (i = 0; i < totl; i++) { 1542 if (work[i] < 0) { 1543 ect += 1; 1544 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1545 } 1546 } 1547 } 1548 PetscCall(PetscFree(work)); 1549 PetscCall(VecRestoreArray(acown, &array)); 1550 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1551 lm[1] = -numVertices; 1552 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1553 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1554 lm[0] = ect; /* edgeCut */ 1555 lm[1] = ectn; /* node-aware edgeCut */ 1556 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1557 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1558 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1559 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1560 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1561 #else 1562 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1563 #endif 1564 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1565 PetscCall(PetscFree(start)); 1566 PetscCall(PetscFree(adjacency)); 1567 PetscCall(VecDestroy(&acown)); 1568 } else { 1569 const char *name; 1570 PetscInt *sizes, *hybsizes, *ghostsizes; 1571 PetscInt locDepth, depth, cellHeight, dim, d; 1572 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1573 PetscInt numLabels, l, maxSize = 17; 1574 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1575 MPI_Comm comm; 1576 PetscMPIInt size, rank; 1577 1578 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1579 PetscCallMPI(MPI_Comm_size(comm, &size)); 1580 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1581 PetscCall(DMGetDimension(dm, &dim)); 1582 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1583 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1584 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1585 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1586 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1587 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1588 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1589 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1590 gcNum = gcEnd - gcStart; 1591 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1592 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1593 for (d = 0; d <= depth; d++) { 1594 PetscInt Nc[2] = {0, 0}, ict; 1595 1596 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1597 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1598 ict = ct0; 1599 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1600 ct0 = (DMPolytopeType)ict; 1601 for (p = pStart; p < pEnd; ++p) { 1602 DMPolytopeType ct; 1603 1604 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1605 if (ct == ct0) ++Nc[0]; 1606 else ++Nc[1]; 1607 } 1608 if (size < maxSize) { 1609 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1610 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1611 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1612 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1613 for (p = 0; p < size; ++p) { 1614 if (rank == 0) { 1615 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1616 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1617 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1618 } 1619 } 1620 } else { 1621 PetscInt locMinMax[2]; 1622 1623 locMinMax[0] = Nc[0] + Nc[1]; 1624 locMinMax[1] = Nc[0] + Nc[1]; 1625 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1626 locMinMax[0] = Nc[1]; 1627 locMinMax[1] = Nc[1]; 1628 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1629 if (d == depth) { 1630 locMinMax[0] = gcNum; 1631 locMinMax[1] = gcNum; 1632 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1633 } 1634 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1635 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1636 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1637 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1638 } 1639 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1640 } 1641 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1642 { 1643 const PetscReal *maxCell; 1644 const PetscReal *L; 1645 PetscBool localized; 1646 1647 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1648 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1649 if (L || localized) { 1650 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1651 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1652 if (L) { 1653 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1654 for (d = 0; d < dim; ++d) { 1655 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1656 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1657 } 1658 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1659 } 1660 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1661 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1662 } 1663 } 1664 PetscCall(DMGetNumLabels(dm, &numLabels)); 1665 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1666 for (l = 0; l < numLabels; ++l) { 1667 DMLabel label; 1668 const char *name; 1669 PetscInt *values; 1670 PetscInt numValues, v; 1671 1672 PetscCall(DMGetLabelName(dm, l, &name)); 1673 PetscCall(DMGetLabel(dm, name, &label)); 1674 PetscCall(DMLabelGetNumValues(label, &numValues)); 1675 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1676 1677 { // Extract array of DMLabel values so it can be sorted 1678 IS is_values; 1679 const PetscInt *is_values_local = NULL; 1680 1681 PetscCall(DMLabelGetValueIS(label, &is_values)); 1682 PetscCall(ISGetIndices(is_values, &is_values_local)); 1683 PetscCall(PetscMalloc1(numValues, &values)); 1684 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1685 PetscCall(PetscSortInt(numValues, values)); 1686 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1687 PetscCall(ISDestroy(&is_values)); 1688 } 1689 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1690 for (v = 0; v < numValues; ++v) { 1691 PetscInt size; 1692 1693 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1694 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1695 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1696 } 1697 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1698 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1699 PetscCall(PetscFree(values)); 1700 } 1701 { 1702 char **labelNames; 1703 PetscInt Nl = numLabels; 1704 PetscBool flg; 1705 1706 PetscCall(PetscMalloc1(Nl, &labelNames)); 1707 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1708 for (l = 0; l < Nl; ++l) { 1709 DMLabel label; 1710 1711 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1712 if (flg) { 1713 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1714 PetscCall(DMLabelView(label, viewer)); 1715 } 1716 PetscCall(PetscFree(labelNames[l])); 1717 } 1718 PetscCall(PetscFree(labelNames)); 1719 } 1720 /* If no fields are specified, people do not want to see adjacency */ 1721 if (dm->Nf) { 1722 PetscInt f; 1723 1724 for (f = 0; f < dm->Nf; ++f) { 1725 const char *name; 1726 1727 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1728 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1729 PetscCall(PetscViewerASCIIPushTab(viewer)); 1730 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1731 if (dm->fields[f].adjacency[0]) { 1732 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1733 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1734 } else { 1735 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1736 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1737 } 1738 PetscCall(PetscViewerASCIIPopTab(viewer)); 1739 } 1740 } 1741 PetscCall(DMGetCoarseDM(dm, &cdm)); 1742 if (cdm) { 1743 PetscCall(PetscViewerASCIIPushTab(viewer)); 1744 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1745 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1746 PetscCall(PetscViewerASCIIPopTab(viewer)); 1747 } 1748 } 1749 PetscFunctionReturn(PETSC_SUCCESS); 1750 } 1751 1752 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1753 { 1754 DMPolytopeType ct; 1755 PetscMPIInt rank; 1756 PetscInt cdim; 1757 1758 PetscFunctionBegin; 1759 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1760 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1761 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1762 switch (ct) { 1763 case DM_POLYTOPE_SEGMENT: 1764 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1765 switch (cdim) { 1766 case 1: { 1767 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1768 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1769 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1771 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1772 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1773 } break; 1774 case 2: { 1775 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1776 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1777 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1778 1779 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1780 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)); 1781 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)); 1782 } break; 1783 default: 1784 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1785 } 1786 break; 1787 case DM_POLYTOPE_TRIANGLE: 1788 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1789 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1790 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1791 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1792 break; 1793 case DM_POLYTOPE_QUADRILATERAL: 1794 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)); 1795 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)); 1796 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1797 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1798 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1799 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1800 break; 1801 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1802 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)); 1803 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)); 1804 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1805 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1806 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1807 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1808 break; 1809 case DM_POLYTOPE_FV_GHOST: 1810 break; 1811 default: 1812 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1813 } 1814 PetscFunctionReturn(PETSC_SUCCESS); 1815 } 1816 1817 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1818 { 1819 PetscReal centroid[2] = {0., 0.}; 1820 PetscMPIInt rank; 1821 PetscInt fillColor; 1822 1823 PetscFunctionBegin; 1824 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1825 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1826 for (PetscInt v = 0; v < Nv; ++v) { 1827 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1828 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1829 } 1830 for (PetscInt e = 0; e < Nv; ++e) { 1831 refCoords[0] = refVertices[e * 2 + 0]; 1832 refCoords[1] = refVertices[e * 2 + 1]; 1833 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1834 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1835 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1836 } 1837 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1838 for (PetscInt d = 0; d < edgeDiv; ++d) { 1839 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)); 1840 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1841 } 1842 } 1843 PetscFunctionReturn(PETSC_SUCCESS); 1844 } 1845 1846 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1847 { 1848 DMPolytopeType ct; 1849 1850 PetscFunctionBegin; 1851 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1852 switch (ct) { 1853 case DM_POLYTOPE_TRIANGLE: { 1854 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1855 1856 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1857 } break; 1858 case DM_POLYTOPE_QUADRILATERAL: { 1859 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1860 1861 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1862 } break; 1863 default: 1864 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1865 } 1866 PetscFunctionReturn(PETSC_SUCCESS); 1867 } 1868 1869 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1870 { 1871 PetscDraw draw; 1872 DM cdm; 1873 PetscSection coordSection; 1874 Vec coordinates; 1875 PetscReal xyl[3], xyr[3]; 1876 PetscReal *refCoords, *edgeCoords; 1877 PetscBool isnull, drawAffine; 1878 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1879 1880 PetscFunctionBegin; 1881 PetscCall(DMGetCoordinateDim(dm, &dim)); 1882 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1883 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1884 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1885 edgeDiv = cDegree + 1; 1886 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1887 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1888 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1889 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1890 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1891 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1892 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1893 1894 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1895 PetscCall(PetscDrawIsNull(draw, &isnull)); 1896 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1897 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1898 1899 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1900 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1901 PetscCall(PetscDrawClear(draw)); 1902 1903 for (c = cStart; c < cEnd; ++c) { 1904 PetscScalar *coords = NULL; 1905 const PetscScalar *coords_arr; 1906 PetscInt numCoords; 1907 PetscBool isDG; 1908 1909 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1910 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1911 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1912 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1913 } 1914 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1915 PetscCall(PetscDrawFlush(draw)); 1916 PetscCall(PetscDrawPause(draw)); 1917 PetscCall(PetscDrawSave(draw)); 1918 PetscFunctionReturn(PETSC_SUCCESS); 1919 } 1920 1921 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1922 { 1923 DM odm = dm, rdm = dm, cdm; 1924 PetscFE fe; 1925 PetscSpace sp; 1926 PetscClassId id; 1927 PetscInt degree; 1928 PetscBool hoView = PETSC_TRUE; 1929 1930 PetscFunctionBegin; 1931 PetscObjectOptionsBegin((PetscObject)dm); 1932 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1933 PetscOptionsEnd(); 1934 PetscCall(PetscObjectReference((PetscObject)dm)); 1935 *hdm = dm; 1936 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1937 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1938 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1939 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1940 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1941 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1942 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1943 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1944 DM cdm, rcdm; 1945 Mat In; 1946 Vec cl, rcl; 1947 1948 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1949 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1950 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1951 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1952 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1953 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1954 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1955 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1956 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1957 PetscCall(MatMult(In, cl, rcl)); 1958 PetscCall(MatDestroy(&In)); 1959 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1960 PetscCall(DMDestroy(&odm)); 1961 odm = rdm; 1962 } 1963 *hdm = rdm; 1964 PetscFunctionReturn(PETSC_SUCCESS); 1965 } 1966 1967 #if defined(PETSC_HAVE_EXODUSII) 1968 #include <exodusII.h> 1969 #include <petscviewerexodusii.h> 1970 #endif 1971 1972 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1973 { 1974 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1975 char name[PETSC_MAX_PATH_LEN]; 1976 1977 PetscFunctionBegin; 1978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1979 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1980 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1981 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1982 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1983 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1984 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1985 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1986 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1987 if (iascii) { 1988 PetscViewerFormat format; 1989 PetscCall(PetscViewerGetFormat(viewer, &format)); 1990 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1991 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1992 } else if (ishdf5) { 1993 #if defined(PETSC_HAVE_HDF5) 1994 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1995 #else 1996 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1997 #endif 1998 } else if (isvtk) { 1999 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2000 } else if (isdraw) { 2001 DM hdm; 2002 2003 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2004 PetscCall(DMPlexView_Draw(hdm, viewer)); 2005 PetscCall(DMDestroy(&hdm)); 2006 } else if (isglvis) { 2007 PetscCall(DMPlexView_GLVis(dm, viewer)); 2008 #if defined(PETSC_HAVE_EXODUSII) 2009 } else if (isexodus) { 2010 /* 2011 exodusII requires that all sets be part of exactly one cell set. 2012 If the dm does not have a "Cell Sets" label defined, we create one 2013 with ID 1, containing all cells. 2014 Note that if the Cell Sets label is defined but does not cover all cells, 2015 we may still have a problem. This should probably be checked here or in the viewer; 2016 */ 2017 PetscInt numCS; 2018 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2019 if (!numCS) { 2020 PetscInt cStart, cEnd, c; 2021 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2022 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2023 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2024 } 2025 PetscCall(DMView_PlexExodusII(dm, viewer)); 2026 #endif 2027 #if defined(PETSC_HAVE_CGNS) 2028 } else if (iscgns) { 2029 PetscCall(DMView_PlexCGNS(dm, viewer)); 2030 #endif 2031 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2032 /* Optionally view the partition */ 2033 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2034 if (flg) { 2035 Vec ranks; 2036 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2037 PetscCall(VecView(ranks, viewer)); 2038 PetscCall(VecDestroy(&ranks)); 2039 } 2040 /* Optionally view a label */ 2041 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2042 if (flg) { 2043 DMLabel label; 2044 Vec val; 2045 2046 PetscCall(DMGetLabel(dm, name, &label)); 2047 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2048 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2049 PetscCall(VecView(val, viewer)); 2050 PetscCall(VecDestroy(&val)); 2051 } 2052 PetscFunctionReturn(PETSC_SUCCESS); 2053 } 2054 2055 /*@ 2056 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2057 2058 Collective 2059 2060 Input Parameters: 2061 + dm - The `DM` whose topology is to be saved 2062 - viewer - The `PetscViewer` to save it in 2063 2064 Level: advanced 2065 2066 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2067 @*/ 2068 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2069 { 2070 PetscBool ishdf5; 2071 2072 PetscFunctionBegin; 2073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2074 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2075 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2076 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2077 if (ishdf5) { 2078 #if defined(PETSC_HAVE_HDF5) 2079 PetscViewerFormat format; 2080 PetscCall(PetscViewerGetFormat(viewer, &format)); 2081 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2082 IS globalPointNumbering; 2083 2084 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2085 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2086 PetscCall(ISDestroy(&globalPointNumbering)); 2087 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2088 #else 2089 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2090 #endif 2091 } 2092 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2093 PetscFunctionReturn(PETSC_SUCCESS); 2094 } 2095 2096 /*@ 2097 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2098 2099 Collective 2100 2101 Input Parameters: 2102 + dm - The `DM` whose coordinates are to be saved 2103 - viewer - The `PetscViewer` for saving 2104 2105 Level: advanced 2106 2107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2108 @*/ 2109 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2110 { 2111 PetscBool ishdf5; 2112 2113 PetscFunctionBegin; 2114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2115 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2116 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2117 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2118 if (ishdf5) { 2119 #if defined(PETSC_HAVE_HDF5) 2120 PetscViewerFormat format; 2121 PetscCall(PetscViewerGetFormat(viewer, &format)); 2122 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2123 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2124 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2125 #else 2126 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2127 #endif 2128 } 2129 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2130 PetscFunctionReturn(PETSC_SUCCESS); 2131 } 2132 2133 /*@ 2134 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2135 2136 Collective 2137 2138 Input Parameters: 2139 + dm - The `DM` whose labels are to be saved 2140 - viewer - The `PetscViewer` for saving 2141 2142 Level: advanced 2143 2144 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2145 @*/ 2146 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2147 { 2148 PetscBool ishdf5; 2149 2150 PetscFunctionBegin; 2151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2152 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2153 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2154 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2155 if (ishdf5) { 2156 #if defined(PETSC_HAVE_HDF5) 2157 IS globalPointNumbering; 2158 PetscViewerFormat format; 2159 2160 PetscCall(PetscViewerGetFormat(viewer, &format)); 2161 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2162 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2163 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2164 PetscCall(ISDestroy(&globalPointNumbering)); 2165 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2166 #else 2167 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2168 #endif 2169 } 2170 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2171 PetscFunctionReturn(PETSC_SUCCESS); 2172 } 2173 2174 /*@ 2175 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2176 2177 Collective 2178 2179 Input Parameters: 2180 + dm - The `DM` that contains the topology on which the section to be saved is defined 2181 . viewer - The `PetscViewer` for saving 2182 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2183 2184 Level: advanced 2185 2186 Notes: 2187 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. 2188 2189 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. 2190 2191 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2192 @*/ 2193 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2194 { 2195 PetscBool ishdf5; 2196 2197 PetscFunctionBegin; 2198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2199 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2200 if (!sectiondm) sectiondm = dm; 2201 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2202 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2203 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2204 if (ishdf5) { 2205 #if defined(PETSC_HAVE_HDF5) 2206 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2207 #else 2208 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2209 #endif 2210 } 2211 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2212 PetscFunctionReturn(PETSC_SUCCESS); 2213 } 2214 2215 /*@ 2216 DMPlexGlobalVectorView - Saves a global vector 2217 2218 Collective 2219 2220 Input Parameters: 2221 + dm - The `DM` that represents the topology 2222 . viewer - The `PetscViewer` to save data with 2223 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2224 - vec - The global vector to be saved 2225 2226 Level: advanced 2227 2228 Notes: 2229 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. 2230 2231 Calling sequence: 2232 .vb 2233 DMCreate(PETSC_COMM_WORLD, &dm); 2234 DMSetType(dm, DMPLEX); 2235 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2236 DMClone(dm, §iondm); 2237 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2238 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2239 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2240 PetscSectionSetChart(section, pStart, pEnd); 2241 PetscSectionSetUp(section); 2242 DMSetLocalSection(sectiondm, section); 2243 PetscSectionDestroy(§ion); 2244 DMGetGlobalVector(sectiondm, &vec); 2245 PetscObjectSetName((PetscObject)vec, "vec_name"); 2246 DMPlexTopologyView(dm, viewer); 2247 DMPlexSectionView(dm, viewer, sectiondm); 2248 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2249 DMRestoreGlobalVector(sectiondm, &vec); 2250 DMDestroy(§iondm); 2251 DMDestroy(&dm); 2252 .ve 2253 2254 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2255 @*/ 2256 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2257 { 2258 PetscBool ishdf5; 2259 2260 PetscFunctionBegin; 2261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2262 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2263 if (!sectiondm) sectiondm = dm; 2264 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2265 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2266 /* Check consistency */ 2267 { 2268 PetscSection section; 2269 PetscBool includesConstraints; 2270 PetscInt m, m1; 2271 2272 PetscCall(VecGetLocalSize(vec, &m1)); 2273 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2274 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2275 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2276 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2277 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2278 } 2279 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2280 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2281 if (ishdf5) { 2282 #if defined(PETSC_HAVE_HDF5) 2283 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2284 #else 2285 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2286 #endif 2287 } 2288 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2289 PetscFunctionReturn(PETSC_SUCCESS); 2290 } 2291 2292 /*@ 2293 DMPlexLocalVectorView - Saves a local vector 2294 2295 Collective 2296 2297 Input Parameters: 2298 + dm - The `DM` that represents the topology 2299 . viewer - The `PetscViewer` to save data with 2300 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2301 - vec - The local vector to be saved 2302 2303 Level: advanced 2304 2305 Note: 2306 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. 2307 2308 Calling sequence: 2309 .vb 2310 DMCreate(PETSC_COMM_WORLD, &dm); 2311 DMSetType(dm, DMPLEX); 2312 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2313 DMClone(dm, §iondm); 2314 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2315 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2316 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2317 PetscSectionSetChart(section, pStart, pEnd); 2318 PetscSectionSetUp(section); 2319 DMSetLocalSection(sectiondm, section); 2320 DMGetLocalVector(sectiondm, &vec); 2321 PetscObjectSetName((PetscObject)vec, "vec_name"); 2322 DMPlexTopologyView(dm, viewer); 2323 DMPlexSectionView(dm, viewer, sectiondm); 2324 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2325 DMRestoreLocalVector(sectiondm, &vec); 2326 DMDestroy(§iondm); 2327 DMDestroy(&dm); 2328 .ve 2329 2330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2331 @*/ 2332 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2333 { 2334 PetscBool ishdf5; 2335 2336 PetscFunctionBegin; 2337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2338 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2339 if (!sectiondm) sectiondm = dm; 2340 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2341 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2342 /* Check consistency */ 2343 { 2344 PetscSection section; 2345 PetscBool includesConstraints; 2346 PetscInt m, m1; 2347 2348 PetscCall(VecGetLocalSize(vec, &m1)); 2349 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2350 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2351 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2352 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2353 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2354 } 2355 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2356 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2357 if (ishdf5) { 2358 #if defined(PETSC_HAVE_HDF5) 2359 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2360 #else 2361 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2362 #endif 2363 } 2364 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2365 PetscFunctionReturn(PETSC_SUCCESS); 2366 } 2367 2368 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2369 { 2370 PetscBool ishdf5; 2371 2372 PetscFunctionBegin; 2373 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2374 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2375 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2376 if (ishdf5) { 2377 #if defined(PETSC_HAVE_HDF5) 2378 PetscViewerFormat format; 2379 PetscCall(PetscViewerGetFormat(viewer, &format)); 2380 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2381 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2382 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2383 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2384 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2385 PetscFunctionReturn(PETSC_SUCCESS); 2386 #else 2387 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2388 #endif 2389 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2390 } 2391 2392 /*@ 2393 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2394 2395 Collective 2396 2397 Input Parameters: 2398 + dm - The `DM` into which the topology is loaded 2399 - viewer - The `PetscViewer` for the saved topology 2400 2401 Output Parameter: 2402 . 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; 2403 `NULL` if unneeded 2404 2405 Level: advanced 2406 2407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2408 `PetscViewer`, `PetscSF` 2409 @*/ 2410 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2411 { 2412 PetscBool ishdf5; 2413 2414 PetscFunctionBegin; 2415 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2416 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2417 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2418 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2419 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2420 if (ishdf5) { 2421 #if defined(PETSC_HAVE_HDF5) 2422 PetscViewerFormat format; 2423 PetscCall(PetscViewerGetFormat(viewer, &format)); 2424 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2425 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2426 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2427 #else 2428 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2429 #endif 2430 } 2431 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2432 PetscFunctionReturn(PETSC_SUCCESS); 2433 } 2434 2435 /*@ 2436 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2437 2438 Collective 2439 2440 Input Parameters: 2441 + dm - The `DM` into which the coordinates are loaded 2442 . viewer - The `PetscViewer` for the saved coordinates 2443 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2444 2445 Level: advanced 2446 2447 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2448 `PetscSF`, `PetscViewer` 2449 @*/ 2450 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2451 { 2452 PetscBool ishdf5; 2453 2454 PetscFunctionBegin; 2455 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2456 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2457 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2458 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2459 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2460 if (ishdf5) { 2461 #if defined(PETSC_HAVE_HDF5) 2462 PetscViewerFormat format; 2463 PetscCall(PetscViewerGetFormat(viewer, &format)); 2464 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2465 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2466 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2467 #else 2468 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2469 #endif 2470 } 2471 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2472 PetscFunctionReturn(PETSC_SUCCESS); 2473 } 2474 2475 /*@ 2476 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2477 2478 Collective 2479 2480 Input Parameters: 2481 + dm - The `DM` into which the labels are loaded 2482 . viewer - The `PetscViewer` for the saved labels 2483 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2484 2485 Level: advanced 2486 2487 Note: 2488 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2489 2490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2491 `PetscSF`, `PetscViewer` 2492 @*/ 2493 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2494 { 2495 PetscBool ishdf5; 2496 2497 PetscFunctionBegin; 2498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2499 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2500 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2501 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2502 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2503 if (ishdf5) { 2504 #if defined(PETSC_HAVE_HDF5) 2505 PetscViewerFormat format; 2506 2507 PetscCall(PetscViewerGetFormat(viewer, &format)); 2508 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2509 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2510 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2511 #else 2512 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2513 #endif 2514 } 2515 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2516 PetscFunctionReturn(PETSC_SUCCESS); 2517 } 2518 2519 /*@ 2520 DMPlexSectionLoad - Loads section into a `DMPLEX` 2521 2522 Collective 2523 2524 Input Parameters: 2525 + dm - The `DM` that represents the topology 2526 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2527 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2528 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2529 2530 Output Parameters: 2531 + 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) 2532 - 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) 2533 2534 Level: advanced 2535 2536 Notes: 2537 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. 2538 2539 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. 2540 2541 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. 2542 2543 Example using 2 processes: 2544 .vb 2545 NX (number of points on dm): 4 2546 sectionA : the on-disk section 2547 vecA : a vector associated with sectionA 2548 sectionB : sectiondm's local section constructed in this function 2549 vecB (local) : a vector associated with sectiondm's local section 2550 vecB (global) : a vector associated with sectiondm's global section 2551 2552 rank 0 rank 1 2553 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2554 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2555 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2556 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2557 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2558 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2559 sectionB->atlasDof : 1 0 1 | 1 3 2560 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2561 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2562 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2563 .ve 2564 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2565 2566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2567 @*/ 2568 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2569 { 2570 PetscBool ishdf5; 2571 2572 PetscFunctionBegin; 2573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2574 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2575 if (!sectiondm) sectiondm = dm; 2576 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2577 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2578 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2579 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2580 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2581 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2582 if (ishdf5) { 2583 #if defined(PETSC_HAVE_HDF5) 2584 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2585 #else 2586 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2587 #endif 2588 } 2589 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2590 PetscFunctionReturn(PETSC_SUCCESS); 2591 } 2592 2593 /*@ 2594 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2595 2596 Collective 2597 2598 Input Parameters: 2599 + dm - The `DM` that represents the topology 2600 . viewer - The `PetscViewer` that represents the on-disk vector data 2601 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2602 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2603 - vec - The global vector to set values of 2604 2605 Level: advanced 2606 2607 Notes: 2608 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. 2609 2610 Calling sequence: 2611 .vb 2612 DMCreate(PETSC_COMM_WORLD, &dm); 2613 DMSetType(dm, DMPLEX); 2614 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2615 DMPlexTopologyLoad(dm, viewer, &sfX); 2616 DMClone(dm, §iondm); 2617 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2618 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2619 DMGetGlobalVector(sectiondm, &vec); 2620 PetscObjectSetName((PetscObject)vec, "vec_name"); 2621 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2622 DMRestoreGlobalVector(sectiondm, &vec); 2623 PetscSFDestroy(&gsf); 2624 PetscSFDestroy(&sfX); 2625 DMDestroy(§iondm); 2626 DMDestroy(&dm); 2627 .ve 2628 2629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2630 `PetscSF`, `PetscViewer` 2631 @*/ 2632 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2633 { 2634 PetscBool ishdf5; 2635 2636 PetscFunctionBegin; 2637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2638 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2639 if (!sectiondm) sectiondm = dm; 2640 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2641 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2642 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2643 /* Check consistency */ 2644 { 2645 PetscSection section; 2646 PetscBool includesConstraints; 2647 PetscInt m, m1; 2648 2649 PetscCall(VecGetLocalSize(vec, &m1)); 2650 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2651 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2652 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2653 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2654 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2655 } 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 /*@ 2670 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2671 2672 Collective 2673 2674 Input Parameters: 2675 + dm - The `DM` that represents the topology 2676 . viewer - The `PetscViewer` that represents the on-disk vector data 2677 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2678 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2679 - vec - The local vector to set values of 2680 2681 Level: advanced 2682 2683 Notes: 2684 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. 2685 2686 Calling sequence: 2687 .vb 2688 DMCreate(PETSC_COMM_WORLD, &dm); 2689 DMSetType(dm, DMPLEX); 2690 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2691 DMPlexTopologyLoad(dm, viewer, &sfX); 2692 DMClone(dm, §iondm); 2693 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2694 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2695 DMGetLocalVector(sectiondm, &vec); 2696 PetscObjectSetName((PetscObject)vec, "vec_name"); 2697 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2698 DMRestoreLocalVector(sectiondm, &vec); 2699 PetscSFDestroy(&lsf); 2700 PetscSFDestroy(&sfX); 2701 DMDestroy(§iondm); 2702 DMDestroy(&dm); 2703 .ve 2704 2705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2706 `PetscSF`, `PetscViewer` 2707 @*/ 2708 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2709 { 2710 PetscBool ishdf5; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2715 if (!sectiondm) sectiondm = dm; 2716 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2717 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2718 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2719 /* Check consistency */ 2720 { 2721 PetscSection section; 2722 PetscBool includesConstraints; 2723 PetscInt m, m1; 2724 2725 PetscCall(VecGetLocalSize(vec, &m1)); 2726 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2727 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2728 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2729 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2730 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2731 } 2732 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2733 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2734 if (ishdf5) { 2735 #if defined(PETSC_HAVE_HDF5) 2736 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2737 #else 2738 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2739 #endif 2740 } 2741 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2742 PetscFunctionReturn(PETSC_SUCCESS); 2743 } 2744 2745 PetscErrorCode DMDestroy_Plex(DM dm) 2746 { 2747 DM_Plex *mesh = (DM_Plex *)dm->data; 2748 2749 PetscFunctionBegin; 2750 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2751 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2753 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2754 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2755 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2756 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2757 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2758 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2759 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2760 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2761 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2762 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2763 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2764 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2765 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2766 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2767 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2768 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2769 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2770 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2771 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2772 PetscCall(PetscFree(mesh->cones)); 2773 PetscCall(PetscFree(mesh->coneOrientations)); 2774 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2775 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2776 PetscCall(PetscFree(mesh->supports)); 2777 PetscCall(PetscFree(mesh->cellTypes)); 2778 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2779 PetscCall(PetscFree(mesh->tetgenOpts)); 2780 PetscCall(PetscFree(mesh->triangleOpts)); 2781 PetscCall(PetscFree(mesh->transformType)); 2782 PetscCall(PetscFree(mesh->distributionName)); 2783 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2784 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2785 PetscCall(ISDestroy(&mesh->subpointIS)); 2786 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2787 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2788 if (mesh->periodic.face_sfs) { 2789 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2790 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2791 } 2792 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2793 if (mesh->periodic.periodic_points) { 2794 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2795 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2796 } 2797 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2798 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2799 PetscCall(ISDestroy(&mesh->anchorIS)); 2800 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2801 PetscCall(PetscFree(mesh->parents)); 2802 PetscCall(PetscFree(mesh->childIDs)); 2803 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2804 PetscCall(PetscFree(mesh->children)); 2805 PetscCall(DMDestroy(&mesh->referenceTree)); 2806 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2807 PetscCall(PetscFree(mesh->neighbors)); 2808 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2809 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2810 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2811 PetscCall(PetscFree(mesh)); 2812 PetscFunctionReturn(PETSC_SUCCESS); 2813 } 2814 2815 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2816 { 2817 PetscSection sectionGlobal, sectionLocal; 2818 PetscInt bs = -1, mbs; 2819 PetscInt localSize, localStart = 0; 2820 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2821 MatType mtype; 2822 ISLocalToGlobalMapping ltog; 2823 2824 PetscFunctionBegin; 2825 PetscCall(MatInitializePackage()); 2826 mtype = dm->mattype; 2827 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2828 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2829 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2830 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2831 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2832 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2833 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2834 PetscCall(MatSetType(*J, mtype)); 2835 PetscCall(MatSetFromOptions(*J)); 2836 PetscCall(MatGetBlockSize(*J, &mbs)); 2837 if (mbs > 1) bs = mbs; 2838 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2839 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2840 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2841 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2842 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2843 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2844 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2845 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2846 if (!isShell) { 2847 // There are three states with pblocks, since block starts can have no dofs: 2848 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2849 // TRUE) Block Start: The first entry in a block has been added 2850 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2851 PetscBT blst; 2852 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2853 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2854 const PetscInt *perm = NULL; 2855 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2856 PetscInt pStart, pEnd, dof, cdof, num_fields; 2857 2858 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2859 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2860 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2861 2862 PetscCall(PetscCalloc1(localSize, &pblocks)); 2863 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2864 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2865 // We need to process in the permuted order to get block sizes right 2866 for (PetscInt point = pStart; point < pEnd; ++point) { 2867 const PetscInt p = perm ? perm[point] : point; 2868 2869 switch (dm->blocking_type) { 2870 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2871 PetscInt bdof, offset; 2872 2873 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2874 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2875 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2876 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2877 if (dof > 0) { 2878 // State change 2879 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2880 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2881 2882 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2883 // Signal block concatenation 2884 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2885 } 2886 dof = dof < 0 ? -(dof + 1) : dof; 2887 bdof = cdof && (dof - cdof) ? 1 : dof; 2888 if (dof) { 2889 if (bs < 0) { 2890 bs = bdof; 2891 } else if (bs != bdof) { 2892 bs = 1; 2893 } 2894 } 2895 } break; 2896 case DM_BLOCKING_FIELD_NODE: { 2897 for (PetscInt field = 0; field < num_fields; field++) { 2898 PetscInt num_comp, bdof, offset; 2899 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2900 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2901 if (dof < 0) continue; 2902 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2903 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2904 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); 2905 PetscInt num_nodes = dof / num_comp; 2906 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2907 // Handle possibly constant block size (unlikely) 2908 bdof = cdof && (dof - cdof) ? 1 : dof; 2909 if (dof) { 2910 if (bs < 0) { 2911 bs = bdof; 2912 } else if (bs != bdof) { 2913 bs = 1; 2914 } 2915 } 2916 } 2917 } break; 2918 } 2919 } 2920 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2921 /* Must have same blocksize on all procs (some might have no points) */ 2922 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2923 bsLocal[1] = bs; 2924 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2925 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2926 else bs = bsMinMax[0]; 2927 bs = PetscMax(1, bs); 2928 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2929 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2930 PetscCall(MatSetBlockSize(*J, bs)); 2931 PetscCall(MatSetUp(*J)); 2932 } else { 2933 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2934 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2935 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2936 } 2937 if (pblocks) { // Consolidate blocks 2938 PetscInt nblocks = 0; 2939 pblocks[0] = PetscAbs(pblocks[0]); 2940 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2941 if (pblocks[i] == 0) continue; 2942 // Negative block size indicates the blocks should be concatenated 2943 if (pblocks[i] < 0) { 2944 pblocks[i] = -pblocks[i]; 2945 pblocks[nblocks - 1] += pblocks[i]; 2946 } else { 2947 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2948 } 2949 for (PetscInt j = 1; j < pblocks[i]; j++) 2950 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); 2951 } 2952 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2953 } 2954 PetscCall(PetscFree(pblocks)); 2955 } 2956 PetscCall(MatSetDM(*J, dm)); 2957 PetscFunctionReturn(PETSC_SUCCESS); 2958 } 2959 2960 /*@ 2961 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2962 2963 Not Collective 2964 2965 Input Parameter: 2966 . dm - The `DMPLEX` 2967 2968 Output Parameter: 2969 . subsection - The subdomain section 2970 2971 Level: developer 2972 2973 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2974 @*/ 2975 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2976 { 2977 DM_Plex *mesh = (DM_Plex *)dm->data; 2978 2979 PetscFunctionBegin; 2980 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2981 if (!mesh->subdomainSection) { 2982 PetscSection section; 2983 PetscSF sf; 2984 2985 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2986 PetscCall(DMGetLocalSection(dm, §ion)); 2987 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2988 PetscCall(PetscSFDestroy(&sf)); 2989 } 2990 *subsection = mesh->subdomainSection; 2991 PetscFunctionReturn(PETSC_SUCCESS); 2992 } 2993 2994 /*@ 2995 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2996 2997 Not Collective 2998 2999 Input Parameter: 3000 . dm - The `DMPLEX` 3001 3002 Output Parameters: 3003 + pStart - The first mesh point 3004 - pEnd - The upper bound for mesh points 3005 3006 Level: beginner 3007 3008 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3009 @*/ 3010 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3011 { 3012 DM_Plex *mesh = (DM_Plex *)dm->data; 3013 3014 PetscFunctionBegin; 3015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3016 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3017 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3018 PetscFunctionReturn(PETSC_SUCCESS); 3019 } 3020 3021 /*@ 3022 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3023 3024 Not Collective 3025 3026 Input Parameters: 3027 + dm - The `DMPLEX` 3028 . pStart - The first mesh point 3029 - pEnd - The upper bound for mesh points 3030 3031 Level: beginner 3032 3033 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3034 @*/ 3035 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3036 { 3037 DM_Plex *mesh = (DM_Plex *)dm->data; 3038 3039 PetscFunctionBegin; 3040 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3041 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3042 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3043 PetscCall(PetscFree(mesh->cellTypes)); 3044 PetscFunctionReturn(PETSC_SUCCESS); 3045 } 3046 3047 /*@ 3048 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3049 3050 Not Collective 3051 3052 Input Parameters: 3053 + dm - The `DMPLEX` 3054 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3055 3056 Output Parameter: 3057 . size - The cone size for point `p` 3058 3059 Level: beginner 3060 3061 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3062 @*/ 3063 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3064 { 3065 DM_Plex *mesh = (DM_Plex *)dm->data; 3066 3067 PetscFunctionBegin; 3068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3069 PetscAssertPointer(size, 3); 3070 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3071 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3072 PetscFunctionReturn(PETSC_SUCCESS); 3073 } 3074 3075 /*@ 3076 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3077 3078 Not Collective 3079 3080 Input Parameters: 3081 + dm - The `DMPLEX` 3082 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3083 - size - The cone size for point `p` 3084 3085 Level: beginner 3086 3087 Note: 3088 This should be called after `DMPlexSetChart()`. 3089 3090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3091 @*/ 3092 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3093 { 3094 DM_Plex *mesh = (DM_Plex *)dm->data; 3095 3096 PetscFunctionBegin; 3097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3098 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3099 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3100 PetscFunctionReturn(PETSC_SUCCESS); 3101 } 3102 3103 /*@C 3104 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3105 3106 Not Collective 3107 3108 Input Parameters: 3109 + dm - The `DMPLEX` 3110 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3111 3112 Output Parameter: 3113 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3114 3115 Level: beginner 3116 3117 Fortran Notes: 3118 `cone` must be declared with 3119 .vb 3120 PetscInt, pointer :: cone(:) 3121 .ve 3122 3123 You must also call `DMPlexRestoreCone()` after you finish using the array. 3124 `DMPlexRestoreCone()` is not needed/available in C. 3125 3126 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3127 @*/ 3128 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3129 { 3130 DM_Plex *mesh = (DM_Plex *)dm->data; 3131 PetscInt off; 3132 3133 PetscFunctionBegin; 3134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3135 PetscAssertPointer(cone, 3); 3136 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3137 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3138 PetscFunctionReturn(PETSC_SUCCESS); 3139 } 3140 3141 /*@ 3142 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3143 3144 Not Collective 3145 3146 Input Parameters: 3147 + dm - The `DMPLEX` 3148 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3149 3150 Output Parameters: 3151 + pConesSection - `PetscSection` describing the layout of `pCones` 3152 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3153 3154 Level: intermediate 3155 3156 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3157 @*/ 3158 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3159 { 3160 PetscSection cs, newcs; 3161 PetscInt *cones; 3162 PetscInt *newarr = NULL; 3163 PetscInt n; 3164 3165 PetscFunctionBegin; 3166 PetscCall(DMPlexGetCones(dm, &cones)); 3167 PetscCall(DMPlexGetConeSection(dm, &cs)); 3168 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3169 if (pConesSection) *pConesSection = newcs; 3170 if (pCones) { 3171 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3172 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3173 } 3174 PetscFunctionReturn(PETSC_SUCCESS); 3175 } 3176 3177 /*@ 3178 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3179 3180 Not Collective 3181 3182 Input Parameters: 3183 + dm - The `DMPLEX` 3184 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3185 3186 Output Parameter: 3187 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3188 3189 Level: advanced 3190 3191 Notes: 3192 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3193 3194 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3195 3196 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3197 `DMPlexGetDepth()`, `IS` 3198 @*/ 3199 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3200 { 3201 IS *expandedPointsAll; 3202 PetscInt depth; 3203 3204 PetscFunctionBegin; 3205 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3206 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3207 PetscAssertPointer(expandedPoints, 3); 3208 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3209 *expandedPoints = expandedPointsAll[0]; 3210 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3211 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3212 PetscFunctionReturn(PETSC_SUCCESS); 3213 } 3214 3215 /*@ 3216 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3217 (DAG points of depth 0, i.e., without cones). 3218 3219 Not Collective 3220 3221 Input Parameters: 3222 + dm - The `DMPLEX` 3223 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3224 3225 Output Parameters: 3226 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3227 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3228 - sections - (optional) An array of sections which describe mappings from points to their cone points 3229 3230 Level: advanced 3231 3232 Notes: 3233 Like `DMPlexGetConeTuple()` but recursive. 3234 3235 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. 3236 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3237 3238 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\: 3239 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3240 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3241 3242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3243 `DMPlexGetDepth()`, `PetscSection`, `IS` 3244 @*/ 3245 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3246 { 3247 const PetscInt *arr0 = NULL, *cone = NULL; 3248 PetscInt *arr = NULL, *newarr = NULL; 3249 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3250 IS *expandedPoints_; 3251 PetscSection *sections_; 3252 3253 PetscFunctionBegin; 3254 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3255 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3256 if (depth) PetscAssertPointer(depth, 3); 3257 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3258 if (sections) PetscAssertPointer(sections, 5); 3259 PetscCall(ISGetLocalSize(points, &n)); 3260 PetscCall(ISGetIndices(points, &arr0)); 3261 PetscCall(DMPlexGetDepth(dm, &depth_)); 3262 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3263 PetscCall(PetscCalloc1(depth_, §ions_)); 3264 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3265 for (d = depth_ - 1; d >= 0; d--) { 3266 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3267 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3268 for (i = 0; i < n; i++) { 3269 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3270 if (arr[i] >= start && arr[i] < end) { 3271 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3272 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3273 } else { 3274 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3275 } 3276 } 3277 PetscCall(PetscSectionSetUp(sections_[d])); 3278 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3279 PetscCall(PetscMalloc1(newn, &newarr)); 3280 for (i = 0; i < n; i++) { 3281 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3282 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3283 if (cn > 1) { 3284 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3285 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3286 } else { 3287 newarr[co] = arr[i]; 3288 } 3289 } 3290 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3291 arr = newarr; 3292 n = newn; 3293 } 3294 PetscCall(ISRestoreIndices(points, &arr0)); 3295 *depth = depth_; 3296 if (expandedPoints) *expandedPoints = expandedPoints_; 3297 else { 3298 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3299 PetscCall(PetscFree(expandedPoints_)); 3300 } 3301 if (sections) *sections = sections_; 3302 else { 3303 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3304 PetscCall(PetscFree(sections_)); 3305 } 3306 PetscFunctionReturn(PETSC_SUCCESS); 3307 } 3308 3309 /*@ 3310 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3311 3312 Not Collective 3313 3314 Input Parameters: 3315 + dm - The `DMPLEX` 3316 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3317 3318 Output Parameters: 3319 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3320 . expandedPoints - (optional) An array of recursively expanded cones 3321 - sections - (optional) An array of sections which describe mappings from points to their cone points 3322 3323 Level: advanced 3324 3325 Note: 3326 See `DMPlexGetConeRecursive()` 3327 3328 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3329 `DMPlexGetDepth()`, `IS`, `PetscSection` 3330 @*/ 3331 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3332 { 3333 PetscInt d, depth_; 3334 3335 PetscFunctionBegin; 3336 PetscCall(DMPlexGetDepth(dm, &depth_)); 3337 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3338 if (depth) *depth = 0; 3339 if (expandedPoints) { 3340 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3341 PetscCall(PetscFree(*expandedPoints)); 3342 } 3343 if (sections) { 3344 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3345 PetscCall(PetscFree(*sections)); 3346 } 3347 PetscFunctionReturn(PETSC_SUCCESS); 3348 } 3349 3350 /*@ 3351 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 3352 3353 Not Collective 3354 3355 Input Parameters: 3356 + dm - The `DMPLEX` 3357 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3358 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3359 3360 Level: beginner 3361 3362 Note: 3363 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3364 3365 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3366 @*/ 3367 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3368 { 3369 DM_Plex *mesh = (DM_Plex *)dm->data; 3370 PetscInt dof, off, c; 3371 3372 PetscFunctionBegin; 3373 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3374 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3375 if (dof) PetscAssertPointer(cone, 3); 3376 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3377 if (PetscDefined(USE_DEBUG)) { 3378 PetscInt pStart, pEnd; 3379 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3380 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); 3381 for (c = 0; c < dof; ++c) { 3382 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); 3383 mesh->cones[off + c] = cone[c]; 3384 } 3385 } else { 3386 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3387 } 3388 PetscFunctionReturn(PETSC_SUCCESS); 3389 } 3390 3391 /*@C 3392 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3393 3394 Not Collective 3395 3396 Input Parameters: 3397 + dm - The `DMPLEX` 3398 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3399 3400 Output Parameter: 3401 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3402 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3403 3404 Level: beginner 3405 3406 Note: 3407 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3408 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3409 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3410 with the identity. 3411 3412 Fortran Notes: 3413 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3414 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3415 3416 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3417 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3418 @*/ 3419 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3420 { 3421 DM_Plex *mesh = (DM_Plex *)dm->data; 3422 PetscInt off; 3423 3424 PetscFunctionBegin; 3425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3426 if (PetscDefined(USE_DEBUG)) { 3427 PetscInt dof; 3428 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3429 if (dof) PetscAssertPointer(coneOrientation, 3); 3430 } 3431 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3432 3433 *coneOrientation = &mesh->coneOrientations[off]; 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /*@ 3438 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3439 3440 Not Collective 3441 3442 Input Parameters: 3443 + dm - The `DMPLEX` 3444 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3445 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3446 3447 Level: beginner 3448 3449 Notes: 3450 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3451 3452 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3453 3454 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3455 @*/ 3456 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3457 { 3458 DM_Plex *mesh = (DM_Plex *)dm->data; 3459 PetscInt pStart, pEnd; 3460 PetscInt dof, off, c; 3461 3462 PetscFunctionBegin; 3463 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3464 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3465 if (dof) PetscAssertPointer(coneOrientation, 3); 3466 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3467 if (PetscDefined(USE_DEBUG)) { 3468 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3469 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); 3470 for (c = 0; c < dof; ++c) { 3471 PetscInt cdof, o = coneOrientation[c]; 3472 3473 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3474 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); 3475 mesh->coneOrientations[off + c] = o; 3476 } 3477 } else { 3478 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3479 } 3480 PetscFunctionReturn(PETSC_SUCCESS); 3481 } 3482 3483 /*@ 3484 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3485 3486 Not Collective 3487 3488 Input Parameters: 3489 + dm - The `DMPLEX` 3490 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3491 . conePos - The local index in the cone where the point should be put 3492 - conePoint - The mesh point to insert 3493 3494 Level: beginner 3495 3496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3497 @*/ 3498 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3499 { 3500 DM_Plex *mesh = (DM_Plex *)dm->data; 3501 PetscInt pStart, pEnd; 3502 PetscInt dof, off; 3503 3504 PetscFunctionBegin; 3505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3506 if (PetscDefined(USE_DEBUG)) { 3507 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3508 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); 3509 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); 3510 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3511 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); 3512 } 3513 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3514 mesh->cones[off + conePos] = conePoint; 3515 PetscFunctionReturn(PETSC_SUCCESS); 3516 } 3517 3518 /*@ 3519 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3520 3521 Not Collective 3522 3523 Input Parameters: 3524 + dm - The `DMPLEX` 3525 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3526 . conePos - The local index in the cone where the point should be put 3527 - coneOrientation - The point orientation to insert 3528 3529 Level: beginner 3530 3531 Note: 3532 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3533 3534 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3535 @*/ 3536 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3537 { 3538 DM_Plex *mesh = (DM_Plex *)dm->data; 3539 PetscInt pStart, pEnd; 3540 PetscInt dof, off; 3541 3542 PetscFunctionBegin; 3543 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3544 if (PetscDefined(USE_DEBUG)) { 3545 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3546 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); 3547 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3548 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); 3549 } 3550 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3551 mesh->coneOrientations[off + conePos] = coneOrientation; 3552 PetscFunctionReturn(PETSC_SUCCESS); 3553 } 3554 3555 /*@C 3556 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3557 3558 Not collective 3559 3560 Input Parameters: 3561 + dm - The DMPlex 3562 - p - The point, which must lie in the chart set with DMPlexSetChart() 3563 3564 Output Parameters: 3565 + cone - An array of points which are on the in-edges for point `p` 3566 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3567 integer giving the prescription for cone traversal. 3568 3569 Level: beginner 3570 3571 Notes: 3572 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3573 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3574 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3575 with the identity. 3576 3577 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3578 3579 Fortran Notes: 3580 `cone` and `ornt` must be declared with 3581 .vb 3582 PetscInt, pointer :: cone(:) 3583 PetscInt, pointer :: ornt(:) 3584 .ve 3585 3586 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3587 @*/ 3588 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3589 { 3590 DM_Plex *mesh = (DM_Plex *)dm->data; 3591 3592 PetscFunctionBegin; 3593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3594 if (mesh->tr) { 3595 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3596 } else { 3597 PetscInt off; 3598 if (PetscDefined(USE_DEBUG)) { 3599 PetscInt dof; 3600 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3601 if (dof) { 3602 if (cone) PetscAssertPointer(cone, 3); 3603 if (ornt) PetscAssertPointer(ornt, 4); 3604 } 3605 } 3606 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3607 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3608 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3609 } 3610 PetscFunctionReturn(PETSC_SUCCESS); 3611 } 3612 3613 /*@C 3614 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3615 3616 Not Collective 3617 3618 Input Parameters: 3619 + dm - The DMPlex 3620 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3621 . cone - An array of points which are on the in-edges for point p 3622 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3623 integer giving the prescription for cone traversal. 3624 3625 Level: beginner 3626 3627 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3628 @*/ 3629 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3630 { 3631 DM_Plex *mesh = (DM_Plex *)dm->data; 3632 3633 PetscFunctionBegin; 3634 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3635 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3636 PetscFunctionReturn(PETSC_SUCCESS); 3637 } 3638 3639 /*@ 3640 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3641 3642 Not Collective 3643 3644 Input Parameters: 3645 + dm - The `DMPLEX` 3646 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3647 3648 Output Parameter: 3649 . size - The support size for point `p` 3650 3651 Level: beginner 3652 3653 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3654 @*/ 3655 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3656 { 3657 DM_Plex *mesh = (DM_Plex *)dm->data; 3658 3659 PetscFunctionBegin; 3660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3661 PetscAssertPointer(size, 3); 3662 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3663 PetscFunctionReturn(PETSC_SUCCESS); 3664 } 3665 3666 /*@ 3667 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3668 3669 Not Collective 3670 3671 Input Parameters: 3672 + dm - The `DMPLEX` 3673 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3674 - size - The support size for point `p` 3675 3676 Level: beginner 3677 3678 Note: 3679 This should be called after `DMPlexSetChart()`. 3680 3681 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3682 @*/ 3683 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3684 { 3685 DM_Plex *mesh = (DM_Plex *)dm->data; 3686 3687 PetscFunctionBegin; 3688 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3689 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3690 PetscFunctionReturn(PETSC_SUCCESS); 3691 } 3692 3693 /*@C 3694 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3695 3696 Not Collective 3697 3698 Input Parameters: 3699 + dm - The `DMPLEX` 3700 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3701 3702 Output Parameter: 3703 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3704 3705 Level: beginner 3706 3707 Fortran Notes: 3708 `support` must be declared with 3709 .vb 3710 PetscInt, pointer :: support(:) 3711 .ve 3712 3713 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3714 `DMPlexRestoreSupport()` is not needed/available in C. 3715 3716 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3717 @*/ 3718 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3719 { 3720 DM_Plex *mesh = (DM_Plex *)dm->data; 3721 PetscInt off; 3722 3723 PetscFunctionBegin; 3724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3725 PetscAssertPointer(support, 3); 3726 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3727 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3728 PetscFunctionReturn(PETSC_SUCCESS); 3729 } 3730 3731 /*@ 3732 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3733 3734 Not Collective 3735 3736 Input Parameters: 3737 + dm - The `DMPLEX` 3738 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3739 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3740 3741 Level: beginner 3742 3743 Note: 3744 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3745 3746 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3747 @*/ 3748 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3749 { 3750 DM_Plex *mesh = (DM_Plex *)dm->data; 3751 PetscInt pStart, pEnd; 3752 PetscInt dof, off, c; 3753 3754 PetscFunctionBegin; 3755 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3756 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3757 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3758 if (dof) PetscAssertPointer(support, 3); 3759 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3760 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); 3761 for (c = 0; c < dof; ++c) { 3762 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); 3763 mesh->supports[off + c] = support[c]; 3764 } 3765 PetscFunctionReturn(PETSC_SUCCESS); 3766 } 3767 3768 /*@ 3769 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3770 3771 Not Collective 3772 3773 Input Parameters: 3774 + dm - The `DMPLEX` 3775 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3776 . supportPos - The local index in the cone where the point should be put 3777 - supportPoint - The mesh point to insert 3778 3779 Level: beginner 3780 3781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3782 @*/ 3783 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3784 { 3785 DM_Plex *mesh = (DM_Plex *)dm->data; 3786 PetscInt pStart, pEnd; 3787 PetscInt dof, off; 3788 3789 PetscFunctionBegin; 3790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3791 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3792 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3793 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3794 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); 3795 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); 3796 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); 3797 mesh->supports[off + supportPos] = supportPoint; 3798 PetscFunctionReturn(PETSC_SUCCESS); 3799 } 3800 3801 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3802 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3803 { 3804 switch (ct) { 3805 case DM_POLYTOPE_SEGMENT: 3806 if (o == -1) return -2; 3807 break; 3808 case DM_POLYTOPE_TRIANGLE: 3809 if (o == -3) return -1; 3810 if (o == -2) return -3; 3811 if (o == -1) return -2; 3812 break; 3813 case DM_POLYTOPE_QUADRILATERAL: 3814 if (o == -4) return -2; 3815 if (o == -3) return -1; 3816 if (o == -2) return -4; 3817 if (o == -1) return -3; 3818 break; 3819 default: 3820 return o; 3821 } 3822 return o; 3823 } 3824 3825 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3826 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3827 { 3828 switch (ct) { 3829 case DM_POLYTOPE_SEGMENT: 3830 if ((o == -2) || (o == 1)) return -1; 3831 if (o == -1) return 0; 3832 break; 3833 case DM_POLYTOPE_TRIANGLE: 3834 if (o == -3) return -2; 3835 if (o == -2) return -1; 3836 if (o == -1) return -3; 3837 break; 3838 case DM_POLYTOPE_QUADRILATERAL: 3839 if (o == -4) return -2; 3840 if (o == -3) return -1; 3841 if (o == -2) return -4; 3842 if (o == -1) return -3; 3843 break; 3844 default: 3845 return o; 3846 } 3847 return o; 3848 } 3849 3850 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3851 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3852 { 3853 PetscInt pStart, pEnd, p; 3854 3855 PetscFunctionBegin; 3856 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3857 for (p = pStart; p < pEnd; ++p) { 3858 const PetscInt *cone, *ornt; 3859 PetscInt coneSize, c; 3860 3861 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3862 PetscCall(DMPlexGetCone(dm, p, &cone)); 3863 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3864 for (c = 0; c < coneSize; ++c) { 3865 DMPolytopeType ct; 3866 const PetscInt o = ornt[c]; 3867 3868 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3869 switch (ct) { 3870 case DM_POLYTOPE_SEGMENT: 3871 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3872 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3873 break; 3874 case DM_POLYTOPE_TRIANGLE: 3875 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3876 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3877 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3878 break; 3879 case DM_POLYTOPE_QUADRILATERAL: 3880 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3881 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3882 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3883 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3884 break; 3885 default: 3886 break; 3887 } 3888 } 3889 } 3890 PetscFunctionReturn(PETSC_SUCCESS); 3891 } 3892 3893 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3894 { 3895 DM_Plex *mesh = (DM_Plex *)dm->data; 3896 3897 PetscFunctionBeginHot; 3898 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3899 if (useCone) { 3900 PetscCall(DMPlexGetConeSize(dm, p, size)); 3901 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3902 } else { 3903 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3904 PetscCall(DMPlexGetSupport(dm, p, arr)); 3905 } 3906 } else { 3907 if (useCone) { 3908 const PetscSection s = mesh->coneSection; 3909 const PetscInt ps = p - s->pStart; 3910 const PetscInt off = s->atlasOff[ps]; 3911 3912 *size = s->atlasDof[ps]; 3913 *arr = mesh->cones + off; 3914 *ornt = mesh->coneOrientations + off; 3915 } else { 3916 const PetscSection s = mesh->supportSection; 3917 const PetscInt ps = p - s->pStart; 3918 const PetscInt off = s->atlasOff[ps]; 3919 3920 *size = s->atlasDof[ps]; 3921 *arr = mesh->supports + off; 3922 } 3923 } 3924 PetscFunctionReturn(PETSC_SUCCESS); 3925 } 3926 3927 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3928 { 3929 DM_Plex *mesh = (DM_Plex *)dm->data; 3930 3931 PetscFunctionBeginHot; 3932 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3933 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3934 } 3935 PetscFunctionReturn(PETSC_SUCCESS); 3936 } 3937 3938 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3939 { 3940 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3941 PetscInt *closure; 3942 const PetscInt *tmp = NULL, *tmpO = NULL; 3943 PetscInt off = 0, tmpSize, t; 3944 3945 PetscFunctionBeginHot; 3946 if (ornt) { 3947 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3948 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; 3949 } 3950 if (*points) { 3951 closure = *points; 3952 } else { 3953 PetscInt maxConeSize, maxSupportSize; 3954 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3955 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3956 } 3957 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3958 if (ct == DM_POLYTOPE_UNKNOWN) { 3959 closure[off++] = p; 3960 closure[off++] = 0; 3961 for (t = 0; t < tmpSize; ++t) { 3962 closure[off++] = tmp[t]; 3963 closure[off++] = tmpO ? tmpO[t] : 0; 3964 } 3965 } else { 3966 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3967 3968 /* We assume that cells with a valid type have faces with a valid type */ 3969 closure[off++] = p; 3970 closure[off++] = ornt; 3971 for (t = 0; t < tmpSize; ++t) { 3972 DMPolytopeType ft; 3973 3974 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3975 closure[off++] = tmp[arr[t]]; 3976 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3977 } 3978 } 3979 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3980 if (numPoints) *numPoints = tmpSize + 1; 3981 if (points) *points = closure; 3982 PetscFunctionReturn(PETSC_SUCCESS); 3983 } 3984 3985 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3986 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3987 { 3988 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3989 const PetscInt *cone, *ornt; 3990 PetscInt *pts, *closure = NULL; 3991 DMPolytopeType ft; 3992 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3993 PetscInt dim, coneSize, c, d, clSize, cl; 3994 3995 PetscFunctionBeginHot; 3996 PetscCall(DMGetDimension(dm, &dim)); 3997 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3998 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3999 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4000 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4001 maxSize = PetscMax(coneSeries, supportSeries); 4002 if (*points) { 4003 pts = *points; 4004 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4005 c = 0; 4006 pts[c++] = point; 4007 pts[c++] = o; 4008 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4009 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4010 for (cl = 0; cl < clSize * 2; cl += 2) { 4011 pts[c++] = closure[cl]; 4012 pts[c++] = closure[cl + 1]; 4013 } 4014 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4015 for (cl = 0; cl < clSize * 2; cl += 2) { 4016 pts[c++] = closure[cl]; 4017 pts[c++] = closure[cl + 1]; 4018 } 4019 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4020 for (d = 2; d < coneSize; ++d) { 4021 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4022 pts[c++] = cone[arr[d * 2 + 0]]; 4023 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4024 } 4025 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4026 if (dim >= 3) { 4027 for (d = 2; d < coneSize; ++d) { 4028 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4029 const PetscInt *fcone, *fornt; 4030 PetscInt fconeSize, fc, i; 4031 4032 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4033 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4034 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4035 for (fc = 0; fc < fconeSize; ++fc) { 4036 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4037 const PetscInt co = farr[fc * 2 + 1]; 4038 4039 for (i = 0; i < c; i += 2) 4040 if (pts[i] == cp) break; 4041 if (i == c) { 4042 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4043 pts[c++] = cp; 4044 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4045 } 4046 } 4047 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4048 } 4049 } 4050 *numPoints = c / 2; 4051 *points = pts; 4052 PetscFunctionReturn(PETSC_SUCCESS); 4053 } 4054 4055 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4056 { 4057 DMPolytopeType ct; 4058 PetscInt *closure, *fifo; 4059 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4060 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4061 PetscInt depth, maxSize; 4062 4063 PetscFunctionBeginHot; 4064 PetscCall(DMPlexGetDepth(dm, &depth)); 4065 if (depth == 1) { 4066 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4067 PetscFunctionReturn(PETSC_SUCCESS); 4068 } 4069 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4070 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; 4071 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4072 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4073 PetscFunctionReturn(PETSC_SUCCESS); 4074 } 4075 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4076 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4077 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4078 maxSize = PetscMax(coneSeries, supportSeries); 4079 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4080 if (*points) { 4081 closure = *points; 4082 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4083 closure[closureSize++] = p; 4084 closure[closureSize++] = ornt; 4085 fifo[fifoSize++] = p; 4086 fifo[fifoSize++] = ornt; 4087 fifo[fifoSize++] = ct; 4088 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4089 while (fifoSize - fifoStart) { 4090 const PetscInt q = fifo[fifoStart++]; 4091 const PetscInt o = fifo[fifoStart++]; 4092 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4093 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4094 const PetscInt *tmp, *tmpO = NULL; 4095 PetscInt tmpSize, t; 4096 4097 if (PetscDefined(USE_DEBUG)) { 4098 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4099 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); 4100 } 4101 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4102 for (t = 0; t < tmpSize; ++t) { 4103 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4104 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4105 const PetscInt cp = tmp[ip]; 4106 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4107 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4108 PetscInt c; 4109 4110 /* Check for duplicate */ 4111 for (c = 0; c < closureSize; c += 2) { 4112 if (closure[c] == cp) break; 4113 } 4114 if (c == closureSize) { 4115 closure[closureSize++] = cp; 4116 closure[closureSize++] = co; 4117 fifo[fifoSize++] = cp; 4118 fifo[fifoSize++] = co; 4119 fifo[fifoSize++] = ct; 4120 } 4121 } 4122 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4123 } 4124 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4125 if (numPoints) *numPoints = closureSize / 2; 4126 if (points) *points = closure; 4127 PetscFunctionReturn(PETSC_SUCCESS); 4128 } 4129 4130 /*@C 4131 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4132 4133 Not Collective 4134 4135 Input Parameters: 4136 + dm - The `DMPLEX` 4137 . p - The mesh point 4138 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4139 4140 Input/Output Parameter: 4141 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4142 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4143 otherwise the provided array is used to hold the values 4144 4145 Output Parameter: 4146 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4147 4148 Level: beginner 4149 4150 Note: 4151 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4152 4153 Fortran Notes: 4154 `points` must be declared with 4155 .vb 4156 PetscInt, pointer :: points(:) 4157 .ve 4158 and is always allocated by the function. 4159 4160 The `numPoints` argument is not present in the Fortran binding. 4161 4162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4163 @*/ 4164 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4165 { 4166 PetscFunctionBeginHot; 4167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4168 if (numPoints) PetscAssertPointer(numPoints, 4); 4169 if (points) PetscAssertPointer(points, 5); 4170 if (PetscDefined(USE_DEBUG)) { 4171 PetscInt pStart, pEnd; 4172 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4173 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); 4174 } 4175 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4176 PetscFunctionReturn(PETSC_SUCCESS); 4177 } 4178 4179 /*@C 4180 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4181 4182 Not Collective 4183 4184 Input Parameters: 4185 + dm - The `DMPLEX` 4186 . p - The mesh point 4187 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4188 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4189 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4190 4191 Level: beginner 4192 4193 Note: 4194 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4195 4196 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4197 @*/ 4198 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4199 { 4200 PetscFunctionBeginHot; 4201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4202 if (numPoints) *numPoints = 0; 4203 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4204 PetscFunctionReturn(PETSC_SUCCESS); 4205 } 4206 4207 /*@ 4208 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4209 4210 Not Collective 4211 4212 Input Parameter: 4213 . dm - The `DMPLEX` 4214 4215 Output Parameters: 4216 + maxConeSize - The maximum number of in-edges 4217 - maxSupportSize - The maximum number of out-edges 4218 4219 Level: beginner 4220 4221 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4222 @*/ 4223 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4224 { 4225 DM_Plex *mesh = (DM_Plex *)dm->data; 4226 4227 PetscFunctionBegin; 4228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4229 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4230 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4231 PetscFunctionReturn(PETSC_SUCCESS); 4232 } 4233 4234 PetscErrorCode DMSetUp_Plex(DM dm) 4235 { 4236 DM_Plex *mesh = (DM_Plex *)dm->data; 4237 PetscInt size, maxSupportSize; 4238 4239 PetscFunctionBegin; 4240 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4241 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4242 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4243 PetscCall(PetscMalloc1(size, &mesh->cones)); 4244 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4245 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4246 if (maxSupportSize) { 4247 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4248 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4249 PetscCall(PetscMalloc1(size, &mesh->supports)); 4250 } 4251 PetscFunctionReturn(PETSC_SUCCESS); 4252 } 4253 4254 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4255 { 4256 PetscFunctionBegin; 4257 if (subdm) PetscCall(DMClone(dm, subdm)); 4258 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4259 if (subdm) (*subdm)->useNatural = dm->useNatural; 4260 if (dm->useNatural && dm->sfMigration) { 4261 PetscSF sfNatural; 4262 4263 (*subdm)->sfMigration = dm->sfMigration; 4264 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4265 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4266 (*subdm)->sfNatural = sfNatural; 4267 } 4268 PetscFunctionReturn(PETSC_SUCCESS); 4269 } 4270 4271 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4272 { 4273 PetscInt i = 0; 4274 4275 PetscFunctionBegin; 4276 PetscCall(DMClone(dms[0], superdm)); 4277 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4278 (*superdm)->useNatural = PETSC_FALSE; 4279 for (i = 0; i < len; i++) { 4280 if (dms[i]->useNatural && dms[i]->sfMigration) { 4281 PetscSF sfNatural; 4282 4283 (*superdm)->sfMigration = dms[i]->sfMigration; 4284 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4285 (*superdm)->useNatural = PETSC_TRUE; 4286 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4287 (*superdm)->sfNatural = sfNatural; 4288 break; 4289 } 4290 } 4291 PetscFunctionReturn(PETSC_SUCCESS); 4292 } 4293 4294 /*@ 4295 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4296 4297 Not Collective 4298 4299 Input Parameter: 4300 . dm - The `DMPLEX` 4301 4302 Level: beginner 4303 4304 Note: 4305 This should be called after all calls to `DMPlexSetCone()` 4306 4307 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4308 @*/ 4309 PetscErrorCode DMPlexSymmetrize(DM dm) 4310 { 4311 DM_Plex *mesh = (DM_Plex *)dm->data; 4312 PetscInt *offsets; 4313 PetscInt supportSize; 4314 PetscInt pStart, pEnd, p; 4315 4316 PetscFunctionBegin; 4317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4318 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4319 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4320 /* Calculate support sizes */ 4321 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4322 for (p = pStart; p < pEnd; ++p) { 4323 PetscInt dof, off, c; 4324 4325 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4326 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4327 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4328 } 4329 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4330 /* Calculate supports */ 4331 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4332 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4333 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4334 for (p = pStart; p < pEnd; ++p) { 4335 PetscInt dof, off, c; 4336 4337 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4338 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4339 for (c = off; c < off + dof; ++c) { 4340 const PetscInt q = mesh->cones[c]; 4341 PetscInt offS; 4342 4343 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4344 4345 mesh->supports[offS + offsets[q]] = p; 4346 ++offsets[q]; 4347 } 4348 } 4349 PetscCall(PetscFree(offsets)); 4350 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4351 PetscFunctionReturn(PETSC_SUCCESS); 4352 } 4353 4354 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4355 { 4356 IS stratumIS; 4357 4358 PetscFunctionBegin; 4359 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4360 if (PetscDefined(USE_DEBUG)) { 4361 PetscInt qStart, qEnd, numLevels, level; 4362 PetscBool overlap = PETSC_FALSE; 4363 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4364 for (level = 0; level < numLevels; level++) { 4365 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4366 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4367 overlap = PETSC_TRUE; 4368 break; 4369 } 4370 } 4371 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); 4372 } 4373 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4374 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4375 PetscCall(ISDestroy(&stratumIS)); 4376 PetscFunctionReturn(PETSC_SUCCESS); 4377 } 4378 4379 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4380 { 4381 PetscInt *pMin, *pMax; 4382 PetscInt pStart, pEnd; 4383 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4384 4385 PetscFunctionBegin; 4386 { 4387 DMLabel label2; 4388 4389 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4390 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4391 } 4392 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4393 for (PetscInt p = pStart; p < pEnd; ++p) { 4394 DMPolytopeType ct; 4395 4396 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4397 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4398 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4399 } 4400 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4401 for (PetscInt d = dmin; d <= dmax; ++d) { 4402 pMin[d] = PETSC_MAX_INT; 4403 pMax[d] = PETSC_MIN_INT; 4404 } 4405 for (PetscInt p = pStart; p < pEnd; ++p) { 4406 DMPolytopeType ct; 4407 PetscInt d; 4408 4409 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4410 d = DMPolytopeTypeGetDim(ct); 4411 pMin[d] = PetscMin(p, pMin[d]); 4412 pMax[d] = PetscMax(p, pMax[d]); 4413 } 4414 for (PetscInt d = dmin; d <= dmax; ++d) { 4415 if (pMin[d] > pMax[d]) continue; 4416 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4417 } 4418 PetscCall(PetscFree2(pMin, pMax)); 4419 PetscFunctionReturn(PETSC_SUCCESS); 4420 } 4421 4422 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4423 { 4424 PetscInt pStart, pEnd; 4425 PetscInt numRoots = 0, numLeaves = 0; 4426 4427 PetscFunctionBegin; 4428 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4429 { 4430 /* Initialize roots and count leaves */ 4431 PetscInt sMin = PETSC_MAX_INT; 4432 PetscInt sMax = PETSC_MIN_INT; 4433 PetscInt coneSize, supportSize; 4434 4435 for (PetscInt p = pStart; p < pEnd; ++p) { 4436 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4437 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4438 if (!coneSize && supportSize) { 4439 sMin = PetscMin(p, sMin); 4440 sMax = PetscMax(p, sMax); 4441 ++numRoots; 4442 } else if (!supportSize && coneSize) { 4443 ++numLeaves; 4444 } else if (!supportSize && !coneSize) { 4445 /* Isolated points */ 4446 sMin = PetscMin(p, sMin); 4447 sMax = PetscMax(p, sMax); 4448 } 4449 } 4450 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4451 } 4452 4453 if (numRoots + numLeaves == (pEnd - pStart)) { 4454 PetscInt sMin = PETSC_MAX_INT; 4455 PetscInt sMax = PETSC_MIN_INT; 4456 PetscInt coneSize, supportSize; 4457 4458 for (PetscInt p = pStart; p < pEnd; ++p) { 4459 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4460 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4461 if (!supportSize && coneSize) { 4462 sMin = PetscMin(p, sMin); 4463 sMax = PetscMax(p, sMax); 4464 } 4465 } 4466 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4467 } else { 4468 PetscInt level = 0; 4469 PetscInt qStart, qEnd; 4470 4471 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4472 while (qEnd > qStart) { 4473 PetscInt sMin = PETSC_MAX_INT; 4474 PetscInt sMax = PETSC_MIN_INT; 4475 4476 for (PetscInt q = qStart; q < qEnd; ++q) { 4477 const PetscInt *support; 4478 PetscInt supportSize; 4479 4480 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4481 PetscCall(DMPlexGetSupport(dm, q, &support)); 4482 for (PetscInt s = 0; s < supportSize; ++s) { 4483 sMin = PetscMin(support[s], sMin); 4484 sMax = PetscMax(support[s], sMax); 4485 } 4486 } 4487 PetscCall(DMLabelGetNumValues(label, &level)); 4488 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4489 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4490 } 4491 } 4492 PetscFunctionReturn(PETSC_SUCCESS); 4493 } 4494 4495 /*@ 4496 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4497 4498 Collective 4499 4500 Input Parameter: 4501 . dm - The `DMPLEX` 4502 4503 Level: beginner 4504 4505 Notes: 4506 The strata group all points of the same grade, and this function calculates the strata. This 4507 grade can be seen as the height (or depth) of the point in the DAG. 4508 4509 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4510 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4511 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4512 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4513 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4514 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4515 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4516 4517 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4518 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4519 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 4520 to interpolate only that one (e0), so that 4521 .vb 4522 cone(c0) = {e0, v2} 4523 cone(e0) = {v0, v1} 4524 .ve 4525 If `DMPlexStratify()` is run on this mesh, it will give depths 4526 .vb 4527 depth 0 = {v0, v1, v2} 4528 depth 1 = {e0, c0} 4529 .ve 4530 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4531 4532 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4533 4534 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4535 @*/ 4536 PetscErrorCode DMPlexStratify(DM dm) 4537 { 4538 DM_Plex *mesh = (DM_Plex *)dm->data; 4539 DMLabel label; 4540 PetscBool flg = PETSC_FALSE; 4541 4542 PetscFunctionBegin; 4543 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4544 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4545 4546 // Create depth label 4547 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4548 PetscCall(DMCreateLabel(dm, "depth")); 4549 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4550 4551 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4552 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4553 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4554 4555 { /* just in case there is an empty process */ 4556 PetscInt numValues, maxValues = 0, v; 4557 4558 PetscCall(DMLabelGetNumValues(label, &numValues)); 4559 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4560 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4561 } 4562 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4563 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4564 PetscFunctionReturn(PETSC_SUCCESS); 4565 } 4566 4567 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4568 { 4569 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4570 PetscInt dim, depth, pheight, coneSize; 4571 4572 PetscFunctionBeginHot; 4573 PetscCall(DMGetDimension(dm, &dim)); 4574 PetscCall(DMPlexGetDepth(dm, &depth)); 4575 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4576 pheight = depth - pdepth; 4577 if (depth <= 1) { 4578 switch (pdepth) { 4579 case 0: 4580 ct = DM_POLYTOPE_POINT; 4581 break; 4582 case 1: 4583 switch (coneSize) { 4584 case 2: 4585 ct = DM_POLYTOPE_SEGMENT; 4586 break; 4587 case 3: 4588 ct = DM_POLYTOPE_TRIANGLE; 4589 break; 4590 case 4: 4591 switch (dim) { 4592 case 2: 4593 ct = DM_POLYTOPE_QUADRILATERAL; 4594 break; 4595 case 3: 4596 ct = DM_POLYTOPE_TETRAHEDRON; 4597 break; 4598 default: 4599 break; 4600 } 4601 break; 4602 case 5: 4603 ct = DM_POLYTOPE_PYRAMID; 4604 break; 4605 case 6: 4606 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4607 break; 4608 case 8: 4609 ct = DM_POLYTOPE_HEXAHEDRON; 4610 break; 4611 default: 4612 break; 4613 } 4614 } 4615 } else { 4616 if (pdepth == 0) { 4617 ct = DM_POLYTOPE_POINT; 4618 } else if (pheight == 0) { 4619 switch (dim) { 4620 case 1: 4621 switch (coneSize) { 4622 case 2: 4623 ct = DM_POLYTOPE_SEGMENT; 4624 break; 4625 default: 4626 break; 4627 } 4628 break; 4629 case 2: 4630 switch (coneSize) { 4631 case 3: 4632 ct = DM_POLYTOPE_TRIANGLE; 4633 break; 4634 case 4: 4635 ct = DM_POLYTOPE_QUADRILATERAL; 4636 break; 4637 default: 4638 break; 4639 } 4640 break; 4641 case 3: 4642 switch (coneSize) { 4643 case 4: 4644 ct = DM_POLYTOPE_TETRAHEDRON; 4645 break; 4646 case 5: { 4647 const PetscInt *cone; 4648 PetscInt faceConeSize; 4649 4650 PetscCall(DMPlexGetCone(dm, p, &cone)); 4651 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4652 switch (faceConeSize) { 4653 case 3: 4654 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4655 break; 4656 case 4: 4657 ct = DM_POLYTOPE_PYRAMID; 4658 break; 4659 } 4660 } break; 4661 case 6: 4662 ct = DM_POLYTOPE_HEXAHEDRON; 4663 break; 4664 default: 4665 break; 4666 } 4667 break; 4668 default: 4669 break; 4670 } 4671 } else if (pheight > 0) { 4672 switch (coneSize) { 4673 case 2: 4674 ct = DM_POLYTOPE_SEGMENT; 4675 break; 4676 case 3: 4677 ct = DM_POLYTOPE_TRIANGLE; 4678 break; 4679 case 4: 4680 ct = DM_POLYTOPE_QUADRILATERAL; 4681 break; 4682 default: 4683 break; 4684 } 4685 } 4686 } 4687 *pt = ct; 4688 PetscFunctionReturn(PETSC_SUCCESS); 4689 } 4690 4691 /*@ 4692 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4693 4694 Collective 4695 4696 Input Parameter: 4697 . dm - The `DMPLEX` 4698 4699 Level: developer 4700 4701 Note: 4702 This function is normally called automatically when a cell type is requested. It creates an 4703 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4704 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4705 4706 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4707 4708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4709 @*/ 4710 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4711 { 4712 DM_Plex *mesh; 4713 DMLabel ctLabel; 4714 PetscInt pStart, pEnd, p; 4715 4716 PetscFunctionBegin; 4717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4718 mesh = (DM_Plex *)dm->data; 4719 PetscCall(DMCreateLabel(dm, "celltype")); 4720 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4721 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4722 PetscCall(PetscFree(mesh->cellTypes)); 4723 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4724 for (p = pStart; p < pEnd; ++p) { 4725 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4726 PetscInt pdepth; 4727 4728 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4729 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4730 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]); 4731 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4732 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4733 } 4734 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4735 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4736 PetscFunctionReturn(PETSC_SUCCESS); 4737 } 4738 4739 /*@C 4740 DMPlexGetJoin - Get an array for the join of the set of points 4741 4742 Not Collective 4743 4744 Input Parameters: 4745 + dm - The `DMPLEX` object 4746 . numPoints - The number of input points for the join 4747 - points - The input points 4748 4749 Output Parameters: 4750 + numCoveredPoints - The number of points in the join 4751 - coveredPoints - The points in the join 4752 4753 Level: intermediate 4754 4755 Note: 4756 Currently, this is restricted to a single level join 4757 4758 Fortran Notes: 4759 `converedPoints` must be declared with 4760 .vb 4761 PetscInt, pointer :: coveredPints(:) 4762 .ve 4763 4764 The `numCoveredPoints` argument is not present in the Fortran binding. 4765 4766 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4767 @*/ 4768 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4769 { 4770 DM_Plex *mesh = (DM_Plex *)dm->data; 4771 PetscInt *join[2]; 4772 PetscInt joinSize, i = 0; 4773 PetscInt dof, off, p, c, m; 4774 PetscInt maxSupportSize; 4775 4776 PetscFunctionBegin; 4777 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4778 PetscAssertPointer(points, 3); 4779 PetscAssertPointer(numCoveredPoints, 4); 4780 PetscAssertPointer(coveredPoints, 5); 4781 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4782 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4783 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4784 /* Copy in support of first point */ 4785 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4786 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4787 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4788 /* Check each successive support */ 4789 for (p = 1; p < numPoints; ++p) { 4790 PetscInt newJoinSize = 0; 4791 4792 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4793 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4794 for (c = 0; c < dof; ++c) { 4795 const PetscInt point = mesh->supports[off + c]; 4796 4797 for (m = 0; m < joinSize; ++m) { 4798 if (point == join[i][m]) { 4799 join[1 - i][newJoinSize++] = point; 4800 break; 4801 } 4802 } 4803 } 4804 joinSize = newJoinSize; 4805 i = 1 - i; 4806 } 4807 *numCoveredPoints = joinSize; 4808 *coveredPoints = join[i]; 4809 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4810 PetscFunctionReturn(PETSC_SUCCESS); 4811 } 4812 4813 /*@C 4814 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4815 4816 Not Collective 4817 4818 Input Parameters: 4819 + dm - The `DMPLEX` object 4820 . numPoints - The number of input points for the join 4821 - points - The input points 4822 4823 Output Parameters: 4824 + numCoveredPoints - The number of points in the join 4825 - coveredPoints - The points in the join 4826 4827 Level: intermediate 4828 4829 Fortran Notes: 4830 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4831 4832 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4833 @*/ 4834 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4835 { 4836 PetscFunctionBegin; 4837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4838 if (points) PetscAssertPointer(points, 3); 4839 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4840 PetscAssertPointer(coveredPoints, 5); 4841 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4842 if (numCoveredPoints) *numCoveredPoints = 0; 4843 PetscFunctionReturn(PETSC_SUCCESS); 4844 } 4845 4846 /*@C 4847 DMPlexGetFullJoin - Get an array for the join of the set of points 4848 4849 Not Collective 4850 4851 Input Parameters: 4852 + dm - The `DMPLEX` object 4853 . numPoints - The number of input points for the join 4854 - points - The input points, its length is `numPoints` 4855 4856 Output Parameters: 4857 + numCoveredPoints - The number of points in the join 4858 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4859 4860 Level: intermediate 4861 4862 Fortran Notes: 4863 `points` and `converedPoints` must be declared with 4864 .vb 4865 PetscInt, pointer :: points(:) 4866 PetscInt, pointer :: coveredPints(:) 4867 .ve 4868 4869 The `numCoveredPoints` argument is not present in the Fortran binding. 4870 4871 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4872 @*/ 4873 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4874 { 4875 PetscInt *offsets, **closures; 4876 PetscInt *join[2]; 4877 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4878 PetscInt p, d, c, m, ms; 4879 4880 PetscFunctionBegin; 4881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4882 PetscAssertPointer(points, 3); 4883 PetscAssertPointer(numCoveredPoints, 4); 4884 PetscAssertPointer(coveredPoints, 5); 4885 4886 PetscCall(DMPlexGetDepth(dm, &depth)); 4887 PetscCall(PetscCalloc1(numPoints, &closures)); 4888 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4889 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4890 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4891 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4892 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4893 4894 for (p = 0; p < numPoints; ++p) { 4895 PetscInt closureSize; 4896 4897 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4898 4899 offsets[p * (depth + 2) + 0] = 0; 4900 for (d = 0; d < depth + 1; ++d) { 4901 PetscInt pStart, pEnd, i; 4902 4903 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4904 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4905 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4906 offsets[p * (depth + 2) + d + 1] = i; 4907 break; 4908 } 4909 } 4910 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4911 } 4912 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); 4913 } 4914 for (d = 0; d < depth + 1; ++d) { 4915 PetscInt dof; 4916 4917 /* Copy in support of first point */ 4918 dof = offsets[d + 1] - offsets[d]; 4919 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4920 /* Check each successive cone */ 4921 for (p = 1; p < numPoints && joinSize; ++p) { 4922 PetscInt newJoinSize = 0; 4923 4924 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4925 for (c = 0; c < dof; ++c) { 4926 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4927 4928 for (m = 0; m < joinSize; ++m) { 4929 if (point == join[i][m]) { 4930 join[1 - i][newJoinSize++] = point; 4931 break; 4932 } 4933 } 4934 } 4935 joinSize = newJoinSize; 4936 i = 1 - i; 4937 } 4938 if (joinSize) break; 4939 } 4940 *numCoveredPoints = joinSize; 4941 *coveredPoints = join[i]; 4942 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4943 PetscCall(PetscFree(closures)); 4944 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4945 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4946 PetscFunctionReturn(PETSC_SUCCESS); 4947 } 4948 4949 /*@C 4950 DMPlexGetMeet - Get an array for the meet of the set of points 4951 4952 Not Collective 4953 4954 Input Parameters: 4955 + dm - The `DMPLEX` object 4956 . numPoints - The number of input points for the meet 4957 - points - The input points, of length `numPoints` 4958 4959 Output Parameters: 4960 + numCoveringPoints - The number of points in the meet 4961 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4962 4963 Level: intermediate 4964 4965 Note: 4966 Currently, this is restricted to a single level meet 4967 4968 Fortran Notes: 4969 `coveringPoints` must be declared with 4970 .vb 4971 PetscInt, pointer :: coveringPoints(:) 4972 .ve 4973 4974 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4975 4976 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4977 @*/ 4978 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4979 { 4980 DM_Plex *mesh = (DM_Plex *)dm->data; 4981 PetscInt *meet[2]; 4982 PetscInt meetSize, i = 0; 4983 PetscInt dof, off, p, c, m; 4984 PetscInt maxConeSize; 4985 4986 PetscFunctionBegin; 4987 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4988 PetscAssertPointer(points, 3); 4989 PetscAssertPointer(numCoveringPoints, 4); 4990 PetscAssertPointer(coveringPoints, 5); 4991 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4992 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4993 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4994 /* Copy in cone of first point */ 4995 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4996 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4997 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4998 /* Check each successive cone */ 4999 for (p = 1; p < numPoints; ++p) { 5000 PetscInt newMeetSize = 0; 5001 5002 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5003 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5004 for (c = 0; c < dof; ++c) { 5005 const PetscInt point = mesh->cones[off + c]; 5006 5007 for (m = 0; m < meetSize; ++m) { 5008 if (point == meet[i][m]) { 5009 meet[1 - i][newMeetSize++] = point; 5010 break; 5011 } 5012 } 5013 } 5014 meetSize = newMeetSize; 5015 i = 1 - i; 5016 } 5017 *numCoveringPoints = meetSize; 5018 *coveringPoints = meet[i]; 5019 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5020 PetscFunctionReturn(PETSC_SUCCESS); 5021 } 5022 5023 /*@C 5024 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5025 5026 Not Collective 5027 5028 Input Parameters: 5029 + dm - The `DMPLEX` object 5030 . numPoints - The number of input points for the meet 5031 - points - The input points 5032 5033 Output Parameters: 5034 + numCoveredPoints - The number of points in the meet 5035 - coveredPoints - The points in the meet 5036 5037 Level: intermediate 5038 5039 Fortran Notes: 5040 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5041 5042 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5043 @*/ 5044 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5045 { 5046 PetscFunctionBegin; 5047 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5048 if (points) PetscAssertPointer(points, 3); 5049 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5050 PetscAssertPointer(coveredPoints, 5); 5051 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5052 if (numCoveredPoints) *numCoveredPoints = 0; 5053 PetscFunctionReturn(PETSC_SUCCESS); 5054 } 5055 5056 /*@C 5057 DMPlexGetFullMeet - Get an array for the meet of the set of points 5058 5059 Not Collective 5060 5061 Input Parameters: 5062 + dm - The `DMPLEX` object 5063 . numPoints - The number of input points for the meet 5064 - points - The input points, of length `numPoints` 5065 5066 Output Parameters: 5067 + numCoveredPoints - The number of points in the meet 5068 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5069 5070 Level: intermediate 5071 5072 Fortran Notes: 5073 `points` and `coveredPoints` must be declared with 5074 .vb 5075 PetscInt, pointer :: points(:) 5076 PetscInt, pointer :: coveredPoints(:) 5077 .ve 5078 5079 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5080 5081 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5082 @*/ 5083 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5084 { 5085 PetscInt *offsets, **closures; 5086 PetscInt *meet[2]; 5087 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5088 PetscInt p, h, c, m, mc; 5089 5090 PetscFunctionBegin; 5091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5092 PetscAssertPointer(points, 3); 5093 PetscAssertPointer(numCoveredPoints, 4); 5094 PetscAssertPointer(coveredPoints, 5); 5095 5096 PetscCall(DMPlexGetDepth(dm, &height)); 5097 PetscCall(PetscMalloc1(numPoints, &closures)); 5098 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5099 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5100 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5101 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5102 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5103 5104 for (p = 0; p < numPoints; ++p) { 5105 PetscInt closureSize; 5106 5107 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5108 5109 offsets[p * (height + 2) + 0] = 0; 5110 for (h = 0; h < height + 1; ++h) { 5111 PetscInt pStart, pEnd, i; 5112 5113 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5114 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5115 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5116 offsets[p * (height + 2) + h + 1] = i; 5117 break; 5118 } 5119 } 5120 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5121 } 5122 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); 5123 } 5124 for (h = 0; h < height + 1; ++h) { 5125 PetscInt dof; 5126 5127 /* Copy in cone of first point */ 5128 dof = offsets[h + 1] - offsets[h]; 5129 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5130 /* Check each successive cone */ 5131 for (p = 1; p < numPoints && meetSize; ++p) { 5132 PetscInt newMeetSize = 0; 5133 5134 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5135 for (c = 0; c < dof; ++c) { 5136 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5137 5138 for (m = 0; m < meetSize; ++m) { 5139 if (point == meet[i][m]) { 5140 meet[1 - i][newMeetSize++] = point; 5141 break; 5142 } 5143 } 5144 } 5145 meetSize = newMeetSize; 5146 i = 1 - i; 5147 } 5148 if (meetSize) break; 5149 } 5150 *numCoveredPoints = meetSize; 5151 *coveredPoints = meet[i]; 5152 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5153 PetscCall(PetscFree(closures)); 5154 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5155 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5156 PetscFunctionReturn(PETSC_SUCCESS); 5157 } 5158 5159 /*@ 5160 DMPlexEqual - Determine if two `DM` have the same topology 5161 5162 Not Collective 5163 5164 Input Parameters: 5165 + dmA - A `DMPLEX` object 5166 - dmB - A `DMPLEX` object 5167 5168 Output Parameter: 5169 . equal - `PETSC_TRUE` if the topologies are identical 5170 5171 Level: intermediate 5172 5173 Note: 5174 We are not solving graph isomorphism, so we do not permute. 5175 5176 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5177 @*/ 5178 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5179 { 5180 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5181 5182 PetscFunctionBegin; 5183 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5184 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5185 PetscAssertPointer(equal, 3); 5186 5187 *equal = PETSC_FALSE; 5188 PetscCall(DMPlexGetDepth(dmA, &depth)); 5189 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5190 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5191 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5192 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5193 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5194 for (p = pStart; p < pEnd; ++p) { 5195 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5196 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5197 5198 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5199 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5200 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5201 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5202 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5203 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5204 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5205 for (c = 0; c < coneSize; ++c) { 5206 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5207 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5208 } 5209 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5210 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5211 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5212 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5213 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5214 for (s = 0; s < supportSize; ++s) { 5215 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5216 } 5217 } 5218 *equal = PETSC_TRUE; 5219 PetscFunctionReturn(PETSC_SUCCESS); 5220 } 5221 5222 /*@ 5223 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5224 5225 Not Collective 5226 5227 Input Parameters: 5228 + dm - The `DMPLEX` 5229 . cellDim - The cell dimension 5230 - numCorners - The number of vertices on a cell 5231 5232 Output Parameter: 5233 . numFaceVertices - The number of vertices on a face 5234 5235 Level: developer 5236 5237 Note: 5238 Of course this can only work for a restricted set of symmetric shapes 5239 5240 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5241 @*/ 5242 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5243 { 5244 MPI_Comm comm; 5245 5246 PetscFunctionBegin; 5247 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5248 PetscAssertPointer(numFaceVertices, 4); 5249 switch (cellDim) { 5250 case 0: 5251 *numFaceVertices = 0; 5252 break; 5253 case 1: 5254 *numFaceVertices = 1; 5255 break; 5256 case 2: 5257 switch (numCorners) { 5258 case 3: /* triangle */ 5259 *numFaceVertices = 2; /* Edge has 2 vertices */ 5260 break; 5261 case 4: /* quadrilateral */ 5262 *numFaceVertices = 2; /* Edge has 2 vertices */ 5263 break; 5264 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5265 *numFaceVertices = 3; /* Edge has 3 vertices */ 5266 break; 5267 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5268 *numFaceVertices = 3; /* Edge has 3 vertices */ 5269 break; 5270 default: 5271 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5272 } 5273 break; 5274 case 3: 5275 switch (numCorners) { 5276 case 4: /* tetradehdron */ 5277 *numFaceVertices = 3; /* Face has 3 vertices */ 5278 break; 5279 case 6: /* tet cohesive cells */ 5280 *numFaceVertices = 4; /* Face has 4 vertices */ 5281 break; 5282 case 8: /* hexahedron */ 5283 *numFaceVertices = 4; /* Face has 4 vertices */ 5284 break; 5285 case 9: /* tet cohesive Lagrange cells */ 5286 *numFaceVertices = 6; /* Face has 6 vertices */ 5287 break; 5288 case 10: /* quadratic tetrahedron */ 5289 *numFaceVertices = 6; /* Face has 6 vertices */ 5290 break; 5291 case 12: /* hex cohesive Lagrange cells */ 5292 *numFaceVertices = 6; /* Face has 6 vertices */ 5293 break; 5294 case 18: /* quadratic tet cohesive Lagrange cells */ 5295 *numFaceVertices = 6; /* Face has 6 vertices */ 5296 break; 5297 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5298 *numFaceVertices = 9; /* Face has 9 vertices */ 5299 break; 5300 default: 5301 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5302 } 5303 break; 5304 default: 5305 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5306 } 5307 PetscFunctionReturn(PETSC_SUCCESS); 5308 } 5309 5310 /*@ 5311 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5312 5313 Not Collective 5314 5315 Input Parameter: 5316 . dm - The `DMPLEX` object 5317 5318 Output Parameter: 5319 . depthLabel - The `DMLabel` recording point depth 5320 5321 Level: developer 5322 5323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5324 @*/ 5325 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5326 { 5327 PetscFunctionBegin; 5328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5329 PetscAssertPointer(depthLabel, 2); 5330 *depthLabel = dm->depthLabel; 5331 PetscFunctionReturn(PETSC_SUCCESS); 5332 } 5333 5334 /*@ 5335 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5336 5337 Not Collective 5338 5339 Input Parameter: 5340 . dm - The `DMPLEX` object 5341 5342 Output Parameter: 5343 . depth - The number of strata (breadth first levels) in the DAG 5344 5345 Level: developer 5346 5347 Notes: 5348 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5349 5350 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5351 5352 An empty mesh gives -1. 5353 5354 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5355 @*/ 5356 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5357 { 5358 DM_Plex *mesh = (DM_Plex *)dm->data; 5359 DMLabel label; 5360 PetscInt d = -1; 5361 5362 PetscFunctionBegin; 5363 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5364 PetscAssertPointer(depth, 2); 5365 if (mesh->tr) { 5366 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5367 } else { 5368 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5369 // Allow missing depths 5370 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5371 *depth = d; 5372 } 5373 PetscFunctionReturn(PETSC_SUCCESS); 5374 } 5375 5376 /*@ 5377 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5378 5379 Not Collective 5380 5381 Input Parameters: 5382 + dm - The `DMPLEX` object 5383 - depth - The requested depth 5384 5385 Output Parameters: 5386 + start - The first point at this `depth` 5387 - end - One beyond the last point at this `depth` 5388 5389 Level: developer 5390 5391 Notes: 5392 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5393 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5394 higher dimension, e.g., "edges". 5395 5396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5397 @*/ 5398 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5399 { 5400 DM_Plex *mesh = (DM_Plex *)dm->data; 5401 DMLabel label; 5402 PetscInt pStart, pEnd; 5403 5404 PetscFunctionBegin; 5405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5406 if (start) { 5407 PetscAssertPointer(start, 3); 5408 *start = 0; 5409 } 5410 if (end) { 5411 PetscAssertPointer(end, 4); 5412 *end = 0; 5413 } 5414 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5415 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5416 if (depth < 0) { 5417 if (start) *start = pStart; 5418 if (end) *end = pEnd; 5419 PetscFunctionReturn(PETSC_SUCCESS); 5420 } 5421 if (mesh->tr) { 5422 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5423 } else { 5424 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5425 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5426 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5427 } 5428 PetscFunctionReturn(PETSC_SUCCESS); 5429 } 5430 5431 /*@ 5432 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5433 5434 Not Collective 5435 5436 Input Parameters: 5437 + dm - The `DMPLEX` object 5438 - height - The requested height 5439 5440 Output Parameters: 5441 + start - The first point at this `height` 5442 - end - One beyond the last point at this `height` 5443 5444 Level: developer 5445 5446 Notes: 5447 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5448 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5449 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5450 5451 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5452 @*/ 5453 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5454 { 5455 DMLabel label; 5456 PetscInt depth, pStart, pEnd; 5457 5458 PetscFunctionBegin; 5459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5460 if (start) { 5461 PetscAssertPointer(start, 3); 5462 *start = 0; 5463 } 5464 if (end) { 5465 PetscAssertPointer(end, 4); 5466 *end = 0; 5467 } 5468 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5469 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5470 if (height < 0) { 5471 if (start) *start = pStart; 5472 if (end) *end = pEnd; 5473 PetscFunctionReturn(PETSC_SUCCESS); 5474 } 5475 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5476 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5477 else PetscCall(DMGetDimension(dm, &depth)); 5478 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5479 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5480 PetscFunctionReturn(PETSC_SUCCESS); 5481 } 5482 5483 /*@ 5484 DMPlexGetPointDepth - Get the `depth` of a given point 5485 5486 Not Collective 5487 5488 Input Parameters: 5489 + dm - The `DMPLEX` object 5490 - point - The point 5491 5492 Output Parameter: 5493 . depth - The depth of the `point` 5494 5495 Level: intermediate 5496 5497 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5498 @*/ 5499 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5500 { 5501 PetscFunctionBegin; 5502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5503 PetscAssertPointer(depth, 3); 5504 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5505 PetscFunctionReturn(PETSC_SUCCESS); 5506 } 5507 5508 /*@ 5509 DMPlexGetPointHeight - Get the `height` of a given point 5510 5511 Not Collective 5512 5513 Input Parameters: 5514 + dm - The `DMPLEX` object 5515 - point - The point 5516 5517 Output Parameter: 5518 . height - The height of the `point` 5519 5520 Level: intermediate 5521 5522 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5523 @*/ 5524 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5525 { 5526 PetscInt n, pDepth; 5527 5528 PetscFunctionBegin; 5529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5530 PetscAssertPointer(height, 3); 5531 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5532 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5533 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5534 PetscFunctionReturn(PETSC_SUCCESS); 5535 } 5536 5537 /*@ 5538 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5539 5540 Not Collective 5541 5542 Input Parameter: 5543 . dm - The `DMPLEX` object 5544 5545 Output Parameter: 5546 . celltypeLabel - The `DMLabel` recording cell polytope type 5547 5548 Level: developer 5549 5550 Note: 5551 This function will trigger automatica computation of cell types. This can be disabled by calling 5552 `DMCreateLabel`(dm, "celltype") beforehand. 5553 5554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5555 @*/ 5556 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5557 { 5558 PetscFunctionBegin; 5559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5560 PetscAssertPointer(celltypeLabel, 2); 5561 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5562 *celltypeLabel = dm->celltypeLabel; 5563 PetscFunctionReturn(PETSC_SUCCESS); 5564 } 5565 5566 /*@ 5567 DMPlexGetCellType - Get the polytope type of a given cell 5568 5569 Not Collective 5570 5571 Input Parameters: 5572 + dm - The `DMPLEX` object 5573 - cell - The cell 5574 5575 Output Parameter: 5576 . celltype - The polytope type of the cell 5577 5578 Level: intermediate 5579 5580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5581 @*/ 5582 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5583 { 5584 DM_Plex *mesh = (DM_Plex *)dm->data; 5585 DMLabel label; 5586 PetscInt ct; 5587 5588 PetscFunctionBegin; 5589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5590 PetscAssertPointer(celltype, 3); 5591 if (mesh->tr) { 5592 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5593 } else { 5594 PetscInt pStart, pEnd; 5595 5596 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5597 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5598 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5599 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5600 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5601 for (PetscInt p = pStart; p < pEnd; p++) { 5602 PetscCall(DMLabelGetValue(label, p, &ct)); 5603 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5604 } 5605 } 5606 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5607 if (PetscDefined(USE_DEBUG)) { 5608 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5609 PetscCall(DMLabelGetValue(label, cell, &ct)); 5610 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5611 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5612 } 5613 } 5614 PetscFunctionReturn(PETSC_SUCCESS); 5615 } 5616 5617 /*@ 5618 DMPlexSetCellType - Set the polytope type of a given cell 5619 5620 Not Collective 5621 5622 Input Parameters: 5623 + dm - The `DMPLEX` object 5624 . cell - The cell 5625 - celltype - The polytope type of the cell 5626 5627 Level: advanced 5628 5629 Note: 5630 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5631 is executed. This function will override the computed type. However, if automatic classification will not succeed 5632 and a user wants to manually specify all types, the classification must be disabled by calling 5633 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5634 5635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5636 @*/ 5637 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5638 { 5639 DM_Plex *mesh = (DM_Plex *)dm->data; 5640 DMLabel label; 5641 PetscInt pStart, pEnd; 5642 5643 PetscFunctionBegin; 5644 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5645 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5646 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5647 PetscCall(DMLabelSetValue(label, cell, celltype)); 5648 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5649 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5650 PetscFunctionReturn(PETSC_SUCCESS); 5651 } 5652 5653 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5654 { 5655 PetscSection section; 5656 PetscInt maxHeight; 5657 const char *prefix; 5658 5659 PetscFunctionBegin; 5660 PetscCall(DMClone(dm, cdm)); 5661 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5662 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5663 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5664 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5665 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5666 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5667 PetscCall(DMSetLocalSection(*cdm, section)); 5668 PetscCall(PetscSectionDestroy(§ion)); 5669 5670 PetscCall(DMSetNumFields(*cdm, 1)); 5671 PetscCall(DMCreateDS(*cdm)); 5672 (*cdm)->cloneOpts = PETSC_TRUE; 5673 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5674 PetscFunctionReturn(PETSC_SUCCESS); 5675 } 5676 5677 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5678 { 5679 Vec coordsLocal, cellCoordsLocal; 5680 DM coordsDM, cellCoordsDM; 5681 5682 PetscFunctionBegin; 5683 *field = NULL; 5684 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5685 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5686 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5687 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5688 if (coordsLocal && coordsDM) { 5689 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5690 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5691 } 5692 PetscFunctionReturn(PETSC_SUCCESS); 5693 } 5694 5695 /*@ 5696 DMPlexGetConeSection - Return a section which describes the layout of cone data 5697 5698 Not Collective 5699 5700 Input Parameter: 5701 . dm - The `DMPLEX` object 5702 5703 Output Parameter: 5704 . section - The `PetscSection` object 5705 5706 Level: developer 5707 5708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5709 @*/ 5710 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5711 { 5712 DM_Plex *mesh = (DM_Plex *)dm->data; 5713 5714 PetscFunctionBegin; 5715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5716 if (section) *section = mesh->coneSection; 5717 PetscFunctionReturn(PETSC_SUCCESS); 5718 } 5719 5720 /*@ 5721 DMPlexGetSupportSection - Return a section which describes the layout of support data 5722 5723 Not Collective 5724 5725 Input Parameter: 5726 . dm - The `DMPLEX` object 5727 5728 Output Parameter: 5729 . section - The `PetscSection` object 5730 5731 Level: developer 5732 5733 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5734 @*/ 5735 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5736 { 5737 DM_Plex *mesh = (DM_Plex *)dm->data; 5738 5739 PetscFunctionBegin; 5740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5741 if (section) *section = mesh->supportSection; 5742 PetscFunctionReturn(PETSC_SUCCESS); 5743 } 5744 5745 /*@C 5746 DMPlexGetCones - Return cone data 5747 5748 Not Collective 5749 5750 Input Parameter: 5751 . dm - The `DMPLEX` object 5752 5753 Output Parameter: 5754 . cones - The cone for each point 5755 5756 Level: developer 5757 5758 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5759 @*/ 5760 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5761 { 5762 DM_Plex *mesh = (DM_Plex *)dm->data; 5763 5764 PetscFunctionBegin; 5765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5766 if (cones) *cones = mesh->cones; 5767 PetscFunctionReturn(PETSC_SUCCESS); 5768 } 5769 5770 /*@C 5771 DMPlexGetConeOrientations - Return cone orientation data 5772 5773 Not Collective 5774 5775 Input Parameter: 5776 . dm - The `DMPLEX` object 5777 5778 Output Parameter: 5779 . coneOrientations - The array of cone orientations for all points 5780 5781 Level: developer 5782 5783 Notes: 5784 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5785 as returned by `DMPlexGetConeOrientation()`. 5786 5787 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5788 5789 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5790 @*/ 5791 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5792 { 5793 DM_Plex *mesh = (DM_Plex *)dm->data; 5794 5795 PetscFunctionBegin; 5796 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5797 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5798 PetscFunctionReturn(PETSC_SUCCESS); 5799 } 5800 5801 /* FEM Support */ 5802 5803 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5804 { 5805 PetscInt depth; 5806 5807 PetscFunctionBegin; 5808 PetscCall(DMPlexGetDepth(plex, &depth)); 5809 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5810 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5811 PetscFunctionReturn(PETSC_SUCCESS); 5812 } 5813 5814 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5815 { 5816 PetscInt depth; 5817 5818 PetscFunctionBegin; 5819 PetscCall(DMPlexGetDepth(plex, &depth)); 5820 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5821 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5822 PetscFunctionReturn(PETSC_SUCCESS); 5823 } 5824 5825 /* 5826 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5827 representing a line in the section. 5828 */ 5829 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5830 { 5831 PetscObject obj; 5832 PetscClassId id; 5833 PetscFE fe = NULL; 5834 5835 PetscFunctionBeginHot; 5836 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5837 PetscCall(DMGetField(dm, field, NULL, &obj)); 5838 PetscCall(PetscObjectGetClassId(obj, &id)); 5839 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5840 5841 if (!fe) { 5842 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5843 /* An order k SEM disc has k-1 dofs on an edge */ 5844 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5845 *k = *k / *Nc + 1; 5846 } else { 5847 PetscInt dual_space_size, dim; 5848 PetscDualSpace dsp; 5849 5850 PetscCall(DMGetDimension(dm, &dim)); 5851 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5852 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5853 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5854 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5855 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5856 } 5857 PetscFunctionReturn(PETSC_SUCCESS); 5858 } 5859 5860 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5861 { 5862 PetscFunctionBeginHot; 5863 if (tensor) { 5864 *dof = PetscPowInt(k + 1, dim); 5865 } else { 5866 switch (dim) { 5867 case 1: 5868 *dof = k + 1; 5869 break; 5870 case 2: 5871 *dof = ((k + 1) * (k + 2)) / 2; 5872 break; 5873 case 3: 5874 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5875 break; 5876 default: 5877 *dof = 0; 5878 } 5879 } 5880 PetscFunctionReturn(PETSC_SUCCESS); 5881 } 5882 5883 /*@ 5884 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5885 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5886 section provided (or the section of the `DM`). 5887 5888 Input Parameters: 5889 + dm - The `DM` 5890 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5891 - section - The `PetscSection` to reorder, or `NULL` for the default section 5892 5893 Example: 5894 A typical interpolated single-quad mesh might order points as 5895 .vb 5896 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5897 5898 v4 -- e6 -- v3 5899 | | 5900 e7 c0 e8 5901 | | 5902 v1 -- e5 -- v2 5903 .ve 5904 5905 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5906 dofs in the order of points, e.g., 5907 .vb 5908 c0 -> [0,1,2,3] 5909 v1 -> [4] 5910 ... 5911 e5 -> [8, 9] 5912 .ve 5913 5914 which corresponds to the dofs 5915 .vb 5916 6 10 11 7 5917 13 2 3 15 5918 12 0 1 14 5919 4 8 9 5 5920 .ve 5921 5922 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5923 .vb 5924 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5925 .ve 5926 5927 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5928 .vb 5929 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5930 .ve 5931 5932 Level: developer 5933 5934 Notes: 5935 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5936 degree of the basis. 5937 5938 This is required to run with libCEED. 5939 5940 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5941 @*/ 5942 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5943 { 5944 DMLabel label; 5945 PetscInt dim, depth = -1, eStart = -1, Nf; 5946 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5947 5948 PetscFunctionBegin; 5949 PetscCall(DMGetDimension(dm, &dim)); 5950 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5951 if (point < 0) { 5952 PetscInt sStart, sEnd; 5953 5954 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5955 point = sEnd - sStart ? sStart : point; 5956 } 5957 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5958 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5959 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5960 if (depth == 1) { 5961 eStart = point; 5962 } else if (depth == dim) { 5963 const PetscInt *cone; 5964 5965 PetscCall(DMPlexGetCone(dm, point, &cone)); 5966 if (dim == 2) eStart = cone[0]; 5967 else if (dim == 3) { 5968 const PetscInt *cone2; 5969 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5970 eStart = cone2[0]; 5971 } 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); 5972 } 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); 5973 5974 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5975 for (PetscInt d = 1; d <= dim; d++) { 5976 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5977 PetscInt *perm; 5978 5979 for (f = 0; f < Nf; ++f) { 5980 PetscInt dof; 5981 5982 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5983 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5984 if (!continuous && d < dim) continue; 5985 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5986 size += dof * Nc; 5987 } 5988 PetscCall(PetscMalloc1(size, &perm)); 5989 for (f = 0; f < Nf; ++f) { 5990 switch (d) { 5991 case 1: 5992 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5993 if (!continuous && d < dim) continue; 5994 /* 5995 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5996 We want [ vtx0; edge of length k-1; vtx1 ] 5997 */ 5998 if (continuous) { 5999 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6000 for (i = 0; i < k - 1; i++) 6001 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6002 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6003 foffset = offset; 6004 } else { 6005 PetscInt dof; 6006 6007 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6008 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6009 foffset = offset; 6010 } 6011 break; 6012 case 2: 6013 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6014 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6015 if (!continuous && d < dim) continue; 6016 /* The SEM order is 6017 6018 v_lb, {e_b}, v_rb, 6019 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6020 v_lt, reverse {e_t}, v_rt 6021 */ 6022 if (continuous) { 6023 const PetscInt of = 0; 6024 const PetscInt oeb = of + PetscSqr(k - 1); 6025 const PetscInt oer = oeb + (k - 1); 6026 const PetscInt oet = oer + (k - 1); 6027 const PetscInt oel = oet + (k - 1); 6028 const PetscInt ovlb = oel + (k - 1); 6029 const PetscInt ovrb = ovlb + 1; 6030 const PetscInt ovrt = ovrb + 1; 6031 const PetscInt ovlt = ovrt + 1; 6032 PetscInt o; 6033 6034 /* bottom */ 6035 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6036 for (o = oeb; o < oer; ++o) 6037 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6039 /* middle */ 6040 for (i = 0; i < k - 1; ++i) { 6041 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6042 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6045 } 6046 /* top */ 6047 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6048 for (o = oel - 1; o >= oet; --o) 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6051 foffset = offset; 6052 } else { 6053 PetscInt dof; 6054 6055 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6056 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6057 foffset = offset; 6058 } 6059 break; 6060 case 3: 6061 /* The original hex closure is 6062 6063 {c, 6064 f_b, f_t, f_f, f_b, f_r, f_l, 6065 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6066 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6067 */ 6068 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6069 if (!continuous && d < dim) continue; 6070 /* The SEM order is 6071 Bottom Slice 6072 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6073 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6074 v_blb, {e_bb}, v_brb, 6075 6076 Middle Slice (j) 6077 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6078 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6079 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6080 6081 Top Slice 6082 v_tlf, {e_tf}, v_trf, 6083 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6084 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6085 */ 6086 if (continuous) { 6087 const PetscInt oc = 0; 6088 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6089 const PetscInt oft = ofb + PetscSqr(k - 1); 6090 const PetscInt off = oft + PetscSqr(k - 1); 6091 const PetscInt ofk = off + PetscSqr(k - 1); 6092 const PetscInt ofr = ofk + PetscSqr(k - 1); 6093 const PetscInt ofl = ofr + PetscSqr(k - 1); 6094 const PetscInt oebl = ofl + PetscSqr(k - 1); 6095 const PetscInt oebb = oebl + (k - 1); 6096 const PetscInt oebr = oebb + (k - 1); 6097 const PetscInt oebf = oebr + (k - 1); 6098 const PetscInt oetf = oebf + (k - 1); 6099 const PetscInt oetr = oetf + (k - 1); 6100 const PetscInt oetb = oetr + (k - 1); 6101 const PetscInt oetl = oetb + (k - 1); 6102 const PetscInt oerf = oetl + (k - 1); 6103 const PetscInt oelf = oerf + (k - 1); 6104 const PetscInt oelb = oelf + (k - 1); 6105 const PetscInt oerb = oelb + (k - 1); 6106 const PetscInt ovblf = oerb + (k - 1); 6107 const PetscInt ovblb = ovblf + 1; 6108 const PetscInt ovbrb = ovblb + 1; 6109 const PetscInt ovbrf = ovbrb + 1; 6110 const PetscInt ovtlf = ovbrf + 1; 6111 const PetscInt ovtrf = ovtlf + 1; 6112 const PetscInt ovtrb = ovtrf + 1; 6113 const PetscInt ovtlb = ovtrb + 1; 6114 PetscInt o, n; 6115 6116 /* Bottom Slice */ 6117 /* bottom */ 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6119 for (o = oetf - 1; o >= oebf; --o) 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6121 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6122 /* middle */ 6123 for (i = 0; i < k - 1; ++i) { 6124 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6125 for (n = 0; n < k - 1; ++n) { 6126 o = ofb + n * (k - 1) + i; 6127 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6128 } 6129 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6130 } 6131 /* top */ 6132 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6133 for (o = oebb; o < oebr; ++o) 6134 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6135 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6136 6137 /* Middle Slice */ 6138 for (j = 0; j < k - 1; ++j) { 6139 /* bottom */ 6140 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6141 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6143 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6144 /* middle */ 6145 for (i = 0; i < k - 1; ++i) { 6146 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6147 for (n = 0; n < k - 1; ++n) 6148 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6149 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6150 } 6151 /* top */ 6152 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6153 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6154 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6155 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6156 } 6157 6158 /* Top Slice */ 6159 /* bottom */ 6160 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6161 for (o = oetf; o < oetr; ++o) 6162 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6163 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6164 /* middle */ 6165 for (i = 0; i < k - 1; ++i) { 6166 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6167 for (n = 0; n < k - 1; ++n) 6168 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6169 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6170 } 6171 /* top */ 6172 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6173 for (o = oetl - 1; o >= oetb; --o) 6174 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6175 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6176 6177 foffset = offset; 6178 } else { 6179 PetscInt dof; 6180 6181 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6182 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6183 foffset = offset; 6184 } 6185 break; 6186 default: 6187 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6188 } 6189 } 6190 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6191 /* Check permutation */ 6192 { 6193 PetscInt *check; 6194 6195 PetscCall(PetscMalloc1(size, &check)); 6196 for (i = 0; i < size; ++i) { 6197 check[i] = -1; 6198 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6199 } 6200 for (i = 0; i < size; ++i) check[perm[i]] = i; 6201 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6202 PetscCall(PetscFree(check)); 6203 } 6204 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6205 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6206 PetscInt *loc_perm; 6207 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6208 for (PetscInt i = 0; i < size; i++) { 6209 loc_perm[i] = perm[i]; 6210 loc_perm[size + i] = size + perm[i]; 6211 } 6212 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6213 } 6214 } 6215 PetscFunctionReturn(PETSC_SUCCESS); 6216 } 6217 6218 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6219 { 6220 PetscDS prob; 6221 PetscInt depth, Nf, h; 6222 DMLabel label; 6223 6224 PetscFunctionBeginHot; 6225 PetscCall(DMGetDS(dm, &prob)); 6226 Nf = prob->Nf; 6227 label = dm->depthLabel; 6228 *dspace = NULL; 6229 if (field < Nf) { 6230 PetscObject disc = prob->disc[field]; 6231 6232 if (disc->classid == PETSCFE_CLASSID) { 6233 PetscDualSpace dsp; 6234 6235 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6236 PetscCall(DMLabelGetNumValues(label, &depth)); 6237 PetscCall(DMLabelGetValue(label, point, &h)); 6238 h = depth - 1 - h; 6239 if (h) { 6240 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6241 } else { 6242 *dspace = dsp; 6243 } 6244 } 6245 } 6246 PetscFunctionReturn(PETSC_SUCCESS); 6247 } 6248 6249 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6250 { 6251 PetscScalar *array; 6252 const PetscScalar *vArray; 6253 const PetscInt *cone, *coneO; 6254 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6255 6256 PetscFunctionBeginHot; 6257 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6258 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6259 PetscCall(DMPlexGetCone(dm, point, &cone)); 6260 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6261 if (!values || !*values) { 6262 if ((point >= pStart) && (point < pEnd)) { 6263 PetscInt dof; 6264 6265 PetscCall(PetscSectionGetDof(section, point, &dof)); 6266 size += dof; 6267 } 6268 for (p = 0; p < numPoints; ++p) { 6269 const PetscInt cp = cone[p]; 6270 PetscInt dof; 6271 6272 if ((cp < pStart) || (cp >= pEnd)) continue; 6273 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6274 size += dof; 6275 } 6276 if (!values) { 6277 if (csize) *csize = size; 6278 PetscFunctionReturn(PETSC_SUCCESS); 6279 } 6280 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6281 } else { 6282 array = *values; 6283 } 6284 size = 0; 6285 PetscCall(VecGetArrayRead(v, &vArray)); 6286 if ((point >= pStart) && (point < pEnd)) { 6287 PetscInt dof, off, d; 6288 const PetscScalar *varr; 6289 6290 PetscCall(PetscSectionGetDof(section, point, &dof)); 6291 PetscCall(PetscSectionGetOffset(section, point, &off)); 6292 varr = PetscSafePointerPlusOffset(vArray, off); 6293 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6294 size += dof; 6295 } 6296 for (p = 0; p < numPoints; ++p) { 6297 const PetscInt cp = cone[p]; 6298 PetscInt o = coneO[p]; 6299 PetscInt dof, off, d; 6300 const PetscScalar *varr; 6301 6302 if ((cp < pStart) || (cp >= pEnd)) continue; 6303 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6304 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6305 varr = PetscSafePointerPlusOffset(vArray, off); 6306 if (o >= 0) { 6307 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6308 } else { 6309 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6310 } 6311 size += dof; 6312 } 6313 PetscCall(VecRestoreArrayRead(v, &vArray)); 6314 if (!*values) { 6315 if (csize) *csize = size; 6316 *values = array; 6317 } else { 6318 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6319 *csize = size; 6320 } 6321 PetscFunctionReturn(PETSC_SUCCESS); 6322 } 6323 6324 /* Compress out points not in the section */ 6325 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6326 { 6327 const PetscInt np = *numPoints; 6328 PetscInt pStart, pEnd, p, q; 6329 6330 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6331 for (p = 0, q = 0; p < np; ++p) { 6332 const PetscInt r = points[p * 2]; 6333 if ((r >= pStart) && (r < pEnd)) { 6334 points[q * 2] = r; 6335 points[q * 2 + 1] = points[p * 2 + 1]; 6336 ++q; 6337 } 6338 } 6339 *numPoints = q; 6340 return PETSC_SUCCESS; 6341 } 6342 6343 /* Compressed closure does not apply closure permutation */ 6344 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6345 { 6346 const PetscInt *cla = NULL; 6347 PetscInt np, *pts = NULL; 6348 6349 PetscFunctionBeginHot; 6350 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6351 if (!ornt && *clPoints) { 6352 PetscInt dof, off; 6353 6354 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6355 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6356 PetscCall(ISGetIndices(*clPoints, &cla)); 6357 np = dof / 2; 6358 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6359 } else { 6360 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6361 PetscCall(CompressPoints_Private(section, &np, pts)); 6362 } 6363 *numPoints = np; 6364 *points = pts; 6365 *clp = cla; 6366 PetscFunctionReturn(PETSC_SUCCESS); 6367 } 6368 6369 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6370 { 6371 PetscFunctionBeginHot; 6372 if (!*clPoints) { 6373 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6374 } else { 6375 PetscCall(ISRestoreIndices(*clPoints, clp)); 6376 } 6377 *numPoints = 0; 6378 *points = NULL; 6379 *clSec = NULL; 6380 *clPoints = NULL; 6381 *clp = NULL; 6382 PetscFunctionReturn(PETSC_SUCCESS); 6383 } 6384 6385 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6386 { 6387 PetscInt offset = 0, p; 6388 const PetscInt **perms = NULL; 6389 const PetscScalar **flips = NULL; 6390 6391 PetscFunctionBeginHot; 6392 *size = 0; 6393 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6394 for (p = 0; p < numPoints; p++) { 6395 const PetscInt point = points[2 * p]; 6396 const PetscInt *perm = perms ? perms[p] : NULL; 6397 const PetscScalar *flip = flips ? flips[p] : NULL; 6398 PetscInt dof, off, d; 6399 const PetscScalar *varr; 6400 6401 PetscCall(PetscSectionGetDof(section, point, &dof)); 6402 PetscCall(PetscSectionGetOffset(section, point, &off)); 6403 varr = PetscSafePointerPlusOffset(vArray, off); 6404 if (clperm) { 6405 if (perm) { 6406 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6407 } else { 6408 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6409 } 6410 if (flip) { 6411 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6412 } 6413 } else { 6414 if (perm) { 6415 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6416 } else { 6417 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6418 } 6419 if (flip) { 6420 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6421 } 6422 } 6423 offset += dof; 6424 } 6425 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6426 *size = offset; 6427 PetscFunctionReturn(PETSC_SUCCESS); 6428 } 6429 6430 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[]) 6431 { 6432 PetscInt offset = 0, f; 6433 6434 PetscFunctionBeginHot; 6435 *size = 0; 6436 for (f = 0; f < numFields; ++f) { 6437 PetscInt p; 6438 const PetscInt **perms = NULL; 6439 const PetscScalar **flips = NULL; 6440 6441 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6442 for (p = 0; p < numPoints; p++) { 6443 const PetscInt point = points[2 * p]; 6444 PetscInt fdof, foff, b; 6445 const PetscScalar *varr; 6446 const PetscInt *perm = perms ? perms[p] : NULL; 6447 const PetscScalar *flip = flips ? flips[p] : NULL; 6448 6449 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6450 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6451 varr = &vArray[foff]; 6452 if (clperm) { 6453 if (perm) { 6454 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6455 } else { 6456 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6457 } 6458 if (flip) { 6459 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6460 } 6461 } else { 6462 if (perm) { 6463 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6464 } else { 6465 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6466 } 6467 if (flip) { 6468 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6469 } 6470 } 6471 offset += fdof; 6472 } 6473 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6474 } 6475 *size = offset; 6476 PetscFunctionReturn(PETSC_SUCCESS); 6477 } 6478 6479 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6480 { 6481 PetscSection clSection; 6482 IS clPoints; 6483 PetscInt *points = NULL; 6484 const PetscInt *clp, *perm = NULL; 6485 PetscInt depth, numFields, numPoints, asize; 6486 6487 PetscFunctionBeginHot; 6488 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6489 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6490 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6491 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6492 PetscCall(DMPlexGetDepth(dm, &depth)); 6493 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6494 if (depth == 1 && numFields < 2) { 6495 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6496 PetscFunctionReturn(PETSC_SUCCESS); 6497 } 6498 /* Get points */ 6499 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6500 /* Get sizes */ 6501 asize = 0; 6502 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6503 PetscInt dof; 6504 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6505 asize += dof; 6506 } 6507 if (values) { 6508 const PetscScalar *vArray; 6509 PetscInt size; 6510 6511 if (*values) { 6512 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); 6513 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6514 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6515 PetscCall(VecGetArrayRead(v, &vArray)); 6516 /* Get values */ 6517 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6518 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6519 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6520 /* Cleanup array */ 6521 PetscCall(VecRestoreArrayRead(v, &vArray)); 6522 } 6523 if (csize) *csize = asize; 6524 /* Cleanup points */ 6525 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6526 PetscFunctionReturn(PETSC_SUCCESS); 6527 } 6528 6529 /*@C 6530 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6531 6532 Not collective 6533 6534 Input Parameters: 6535 + dm - The `DM` 6536 . section - The section describing the layout in `v`, or `NULL` to use the default section 6537 . v - The local vector 6538 - point - The point in the `DM` 6539 6540 Input/Output Parameters: 6541 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6542 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6543 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6544 6545 Level: intermediate 6546 6547 Notes: 6548 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6549 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6550 assembly function, and a user may already have allocated storage for this operation. 6551 6552 A typical use could be 6553 .vb 6554 values = NULL; 6555 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6556 for (cl = 0; cl < clSize; ++cl) { 6557 <Compute on closure> 6558 } 6559 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6560 .ve 6561 or 6562 .vb 6563 PetscMalloc1(clMaxSize, &values); 6564 for (p = pStart; p < pEnd; ++p) { 6565 clSize = clMaxSize; 6566 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6567 for (cl = 0; cl < clSize; ++cl) { 6568 <Compute on closure> 6569 } 6570 } 6571 PetscFree(values); 6572 .ve 6573 6574 Fortran Notes: 6575 The `csize` argument is not present in the Fortran binding. 6576 6577 `values` must be declared with 6578 .vb 6579 PetscScalar,dimension(:),pointer :: values 6580 .ve 6581 and it will be allocated internally by PETSc to hold the values returned 6582 6583 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6584 @*/ 6585 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6586 { 6587 PetscFunctionBeginHot; 6588 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6589 PetscFunctionReturn(PETSC_SUCCESS); 6590 } 6591 6592 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6593 { 6594 DMLabel depthLabel; 6595 PetscSection clSection; 6596 IS clPoints; 6597 PetscScalar *array; 6598 const PetscScalar *vArray; 6599 PetscInt *points = NULL; 6600 const PetscInt *clp, *perm = NULL; 6601 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6602 6603 PetscFunctionBeginHot; 6604 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6605 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6606 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6607 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6608 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6609 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6610 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6611 if (mdepth == 1 && numFields < 2) { 6612 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6613 PetscFunctionReturn(PETSC_SUCCESS); 6614 } 6615 /* Get points */ 6616 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6617 for (clsize = 0, p = 0; p < Np; p++) { 6618 PetscInt dof; 6619 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6620 clsize += dof; 6621 } 6622 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6623 /* Filter points */ 6624 for (p = 0; p < numPoints * 2; p += 2) { 6625 PetscInt dep; 6626 6627 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6628 if (dep != depth) continue; 6629 points[Np * 2 + 0] = points[p]; 6630 points[Np * 2 + 1] = points[p + 1]; 6631 ++Np; 6632 } 6633 /* Get array */ 6634 if (!values || !*values) { 6635 PetscInt asize = 0, dof; 6636 6637 for (p = 0; p < Np * 2; p += 2) { 6638 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6639 asize += dof; 6640 } 6641 if (!values) { 6642 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6643 if (csize) *csize = asize; 6644 PetscFunctionReturn(PETSC_SUCCESS); 6645 } 6646 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6647 } else { 6648 array = *values; 6649 } 6650 PetscCall(VecGetArrayRead(v, &vArray)); 6651 /* Get values */ 6652 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6653 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6654 /* Cleanup points */ 6655 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6656 /* Cleanup array */ 6657 PetscCall(VecRestoreArrayRead(v, &vArray)); 6658 if (!*values) { 6659 if (csize) *csize = size; 6660 *values = array; 6661 } else { 6662 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6663 *csize = size; 6664 } 6665 PetscFunctionReturn(PETSC_SUCCESS); 6666 } 6667 6668 /*@C 6669 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6670 6671 Not collective 6672 6673 Input Parameters: 6674 + dm - The `DM` 6675 . section - The section describing the layout in `v`, or `NULL` to use the default section 6676 . v - The local vector 6677 . point - The point in the `DM` 6678 . csize - The number of values in the closure, or `NULL` 6679 - values - The array of values 6680 6681 Level: intermediate 6682 6683 Note: 6684 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6685 6686 Fortran Note: 6687 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6688 6689 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6690 @*/ 6691 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6692 { 6693 PetscInt size = 0; 6694 6695 PetscFunctionBegin; 6696 /* Should work without recalculating size */ 6697 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6698 *values = NULL; 6699 PetscFunctionReturn(PETSC_SUCCESS); 6700 } 6701 6702 static inline void add(PetscScalar *x, PetscScalar y) 6703 { 6704 *x += y; 6705 } 6706 static inline void insert(PetscScalar *x, PetscScalar y) 6707 { 6708 *x = y; 6709 } 6710 6711 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[]) 6712 { 6713 PetscInt cdof; /* The number of constraints on this point */ 6714 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6715 PetscScalar *a; 6716 PetscInt off, cind = 0, k; 6717 6718 PetscFunctionBegin; 6719 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6720 PetscCall(PetscSectionGetOffset(section, point, &off)); 6721 a = &array[off]; 6722 if (!cdof || setBC) { 6723 if (clperm) { 6724 if (perm) { 6725 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6726 } else { 6727 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6728 } 6729 } else { 6730 if (perm) { 6731 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6732 } else { 6733 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6734 } 6735 } 6736 } else { 6737 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6738 if (clperm) { 6739 if (perm) { 6740 for (k = 0; k < dof; ++k) { 6741 if ((cind < cdof) && (k == cdofs[cind])) { 6742 ++cind; 6743 continue; 6744 } 6745 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6746 } 6747 } else { 6748 for (k = 0; k < dof; ++k) { 6749 if ((cind < cdof) && (k == cdofs[cind])) { 6750 ++cind; 6751 continue; 6752 } 6753 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6754 } 6755 } 6756 } else { 6757 if (perm) { 6758 for (k = 0; k < dof; ++k) { 6759 if ((cind < cdof) && (k == cdofs[cind])) { 6760 ++cind; 6761 continue; 6762 } 6763 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6764 } 6765 } else { 6766 for (k = 0; k < dof; ++k) { 6767 if ((cind < cdof) && (k == cdofs[cind])) { 6768 ++cind; 6769 continue; 6770 } 6771 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6772 } 6773 } 6774 } 6775 } 6776 PetscFunctionReturn(PETSC_SUCCESS); 6777 } 6778 6779 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[]) 6780 { 6781 PetscInt cdof; /* The number of constraints on this point */ 6782 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6783 PetscScalar *a; 6784 PetscInt off, cind = 0, k; 6785 6786 PetscFunctionBegin; 6787 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6788 PetscCall(PetscSectionGetOffset(section, point, &off)); 6789 a = &array[off]; 6790 if (cdof) { 6791 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6792 if (clperm) { 6793 if (perm) { 6794 for (k = 0; k < dof; ++k) { 6795 if ((cind < cdof) && (k == cdofs[cind])) { 6796 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6797 cind++; 6798 } 6799 } 6800 } else { 6801 for (k = 0; k < dof; ++k) { 6802 if ((cind < cdof) && (k == cdofs[cind])) { 6803 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6804 cind++; 6805 } 6806 } 6807 } 6808 } else { 6809 if (perm) { 6810 for (k = 0; k < dof; ++k) { 6811 if ((cind < cdof) && (k == cdofs[cind])) { 6812 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6813 cind++; 6814 } 6815 } 6816 } else { 6817 for (k = 0; k < dof; ++k) { 6818 if ((cind < cdof) && (k == cdofs[cind])) { 6819 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6820 cind++; 6821 } 6822 } 6823 } 6824 } 6825 } 6826 PetscFunctionReturn(PETSC_SUCCESS); 6827 } 6828 6829 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[]) 6830 { 6831 PetscScalar *a; 6832 PetscInt fdof, foff, fcdof, foffset = *offset; 6833 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6834 PetscInt cind = 0, b; 6835 6836 PetscFunctionBegin; 6837 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6838 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6839 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6840 a = &array[foff]; 6841 if (!fcdof || setBC) { 6842 if (clperm) { 6843 if (perm) { 6844 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6845 } else { 6846 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6847 } 6848 } else { 6849 if (perm) { 6850 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6851 } else { 6852 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6853 } 6854 } 6855 } else { 6856 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6857 if (clperm) { 6858 if (perm) { 6859 for (b = 0; b < fdof; b++) { 6860 if ((cind < fcdof) && (b == fcdofs[cind])) { 6861 ++cind; 6862 continue; 6863 } 6864 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6865 } 6866 } else { 6867 for (b = 0; b < fdof; b++) { 6868 if ((cind < fcdof) && (b == fcdofs[cind])) { 6869 ++cind; 6870 continue; 6871 } 6872 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6873 } 6874 } 6875 } else { 6876 if (perm) { 6877 for (b = 0; b < fdof; b++) { 6878 if ((cind < fcdof) && (b == fcdofs[cind])) { 6879 ++cind; 6880 continue; 6881 } 6882 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6883 } 6884 } else { 6885 for (b = 0; b < fdof; b++) { 6886 if ((cind < fcdof) && (b == fcdofs[cind])) { 6887 ++cind; 6888 continue; 6889 } 6890 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6891 } 6892 } 6893 } 6894 } 6895 *offset += fdof; 6896 PetscFunctionReturn(PETSC_SUCCESS); 6897 } 6898 6899 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[]) 6900 { 6901 PetscScalar *a; 6902 PetscInt fdof, foff, fcdof, foffset = *offset; 6903 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6904 PetscInt Nc, cind = 0, ncind = 0, b; 6905 PetscBool ncSet, fcSet; 6906 6907 PetscFunctionBegin; 6908 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6909 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6910 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6911 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6912 a = &array[foff]; 6913 if (fcdof) { 6914 /* We just override fcdof and fcdofs with Ncc and comps */ 6915 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6916 if (clperm) { 6917 if (perm) { 6918 if (comps) { 6919 for (b = 0; b < fdof; b++) { 6920 ncSet = fcSet = PETSC_FALSE; 6921 if (b % Nc == comps[ncind]) { 6922 ncind = (ncind + 1) % Ncc; 6923 ncSet = PETSC_TRUE; 6924 } 6925 if ((cind < fcdof) && (b == fcdofs[cind])) { 6926 ++cind; 6927 fcSet = PETSC_TRUE; 6928 } 6929 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6930 } 6931 } else { 6932 for (b = 0; b < fdof; b++) { 6933 if ((cind < fcdof) && (b == fcdofs[cind])) { 6934 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6935 ++cind; 6936 } 6937 } 6938 } 6939 } else { 6940 if (comps) { 6941 for (b = 0; b < fdof; b++) { 6942 ncSet = fcSet = PETSC_FALSE; 6943 if (b % Nc == comps[ncind]) { 6944 ncind = (ncind + 1) % Ncc; 6945 ncSet = PETSC_TRUE; 6946 } 6947 if ((cind < fcdof) && (b == fcdofs[cind])) { 6948 ++cind; 6949 fcSet = PETSC_TRUE; 6950 } 6951 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6952 } 6953 } else { 6954 for (b = 0; b < fdof; b++) { 6955 if ((cind < fcdof) && (b == fcdofs[cind])) { 6956 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6957 ++cind; 6958 } 6959 } 6960 } 6961 } 6962 } else { 6963 if (perm) { 6964 if (comps) { 6965 for (b = 0; b < fdof; b++) { 6966 ncSet = fcSet = PETSC_FALSE; 6967 if (b % Nc == comps[ncind]) { 6968 ncind = (ncind + 1) % Ncc; 6969 ncSet = PETSC_TRUE; 6970 } 6971 if ((cind < fcdof) && (b == fcdofs[cind])) { 6972 ++cind; 6973 fcSet = PETSC_TRUE; 6974 } 6975 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6976 } 6977 } else { 6978 for (b = 0; b < fdof; b++) { 6979 if ((cind < fcdof) && (b == fcdofs[cind])) { 6980 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6981 ++cind; 6982 } 6983 } 6984 } 6985 } else { 6986 if (comps) { 6987 for (b = 0; b < fdof; b++) { 6988 ncSet = fcSet = PETSC_FALSE; 6989 if (b % Nc == comps[ncind]) { 6990 ncind = (ncind + 1) % Ncc; 6991 ncSet = PETSC_TRUE; 6992 } 6993 if ((cind < fcdof) && (b == fcdofs[cind])) { 6994 ++cind; 6995 fcSet = PETSC_TRUE; 6996 } 6997 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6998 } 6999 } else { 7000 for (b = 0; b < fdof; b++) { 7001 if ((cind < fcdof) && (b == fcdofs[cind])) { 7002 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7003 ++cind; 7004 } 7005 } 7006 } 7007 } 7008 } 7009 } 7010 *offset += fdof; 7011 PetscFunctionReturn(PETSC_SUCCESS); 7012 } 7013 7014 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7015 { 7016 PetscScalar *array; 7017 const PetscInt *cone, *coneO; 7018 PetscInt pStart, pEnd, p, numPoints, off, dof; 7019 7020 PetscFunctionBeginHot; 7021 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7022 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7023 PetscCall(DMPlexGetCone(dm, point, &cone)); 7024 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7025 PetscCall(VecGetArray(v, &array)); 7026 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7027 const PetscInt cp = !p ? point : cone[p - 1]; 7028 const PetscInt o = !p ? 0 : coneO[p - 1]; 7029 7030 if ((cp < pStart) || (cp >= pEnd)) { 7031 dof = 0; 7032 continue; 7033 } 7034 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7035 /* ADD_VALUES */ 7036 { 7037 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7038 PetscScalar *a; 7039 PetscInt cdof, coff, cind = 0, k; 7040 7041 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7042 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7043 a = &array[coff]; 7044 if (!cdof) { 7045 if (o >= 0) { 7046 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7047 } else { 7048 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7049 } 7050 } else { 7051 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7052 if (o >= 0) { 7053 for (k = 0; k < dof; ++k) { 7054 if ((cind < cdof) && (k == cdofs[cind])) { 7055 ++cind; 7056 continue; 7057 } 7058 a[k] += values[off + k]; 7059 } 7060 } else { 7061 for (k = 0; k < dof; ++k) { 7062 if ((cind < cdof) && (k == cdofs[cind])) { 7063 ++cind; 7064 continue; 7065 } 7066 a[k] += values[off + dof - k - 1]; 7067 } 7068 } 7069 } 7070 } 7071 } 7072 PetscCall(VecRestoreArray(v, &array)); 7073 PetscFunctionReturn(PETSC_SUCCESS); 7074 } 7075 7076 /*@C 7077 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7078 7079 Not collective 7080 7081 Input Parameters: 7082 + dm - The `DM` 7083 . section - The section describing the layout in `v`, or `NULL` to use the default section 7084 . v - The local vector 7085 . point - The point in the `DM` 7086 . values - The array of values 7087 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7088 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7089 7090 Level: intermediate 7091 7092 Note: 7093 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7094 7095 Fortran Note: 7096 `values` must be declared with 7097 .vb 7098 PetscScalar,dimension(:),pointer :: values 7099 .ve 7100 7101 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7102 @*/ 7103 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7104 { 7105 PetscSection clSection; 7106 IS clPoints; 7107 PetscScalar *array; 7108 PetscInt *points = NULL; 7109 const PetscInt *clp, *clperm = NULL; 7110 PetscInt depth, numFields, numPoints, p, clsize; 7111 7112 PetscFunctionBeginHot; 7113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7114 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7115 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7116 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7117 PetscCall(DMPlexGetDepth(dm, &depth)); 7118 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7119 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7120 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7121 PetscFunctionReturn(PETSC_SUCCESS); 7122 } 7123 /* Get points */ 7124 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7125 for (clsize = 0, p = 0; p < numPoints; p++) { 7126 PetscInt dof; 7127 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7128 clsize += dof; 7129 } 7130 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7131 /* Get array */ 7132 PetscCall(VecGetArray(v, &array)); 7133 /* Get values */ 7134 if (numFields > 0) { 7135 PetscInt offset = 0, f; 7136 for (f = 0; f < numFields; ++f) { 7137 const PetscInt **perms = NULL; 7138 const PetscScalar **flips = NULL; 7139 7140 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7141 switch (mode) { 7142 case INSERT_VALUES: 7143 for (p = 0; p < numPoints; p++) { 7144 const PetscInt point = points[2 * p]; 7145 const PetscInt *perm = perms ? perms[p] : NULL; 7146 const PetscScalar *flip = flips ? flips[p] : NULL; 7147 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7148 } 7149 break; 7150 case INSERT_ALL_VALUES: 7151 for (p = 0; p < numPoints; p++) { 7152 const PetscInt point = points[2 * p]; 7153 const PetscInt *perm = perms ? perms[p] : NULL; 7154 const PetscScalar *flip = flips ? flips[p] : NULL; 7155 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7156 } 7157 break; 7158 case INSERT_BC_VALUES: 7159 for (p = 0; p < numPoints; p++) { 7160 const PetscInt point = points[2 * p]; 7161 const PetscInt *perm = perms ? perms[p] : NULL; 7162 const PetscScalar *flip = flips ? flips[p] : NULL; 7163 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7164 } 7165 break; 7166 case ADD_VALUES: 7167 for (p = 0; p < numPoints; p++) { 7168 const PetscInt point = points[2 * p]; 7169 const PetscInt *perm = perms ? perms[p] : NULL; 7170 const PetscScalar *flip = flips ? flips[p] : NULL; 7171 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7172 } 7173 break; 7174 case ADD_ALL_VALUES: 7175 for (p = 0; p < numPoints; p++) { 7176 const PetscInt point = points[2 * p]; 7177 const PetscInt *perm = perms ? perms[p] : NULL; 7178 const PetscScalar *flip = flips ? flips[p] : NULL; 7179 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7180 } 7181 break; 7182 case ADD_BC_VALUES: 7183 for (p = 0; p < numPoints; p++) { 7184 const PetscInt point = points[2 * p]; 7185 const PetscInt *perm = perms ? perms[p] : NULL; 7186 const PetscScalar *flip = flips ? flips[p] : NULL; 7187 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7188 } 7189 break; 7190 default: 7191 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7192 } 7193 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7194 } 7195 } else { 7196 PetscInt dof, off; 7197 const PetscInt **perms = NULL; 7198 const PetscScalar **flips = NULL; 7199 7200 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7201 switch (mode) { 7202 case INSERT_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_FALSE, perm, flip, clperm, values, off, array)); 7209 } 7210 break; 7211 case INSERT_ALL_VALUES: 7212 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7213 const PetscInt point = points[2 * p]; 7214 const PetscInt *perm = perms ? perms[p] : NULL; 7215 const PetscScalar *flip = flips ? flips[p] : NULL; 7216 PetscCall(PetscSectionGetDof(section, point, &dof)); 7217 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7218 } 7219 break; 7220 case INSERT_BC_VALUES: 7221 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7222 const PetscInt point = points[2 * p]; 7223 const PetscInt *perm = perms ? perms[p] : NULL; 7224 const PetscScalar *flip = flips ? flips[p] : NULL; 7225 PetscCall(PetscSectionGetDof(section, point, &dof)); 7226 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7227 } 7228 break; 7229 case ADD_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_FALSE, perm, flip, clperm, values, off, array)); 7236 } 7237 break; 7238 case ADD_ALL_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(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7245 } 7246 break; 7247 case ADD_BC_VALUES: 7248 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7249 const PetscInt point = points[2 * p]; 7250 const PetscInt *perm = perms ? perms[p] : NULL; 7251 const PetscScalar *flip = flips ? flips[p] : NULL; 7252 PetscCall(PetscSectionGetDof(section, point, &dof)); 7253 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7254 } 7255 break; 7256 default: 7257 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7258 } 7259 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7260 } 7261 /* Cleanup points */ 7262 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7263 /* Cleanup array */ 7264 PetscCall(VecRestoreArray(v, &array)); 7265 PetscFunctionReturn(PETSC_SUCCESS); 7266 } 7267 7268 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7269 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7270 { 7271 PetscFunctionBegin; 7272 *contains = PETSC_TRUE; 7273 if (label) { 7274 PetscInt fdof; 7275 7276 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7277 if (!*contains) { 7278 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7279 *offset += fdof; 7280 PetscFunctionReturn(PETSC_SUCCESS); 7281 } 7282 } 7283 PetscFunctionReturn(PETSC_SUCCESS); 7284 } 7285 7286 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7287 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) 7288 { 7289 PetscSection clSection; 7290 IS clPoints; 7291 PetscScalar *array; 7292 PetscInt *points = NULL; 7293 const PetscInt *clp; 7294 PetscInt numFields, numPoints, p; 7295 PetscInt offset = 0, f; 7296 7297 PetscFunctionBeginHot; 7298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7299 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7300 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7301 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7302 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7303 /* Get points */ 7304 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7305 /* Get array */ 7306 PetscCall(VecGetArray(v, &array)); 7307 /* Get values */ 7308 for (f = 0; f < numFields; ++f) { 7309 const PetscInt **perms = NULL; 7310 const PetscScalar **flips = NULL; 7311 PetscBool contains; 7312 7313 if (!fieldActive[f]) { 7314 for (p = 0; p < numPoints * 2; p += 2) { 7315 PetscInt fdof; 7316 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7317 offset += fdof; 7318 } 7319 continue; 7320 } 7321 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7322 switch (mode) { 7323 case INSERT_VALUES: 7324 for (p = 0; p < numPoints; p++) { 7325 const PetscInt point = points[2 * p]; 7326 const PetscInt *perm = perms ? perms[p] : NULL; 7327 const PetscScalar *flip = flips ? flips[p] : NULL; 7328 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7329 if (!contains) continue; 7330 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7331 } 7332 break; 7333 case INSERT_ALL_VALUES: 7334 for (p = 0; p < numPoints; p++) { 7335 const PetscInt point = points[2 * p]; 7336 const PetscInt *perm = perms ? perms[p] : NULL; 7337 const PetscScalar *flip = flips ? flips[p] : NULL; 7338 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7339 if (!contains) continue; 7340 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7341 } 7342 break; 7343 case INSERT_BC_VALUES: 7344 for (p = 0; p < numPoints; p++) { 7345 const PetscInt point = points[2 * p]; 7346 const PetscInt *perm = perms ? perms[p] : NULL; 7347 const PetscScalar *flip = flips ? flips[p] : NULL; 7348 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7349 if (!contains) continue; 7350 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7351 } 7352 break; 7353 case ADD_VALUES: 7354 for (p = 0; p < numPoints; p++) { 7355 const PetscInt point = points[2 * p]; 7356 const PetscInt *perm = perms ? perms[p] : NULL; 7357 const PetscScalar *flip = flips ? flips[p] : NULL; 7358 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7359 if (!contains) continue; 7360 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7361 } 7362 break; 7363 case ADD_ALL_VALUES: 7364 for (p = 0; p < numPoints; p++) { 7365 const PetscInt point = points[2 * p]; 7366 const PetscInt *perm = perms ? perms[p] : NULL; 7367 const PetscScalar *flip = flips ? flips[p] : NULL; 7368 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7369 if (!contains) continue; 7370 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7371 } 7372 break; 7373 default: 7374 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7375 } 7376 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7377 } 7378 /* Cleanup points */ 7379 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7380 /* Cleanup array */ 7381 PetscCall(VecRestoreArray(v, &array)); 7382 PetscFunctionReturn(PETSC_SUCCESS); 7383 } 7384 7385 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7386 { 7387 PetscMPIInt rank; 7388 PetscInt i, j; 7389 7390 PetscFunctionBegin; 7391 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7392 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7393 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7394 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7395 numCIndices = numCIndices ? numCIndices : numRIndices; 7396 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7397 for (i = 0; i < numRIndices; i++) { 7398 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7399 for (j = 0; j < numCIndices; j++) { 7400 #if defined(PETSC_USE_COMPLEX) 7401 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7402 #else 7403 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7404 #endif 7405 } 7406 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7407 } 7408 PetscFunctionReturn(PETSC_SUCCESS); 7409 } 7410 7411 /* 7412 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7413 7414 Input Parameters: 7415 + section - The section for this data layout 7416 . islocal - Is the section (and thus indices being requested) local or global? 7417 . point - The point contributing dofs with these indices 7418 . off - The global offset of this point 7419 . loff - The local offset of each field 7420 . setBC - The flag determining whether to include indices of boundary values 7421 . perm - A permutation of the dofs on this point, or NULL 7422 - indperm - A permutation of the entire indices array, or NULL 7423 7424 Output Parameter: 7425 . indices - Indices for dofs on this point 7426 7427 Level: developer 7428 7429 Note: The indices could be local or global, depending on the value of 'off'. 7430 */ 7431 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7432 { 7433 PetscInt dof; /* The number of unknowns on this point */ 7434 PetscInt cdof; /* The number of constraints on this point */ 7435 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7436 PetscInt cind = 0, k; 7437 7438 PetscFunctionBegin; 7439 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7440 PetscCall(PetscSectionGetDof(section, point, &dof)); 7441 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7442 if (!cdof || setBC) { 7443 for (k = 0; k < dof; ++k) { 7444 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7445 const PetscInt ind = indperm ? indperm[preind] : preind; 7446 7447 indices[ind] = off + k; 7448 } 7449 } else { 7450 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7451 for (k = 0; k < dof; ++k) { 7452 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7453 const PetscInt ind = indperm ? indperm[preind] : preind; 7454 7455 if ((cind < cdof) && (k == cdofs[cind])) { 7456 /* Insert check for returning constrained indices */ 7457 indices[ind] = -(off + k + 1); 7458 ++cind; 7459 } else { 7460 indices[ind] = off + k - (islocal ? 0 : cind); 7461 } 7462 } 7463 } 7464 *loff += dof; 7465 PetscFunctionReturn(PETSC_SUCCESS); 7466 } 7467 7468 /* 7469 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7470 7471 Input Parameters: 7472 + section - a section (global or local) 7473 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7474 . point - point within section 7475 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7476 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7477 . setBC - identify constrained (boundary condition) points via involution. 7478 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7479 . permsoff - offset 7480 - indperm - index permutation 7481 7482 Output Parameter: 7483 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7484 . indices - array to hold indices (as defined by section) of each dof associated with point 7485 7486 Notes: 7487 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7488 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7489 in the local vector. 7490 7491 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7492 significant). It is invalid to call with a global section and setBC=true. 7493 7494 Developer Note: 7495 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7496 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7497 offset could be obtained from the section instead of passing it explicitly as we do now. 7498 7499 Example: 7500 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7501 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7502 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7503 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. 7504 7505 Level: developer 7506 */ 7507 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[]) 7508 { 7509 PetscInt numFields, foff, f; 7510 7511 PetscFunctionBegin; 7512 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7513 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7514 for (f = 0, foff = 0; f < numFields; ++f) { 7515 PetscInt fdof, cfdof; 7516 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7517 PetscInt cind = 0, b; 7518 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7519 7520 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7521 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7522 if (!cfdof || setBC) { 7523 for (b = 0; b < fdof; ++b) { 7524 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7525 const PetscInt ind = indperm ? indperm[preind] : preind; 7526 7527 indices[ind] = off + foff + b; 7528 } 7529 } else { 7530 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7531 for (b = 0; b < fdof; ++b) { 7532 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7533 const PetscInt ind = indperm ? indperm[preind] : preind; 7534 7535 if ((cind < cfdof) && (b == fcdofs[cind])) { 7536 indices[ind] = -(off + foff + b + 1); 7537 ++cind; 7538 } else { 7539 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7540 } 7541 } 7542 } 7543 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7544 foffs[f] += fdof; 7545 } 7546 PetscFunctionReturn(PETSC_SUCCESS); 7547 } 7548 7549 /* 7550 This version believes the globalSection offsets for each field, rather than just the point offset 7551 7552 . foffs - The offset into 'indices' for each field, since it is segregated by field 7553 7554 Notes: 7555 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7556 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7557 */ 7558 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7559 { 7560 PetscInt numFields, foff, f; 7561 7562 PetscFunctionBegin; 7563 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7564 for (f = 0; f < numFields; ++f) { 7565 PetscInt fdof, cfdof; 7566 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7567 PetscInt cind = 0, b; 7568 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7569 7570 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7571 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7572 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7573 if (!cfdof) { 7574 for (b = 0; b < fdof; ++b) { 7575 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7576 const PetscInt ind = indperm ? indperm[preind] : preind; 7577 7578 indices[ind] = foff + b; 7579 } 7580 } else { 7581 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7582 for (b = 0; b < fdof; ++b) { 7583 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7584 const PetscInt ind = indperm ? indperm[preind] : preind; 7585 7586 if ((cind < cfdof) && (b == fcdofs[cind])) { 7587 indices[ind] = -(foff + b + 1); 7588 ++cind; 7589 } else { 7590 indices[ind] = foff + b - cind; 7591 } 7592 } 7593 } 7594 foffs[f] += fdof; 7595 } 7596 PetscFunctionReturn(PETSC_SUCCESS); 7597 } 7598 7599 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7600 { 7601 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7602 7603 PetscFunctionBegin; 7604 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7605 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7606 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7607 for (PetscInt p = 0; p < nPoints; p++) { 7608 PetscInt b = pnts[2 * p]; 7609 PetscInt bSecDof = 0, bOff; 7610 PetscInt cSecDof = 0; 7611 PetscSection indices_section; 7612 7613 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7614 if (!bSecDof) continue; 7615 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7616 indices_section = cSecDof > 0 ? cSec : section; 7617 if (numFields) { 7618 PetscInt fStart[32], fEnd[32]; 7619 7620 fStart[0] = 0; 7621 fEnd[0] = 0; 7622 for (PetscInt f = 0; f < numFields; f++) { 7623 PetscInt fDof = 0; 7624 7625 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7626 fStart[f + 1] = fStart[f] + fDof; 7627 fEnd[f + 1] = fStart[f + 1]; 7628 } 7629 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7630 // only apply permutations on one side 7631 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7632 for (PetscInt f = 0; f < numFields; f++) { 7633 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7634 } 7635 } else { 7636 PetscInt bEnd = 0; 7637 7638 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7639 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7640 7641 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7642 } 7643 } 7644 PetscFunctionReturn(PETSC_SUCCESS); 7645 } 7646 7647 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[]) 7648 { 7649 Mat cMat; 7650 PetscSection aSec, cSec; 7651 IS aIS; 7652 PetscInt aStart = -1, aEnd = -1; 7653 PetscInt sStart = -1, sEnd = -1; 7654 PetscInt cStart = -1, cEnd = -1; 7655 const PetscInt *anchors; 7656 PetscInt numFields, p; 7657 PetscInt newNumPoints = 0, newNumIndices = 0; 7658 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7659 PetscInt oldOffsets[32]; 7660 PetscInt newOffsets[32]; 7661 PetscInt oldOffsetsCopy[32]; 7662 PetscInt newOffsetsCopy[32]; 7663 PetscScalar *modMat = NULL; 7664 PetscBool anyConstrained = PETSC_FALSE; 7665 7666 PetscFunctionBegin; 7667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7668 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7669 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7670 7671 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7672 /* if there are point-to-point constraints */ 7673 if (aSec) { 7674 PetscCall(PetscArrayzero(newOffsets, 32)); 7675 PetscCall(PetscArrayzero(oldOffsets, 32)); 7676 PetscCall(ISGetIndices(aIS, &anchors)); 7677 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7678 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7679 /* figure out how many points are going to be in the new element matrix 7680 * (we allow double counting, because it's all just going to be summed 7681 * into the global matrix anyway) */ 7682 for (p = 0; p < 2 * numPoints; p += 2) { 7683 PetscInt b = points[p]; 7684 PetscInt bDof = 0, bSecDof = 0; 7685 7686 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7687 if (!bSecDof) continue; 7688 7689 for (PetscInt f = 0; f < numFields; f++) { 7690 PetscInt fDof = 0; 7691 7692 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7693 oldOffsets[f + 1] += fDof; 7694 } 7695 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7696 if (bDof) { 7697 /* this point is constrained */ 7698 /* it is going to be replaced by its anchors */ 7699 PetscInt bOff, q; 7700 7701 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7702 for (q = 0; q < bDof; q++) { 7703 PetscInt a = anchors[bOff + q]; 7704 PetscInt aDof = 0; 7705 7706 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7707 if (aDof) { 7708 anyConstrained = PETSC_TRUE; 7709 newNumPoints += 1; 7710 } 7711 newNumIndices += aDof; 7712 for (PetscInt f = 0; f < numFields; ++f) { 7713 PetscInt fDof = 0; 7714 7715 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7716 newOffsets[f + 1] += fDof; 7717 } 7718 } 7719 } else { 7720 /* this point is not constrained */ 7721 newNumPoints++; 7722 newNumIndices += bSecDof; 7723 for (PetscInt f = 0; f < numFields; ++f) { 7724 PetscInt fDof; 7725 7726 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7727 newOffsets[f + 1] += fDof; 7728 } 7729 } 7730 } 7731 } 7732 if (!anyConstrained) { 7733 if (outNumPoints) *outNumPoints = 0; 7734 if (outNumIndices) *outNumIndices = 0; 7735 if (outPoints) *outPoints = NULL; 7736 if (outMat) *outMat = NULL; 7737 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7738 PetscFunctionReturn(PETSC_SUCCESS); 7739 } 7740 7741 if (outNumPoints) *outNumPoints = newNumPoints; 7742 if (outNumIndices) *outNumIndices = newNumIndices; 7743 7744 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7745 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7746 7747 if (!outPoints && !outMat) { 7748 if (offsets) { 7749 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7750 } 7751 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7752 PetscFunctionReturn(PETSC_SUCCESS); 7753 } 7754 7755 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7756 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7757 7758 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7759 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7760 7761 /* output arrays */ 7762 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7763 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7764 7765 // get the new Points 7766 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7767 PetscInt b = points[2 * p]; 7768 PetscInt bDof = 0, bSecDof = 0, bOff; 7769 7770 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7771 if (!bSecDof) continue; 7772 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7773 if (bDof) { 7774 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7775 for (PetscInt q = 0; q < bDof; q++) { 7776 PetscInt a = anchors[bOff + q], aDof = 0; 7777 7778 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7779 if (aDof) { 7780 newPoints[2 * newP] = a; 7781 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7782 newP++; 7783 } 7784 } 7785 } else { 7786 newPoints[2 * newP] = b; 7787 newPoints[2 * newP + 1] = points[2 * p + 1]; 7788 newP++; 7789 } 7790 } 7791 7792 if (outMat) { 7793 PetscScalar *tmpMat; 7794 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7795 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7796 7797 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7798 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7799 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7800 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7801 7802 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7803 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7804 7805 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7806 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7807 7808 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7809 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7810 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7811 // for each field, insert the anchor modification into modMat 7812 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7813 PetscInt fStart = oldOffsets[f]; 7814 PetscInt fNewStart = newOffsets[f]; 7815 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7816 PetscInt b = points[2 * p]; 7817 PetscInt bDof = 0, bSecDof = 0, bOff; 7818 7819 if (b >= sStart && b < sEnd) { 7820 if (numFields) { 7821 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7822 } else { 7823 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7824 } 7825 } 7826 if (!bSecDof) continue; 7827 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7828 if (bDof) { 7829 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7830 for (PetscInt q = 0; q < bDof; q++, newP++) { 7831 PetscInt a = anchors[bOff + q], aDof = 0; 7832 7833 if (a >= sStart && a < sEnd) { 7834 if (numFields) { 7835 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7836 } else { 7837 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7838 } 7839 } 7840 if (aDof) { 7841 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7842 for (PetscInt d = 0; d < bSecDof; d++) { 7843 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7844 } 7845 } 7846 oNew += aDof; 7847 } 7848 } else { 7849 // Insert the identity matrix in this block 7850 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7851 oNew += bSecDof; 7852 newP++; 7853 } 7854 o += bSecDof; 7855 } 7856 } 7857 7858 *outMat = modMat; 7859 7860 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7861 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7862 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7863 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7864 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7865 } 7866 PetscCall(ISRestoreIndices(aIS, &anchors)); 7867 7868 /* output */ 7869 if (outPoints) { 7870 *outPoints = newPoints; 7871 } else { 7872 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7873 } 7874 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7875 PetscFunctionReturn(PETSC_SUCCESS); 7876 } 7877 7878 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) 7879 { 7880 PetscScalar *modMat = NULL; 7881 PetscInt newNumIndices = -1; 7882 7883 PetscFunctionBegin; 7884 /* 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. 7885 modMat is that matrix C */ 7886 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7887 if (outNumIndices) *outNumIndices = newNumIndices; 7888 if (modMat) { 7889 const PetscScalar *newValues = values; 7890 7891 if (multiplyRight) { 7892 PetscScalar *newNewValues = NULL; 7893 PetscBLASInt M = newNumIndices; 7894 PetscBLASInt N = numRows; 7895 PetscBLASInt K = numIndices; 7896 PetscScalar a = 1.0, b = 0.0; 7897 7898 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); 7899 7900 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7901 // row-major to column-major conversion, right multiplication becomes left multiplication 7902 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7903 7904 numCols = newNumIndices; 7905 newValues = newNewValues; 7906 } 7907 7908 if (multiplyLeft) { 7909 PetscScalar *newNewValues = NULL; 7910 PetscBLASInt M = numCols; 7911 PetscBLASInt N = newNumIndices; 7912 PetscBLASInt K = numIndices; 7913 PetscScalar a = 1.0, b = 0.0; 7914 7915 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); 7916 7917 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7918 // row-major to column-major conversion, left multiplication becomes right multiplication 7919 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7920 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7921 newValues = newNewValues; 7922 } 7923 *outValues = (PetscScalar *)newValues; 7924 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7925 } 7926 PetscFunctionReturn(PETSC_SUCCESS); 7927 } 7928 7929 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) 7930 { 7931 PetscFunctionBegin; 7932 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7933 PetscFunctionReturn(PETSC_SUCCESS); 7934 } 7935 7936 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7937 { 7938 /* Closure ordering */ 7939 PetscSection clSection; 7940 IS clPoints; 7941 const PetscInt *clp; 7942 PetscInt *points; 7943 PetscInt Ncl, Ni = 0; 7944 7945 PetscFunctionBeginHot; 7946 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7947 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7948 PetscInt dof; 7949 7950 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7951 Ni += dof; 7952 } 7953 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7954 *closureSize = Ni; 7955 PetscFunctionReturn(PETSC_SUCCESS); 7956 } 7957 7958 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) 7959 { 7960 /* Closure ordering */ 7961 PetscSection clSection; 7962 IS clPoints; 7963 const PetscInt *clp; 7964 PetscInt *points; 7965 const PetscInt *clperm = NULL; 7966 /* Dof permutation and sign flips */ 7967 const PetscInt **perms[32] = {NULL}; 7968 const PetscScalar **flips[32] = {NULL}; 7969 PetscScalar *valCopy = NULL; 7970 /* Hanging node constraints */ 7971 PetscInt *pointsC = NULL; 7972 PetscScalar *valuesC = NULL; 7973 PetscInt NclC, NiC; 7974 7975 PetscInt *idx; 7976 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7977 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7978 PetscInt idxStart, idxEnd; 7979 PetscInt nRows, nCols; 7980 7981 PetscFunctionBeginHot; 7982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7983 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7984 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7985 PetscAssertPointer(numRows, 6); 7986 PetscAssertPointer(numCols, 7); 7987 if (indices) PetscAssertPointer(indices, 8); 7988 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7989 if (values) PetscAssertPointer(values, 10); 7990 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7991 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7992 PetscCall(PetscArrayzero(offsets, 32)); 7993 /* 1) Get points in closure */ 7994 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7995 if (useClPerm) { 7996 PetscInt depth, clsize; 7997 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7998 for (clsize = 0, p = 0; p < Ncl; p++) { 7999 PetscInt dof; 8000 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8001 clsize += dof; 8002 } 8003 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8004 } 8005 /* 2) Get number of indices on these points and field offsets from section */ 8006 for (p = 0; p < Ncl * 2; p += 2) { 8007 PetscInt dof, fdof; 8008 8009 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8010 for (f = 0; f < Nf; ++f) { 8011 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8012 offsets[f + 1] += fdof; 8013 } 8014 Ni += dof; 8015 } 8016 if (*numRows == -1) *numRows = Ni; 8017 if (*numCols == -1) *numCols = Ni; 8018 nRows = *numRows; 8019 nCols = *numCols; 8020 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8021 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8022 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8023 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8024 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8025 for (f = 0; f < PetscMax(1, Nf); ++f) { 8026 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8027 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8028 /* may need to apply sign changes to the element matrix */ 8029 if (values && flips[f]) { 8030 PetscInt foffset = offsets[f]; 8031 8032 for (p = 0; p < Ncl; ++p) { 8033 PetscInt pnt = points[2 * p], fdof; 8034 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8035 8036 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8037 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8038 if (flip) { 8039 PetscInt i, j, k; 8040 8041 if (!valCopy) { 8042 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8043 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8044 *values = valCopy; 8045 } 8046 for (i = 0; i < fdof; ++i) { 8047 PetscScalar fval = flip[i]; 8048 8049 if (multiplyRight) { 8050 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8051 } 8052 if (multiplyLeft) { 8053 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8054 } 8055 } 8056 } 8057 foffset += fdof; 8058 } 8059 } 8060 } 8061 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8062 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8063 if (NclC) { 8064 if (multiplyRight) { *numCols = nCols = NiC; } 8065 if (multiplyLeft) { *numRows = nRows = NiC; } 8066 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8067 for (f = 0; f < PetscMax(1, Nf); ++f) { 8068 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8069 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8070 } 8071 for (f = 0; f < PetscMax(1, Nf); ++f) { 8072 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8073 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8074 } 8075 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8076 Ncl = NclC; 8077 Ni = NiC; 8078 points = pointsC; 8079 if (values) *values = valuesC; 8080 } 8081 /* 5) Calculate indices */ 8082 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8083 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8084 if (Nf) { 8085 PetscInt idxOff; 8086 PetscBool useFieldOffsets; 8087 8088 if (outOffsets) { 8089 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8090 } 8091 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8092 if (useFieldOffsets) { 8093 for (p = 0; p < Ncl; ++p) { 8094 const PetscInt pnt = points[p * 2]; 8095 8096 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8097 } 8098 } else { 8099 for (p = 0; p < Ncl; ++p) { 8100 const PetscInt pnt = points[p * 2]; 8101 8102 if (pnt < idxStart || pnt >= idxEnd) continue; 8103 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8104 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8105 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8106 * global section. */ 8107 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8108 } 8109 } 8110 } else { 8111 PetscInt off = 0, idxOff; 8112 8113 for (p = 0; p < Ncl; ++p) { 8114 const PetscInt pnt = points[p * 2]; 8115 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8116 8117 if (pnt < idxStart || pnt >= idxEnd) continue; 8118 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8119 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8120 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8121 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8122 } 8123 } 8124 /* 6) Cleanup */ 8125 for (f = 0; f < PetscMax(1, Nf); ++f) { 8126 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8127 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8128 } 8129 if (NclC) { 8130 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8131 } else { 8132 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8133 } 8134 8135 if (indices) *indices = idx; 8136 PetscFunctionReturn(PETSC_SUCCESS); 8137 } 8138 8139 /*@C 8140 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8141 8142 Not collective 8143 8144 Input Parameters: 8145 + dm - The `DM` 8146 . section - The `PetscSection` describing the points (a local section) 8147 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8148 . point - The point defining the closure 8149 - useClPerm - Use the closure point permutation if available 8150 8151 Output Parameters: 8152 + numIndices - The number of dof indices in the closure of point with the input sections 8153 . indices - The dof indices 8154 . outOffsets - Array to write the field offsets into, or `NULL` 8155 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8156 8157 Level: advanced 8158 8159 Notes: 8160 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8161 8162 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8163 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8164 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8165 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8166 indices (with the above semantics) are implied. 8167 8168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8169 `PetscSection`, `DMGetGlobalSection()` 8170 @*/ 8171 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8172 { 8173 PetscInt numRows = -1, numCols = -1; 8174 8175 PetscFunctionBeginHot; 8176 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8177 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8178 *numIndices = numRows; 8179 PetscFunctionReturn(PETSC_SUCCESS); 8180 } 8181 8182 /*@C 8183 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8184 8185 Not collective 8186 8187 Input Parameters: 8188 + dm - The `DM` 8189 . section - The `PetscSection` describing the points (a local section) 8190 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8191 . point - The point defining the closure 8192 - useClPerm - Use the closure point permutation if available 8193 8194 Output Parameters: 8195 + numIndices - The number of dof indices in the closure of point with the input sections 8196 . indices - The dof indices 8197 . outOffsets - Array to write the field offsets into, or `NULL` 8198 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8199 8200 Level: advanced 8201 8202 Notes: 8203 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8204 8205 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8206 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8207 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8208 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8209 indices (with the above semantics) are implied. 8210 8211 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8212 @*/ 8213 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8214 { 8215 PetscFunctionBegin; 8216 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8217 PetscAssertPointer(indices, 7); 8218 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8219 PetscFunctionReturn(PETSC_SUCCESS); 8220 } 8221 8222 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8223 { 8224 DM_Plex *mesh = (DM_Plex *)dm->data; 8225 PetscInt *indices; 8226 PetscInt numIndices; 8227 const PetscScalar *valuesOrig = values; 8228 PetscErrorCode ierr; 8229 8230 PetscFunctionBegin; 8231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8232 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8233 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8234 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8235 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8236 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8237 8238 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8239 8240 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8241 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8242 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8243 if (ierr) { 8244 PetscMPIInt rank; 8245 8246 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8247 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8248 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8249 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8250 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8251 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8252 } 8253 if (mesh->printFEM > 1) { 8254 PetscInt i; 8255 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8256 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8257 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8258 } 8259 8260 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8261 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8262 PetscFunctionReturn(PETSC_SUCCESS); 8263 } 8264 8265 /*@C 8266 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8267 8268 Not collective 8269 8270 Input Parameters: 8271 + dm - The `DM` 8272 . section - The section describing the layout in `v`, or `NULL` to use the default section 8273 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8274 . A - The matrix 8275 . point - The point in the `DM` 8276 . values - The array of values 8277 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8278 8279 Level: intermediate 8280 8281 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8282 @*/ 8283 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8284 { 8285 PetscFunctionBegin; 8286 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8287 PetscFunctionReturn(PETSC_SUCCESS); 8288 } 8289 8290 /*@C 8291 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8292 8293 Not collective 8294 8295 Input Parameters: 8296 + dmRow - The `DM` for the row fields 8297 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8298 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8299 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8300 . dmCol - The `DM` for the column fields 8301 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8302 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8303 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8304 . A - The matrix 8305 . point - The point in the `DM` 8306 . values - The array of values 8307 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8308 8309 Level: intermediate 8310 8311 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8312 @*/ 8313 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) 8314 { 8315 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8316 PetscInt *indicesRow, *indicesCol; 8317 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8318 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8319 8320 PetscErrorCode ierr; 8321 8322 PetscFunctionBegin; 8323 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8324 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8325 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8326 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8327 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8328 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8329 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8330 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8331 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8332 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8333 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8334 8335 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8336 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8337 valuesV1 = valuesV0; 8338 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8339 valuesV2 = valuesV1; 8340 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8341 8342 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8343 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8344 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8345 if (ierr) { 8346 PetscMPIInt rank; 8347 8348 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8349 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8350 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8351 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8352 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8353 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8354 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8355 } 8356 8357 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8358 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8359 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8360 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8361 PetscFunctionReturn(PETSC_SUCCESS); 8362 } 8363 8364 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8365 { 8366 DM_Plex *mesh = (DM_Plex *)dmf->data; 8367 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8368 PetscInt *cpoints = NULL; 8369 PetscInt *findices, *cindices; 8370 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8371 PetscInt foffsets[32], coffsets[32]; 8372 DMPolytopeType ct; 8373 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8374 PetscErrorCode ierr; 8375 8376 PetscFunctionBegin; 8377 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8378 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8379 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8380 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8381 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8382 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8383 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8384 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8385 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8386 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8387 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8388 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8389 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8390 PetscCall(PetscArrayzero(foffsets, 32)); 8391 PetscCall(PetscArrayzero(coffsets, 32)); 8392 /* Column indices */ 8393 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8394 maxFPoints = numCPoints; 8395 /* Compress out points not in the section */ 8396 /* TODO: Squeeze out points with 0 dof as well */ 8397 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8398 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8399 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8400 cpoints[q * 2] = cpoints[p]; 8401 cpoints[q * 2 + 1] = cpoints[p + 1]; 8402 ++q; 8403 } 8404 } 8405 numCPoints = q; 8406 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8407 PetscInt fdof; 8408 8409 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8410 if (!dof) continue; 8411 for (f = 0; f < numFields; ++f) { 8412 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8413 coffsets[f + 1] += fdof; 8414 } 8415 numCIndices += dof; 8416 } 8417 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8418 /* Row indices */ 8419 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8420 { 8421 DMPlexTransform tr; 8422 DMPolytopeType *rct; 8423 PetscInt *rsize, *rcone, *rornt, Nt; 8424 8425 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8426 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8427 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8428 numSubcells = rsize[Nt - 1]; 8429 PetscCall(DMPlexTransformDestroy(&tr)); 8430 } 8431 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8432 for (r = 0, q = 0; r < numSubcells; ++r) { 8433 /* TODO Map from coarse to fine cells */ 8434 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8435 /* Compress out points not in the section */ 8436 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8437 for (p = 0; p < numFPoints * 2; p += 2) { 8438 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8439 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8440 if (!dof) continue; 8441 for (s = 0; s < q; ++s) 8442 if (fpoints[p] == ftotpoints[s * 2]) break; 8443 if (s < q) continue; 8444 ftotpoints[q * 2] = fpoints[p]; 8445 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8446 ++q; 8447 } 8448 } 8449 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8450 } 8451 numFPoints = q; 8452 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8453 PetscInt fdof; 8454 8455 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8456 if (!dof) continue; 8457 for (f = 0; f < numFields; ++f) { 8458 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8459 foffsets[f + 1] += fdof; 8460 } 8461 numFIndices += dof; 8462 } 8463 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8464 8465 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8466 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8467 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8468 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8469 if (numFields) { 8470 const PetscInt **permsF[32] = {NULL}; 8471 const PetscInt **permsC[32] = {NULL}; 8472 8473 for (f = 0; f < numFields; f++) { 8474 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8475 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8476 } 8477 for (p = 0; p < numFPoints; p++) { 8478 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8479 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8480 } 8481 for (p = 0; p < numCPoints; p++) { 8482 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8483 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8484 } 8485 for (f = 0; f < numFields; f++) { 8486 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8487 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8488 } 8489 } else { 8490 const PetscInt **permsF = NULL; 8491 const PetscInt **permsC = NULL; 8492 8493 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8494 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8495 for (p = 0, off = 0; p < numFPoints; p++) { 8496 const PetscInt *perm = permsF ? permsF[p] : NULL; 8497 8498 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8499 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8500 } 8501 for (p = 0, off = 0; p < numCPoints; p++) { 8502 const PetscInt *perm = permsC ? permsC[p] : NULL; 8503 8504 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8505 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8506 } 8507 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8508 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8509 } 8510 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8511 /* TODO: flips */ 8512 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8513 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8514 if (ierr) { 8515 PetscMPIInt rank; 8516 8517 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8518 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8519 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8520 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8521 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8522 } 8523 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8524 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8525 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8526 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8527 PetscFunctionReturn(PETSC_SUCCESS); 8528 } 8529 8530 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8531 { 8532 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8533 PetscInt *cpoints = NULL; 8534 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8535 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8536 DMPolytopeType ct; 8537 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8538 8539 PetscFunctionBegin; 8540 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8541 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8542 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8543 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8544 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8545 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8546 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8547 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8548 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8549 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8550 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8551 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8552 /* Column indices */ 8553 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8554 maxFPoints = numCPoints; 8555 /* Compress out points not in the section */ 8556 /* TODO: Squeeze out points with 0 dof as well */ 8557 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8558 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8559 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8560 cpoints[q * 2] = cpoints[p]; 8561 cpoints[q * 2 + 1] = cpoints[p + 1]; 8562 ++q; 8563 } 8564 } 8565 numCPoints = q; 8566 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8567 PetscInt fdof; 8568 8569 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8570 if (!dof) continue; 8571 for (f = 0; f < numFields; ++f) { 8572 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8573 coffsets[f + 1] += fdof; 8574 } 8575 numCIndices += dof; 8576 } 8577 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8578 /* Row indices */ 8579 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8580 { 8581 DMPlexTransform tr; 8582 DMPolytopeType *rct; 8583 PetscInt *rsize, *rcone, *rornt, Nt; 8584 8585 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8586 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8587 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8588 numSubcells = rsize[Nt - 1]; 8589 PetscCall(DMPlexTransformDestroy(&tr)); 8590 } 8591 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8592 for (r = 0, q = 0; r < numSubcells; ++r) { 8593 /* TODO Map from coarse to fine cells */ 8594 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8595 /* Compress out points not in the section */ 8596 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8597 for (p = 0; p < numFPoints * 2; p += 2) { 8598 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8599 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8600 if (!dof) continue; 8601 for (s = 0; s < q; ++s) 8602 if (fpoints[p] == ftotpoints[s * 2]) break; 8603 if (s < q) continue; 8604 ftotpoints[q * 2] = fpoints[p]; 8605 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8606 ++q; 8607 } 8608 } 8609 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8610 } 8611 numFPoints = q; 8612 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8613 PetscInt fdof; 8614 8615 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8616 if (!dof) continue; 8617 for (f = 0; f < numFields; ++f) { 8618 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8619 foffsets[f + 1] += fdof; 8620 } 8621 numFIndices += dof; 8622 } 8623 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8624 8625 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8626 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8627 if (numFields) { 8628 const PetscInt **permsF[32] = {NULL}; 8629 const PetscInt **permsC[32] = {NULL}; 8630 8631 for (f = 0; f < numFields; f++) { 8632 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8633 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8634 } 8635 for (p = 0; p < numFPoints; p++) { 8636 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8637 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8638 } 8639 for (p = 0; p < numCPoints; p++) { 8640 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8641 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8642 } 8643 for (f = 0; f < numFields; f++) { 8644 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8645 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8646 } 8647 } else { 8648 const PetscInt **permsF = NULL; 8649 const PetscInt **permsC = NULL; 8650 8651 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8652 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8653 for (p = 0, off = 0; p < numFPoints; p++) { 8654 const PetscInt *perm = permsF ? permsF[p] : NULL; 8655 8656 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8657 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8658 } 8659 for (p = 0, off = 0; p < numCPoints; p++) { 8660 const PetscInt *perm = permsC ? permsC[p] : NULL; 8661 8662 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8663 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8664 } 8665 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8666 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8667 } 8668 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8669 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8670 PetscFunctionReturn(PETSC_SUCCESS); 8671 } 8672 8673 /*@ 8674 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8675 8676 Input Parameter: 8677 . dm - The `DMPLEX` object 8678 8679 Output Parameter: 8680 . cellHeight - The height of a cell 8681 8682 Level: developer 8683 8684 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8685 @*/ 8686 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8687 { 8688 DM_Plex *mesh = (DM_Plex *)dm->data; 8689 8690 PetscFunctionBegin; 8691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8692 PetscAssertPointer(cellHeight, 2); 8693 *cellHeight = mesh->vtkCellHeight; 8694 PetscFunctionReturn(PETSC_SUCCESS); 8695 } 8696 8697 /*@ 8698 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8699 8700 Input Parameters: 8701 + dm - The `DMPLEX` object 8702 - cellHeight - The height of a cell 8703 8704 Level: developer 8705 8706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8707 @*/ 8708 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8709 { 8710 DM_Plex *mesh = (DM_Plex *)dm->data; 8711 8712 PetscFunctionBegin; 8713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8714 mesh->vtkCellHeight = cellHeight; 8715 PetscFunctionReturn(PETSC_SUCCESS); 8716 } 8717 8718 /*@ 8719 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8720 8721 Input Parameters: 8722 + dm - The `DMPLEX` object 8723 - ct - The `DMPolytopeType` of the cell 8724 8725 Output Parameters: 8726 + start - The first cell of this type, or `NULL` 8727 - end - The upper bound on this celltype, or `NULL` 8728 8729 Level: advanced 8730 8731 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8732 @*/ 8733 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8734 { 8735 DM_Plex *mesh = (DM_Plex *)dm->data; 8736 DMLabel label; 8737 PetscInt pStart, pEnd; 8738 8739 PetscFunctionBegin; 8740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8741 if (start) { 8742 PetscAssertPointer(start, 3); 8743 *start = 0; 8744 } 8745 if (end) { 8746 PetscAssertPointer(end, 4); 8747 *end = 0; 8748 } 8749 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8750 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8751 if (mesh->tr) { 8752 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8753 } else { 8754 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8755 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8756 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8757 } 8758 PetscFunctionReturn(PETSC_SUCCESS); 8759 } 8760 8761 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8762 { 8763 PetscSection section, globalSection; 8764 PetscInt *numbers, p; 8765 8766 PetscFunctionBegin; 8767 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8768 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8769 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8770 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8771 PetscCall(PetscSectionSetUp(section)); 8772 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8773 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8774 for (p = pStart; p < pEnd; ++p) { 8775 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8776 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8777 else numbers[p - pStart] += shift; 8778 } 8779 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8780 if (globalSize) { 8781 PetscLayout layout; 8782 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8783 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8784 PetscCall(PetscLayoutDestroy(&layout)); 8785 } 8786 PetscCall(PetscSectionDestroy(§ion)); 8787 PetscCall(PetscSectionDestroy(&globalSection)); 8788 PetscFunctionReturn(PETSC_SUCCESS); 8789 } 8790 8791 /*@ 8792 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8793 8794 Input Parameters: 8795 + dm - The `DMPLEX` object 8796 - includeAll - Whether to include all cells, or just the simplex and box cells 8797 8798 Output Parameter: 8799 . globalCellNumbers - Global cell numbers for all cells on this process 8800 8801 Level: developer 8802 8803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8804 @*/ 8805 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8806 { 8807 PetscInt cellHeight, cStart, cEnd; 8808 8809 PetscFunctionBegin; 8810 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8811 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8812 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8813 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8814 PetscFunctionReturn(PETSC_SUCCESS); 8815 } 8816 8817 /*@ 8818 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8819 8820 Input Parameter: 8821 . dm - The `DMPLEX` object 8822 8823 Output Parameter: 8824 . globalCellNumbers - Global cell numbers for all cells on this process 8825 8826 Level: developer 8827 8828 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8829 @*/ 8830 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8831 { 8832 DM_Plex *mesh = (DM_Plex *)dm->data; 8833 8834 PetscFunctionBegin; 8835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8836 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8837 *globalCellNumbers = mesh->globalCellNumbers; 8838 PetscFunctionReturn(PETSC_SUCCESS); 8839 } 8840 8841 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8842 { 8843 PetscInt vStart, vEnd; 8844 8845 PetscFunctionBegin; 8846 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8847 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8848 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8849 PetscFunctionReturn(PETSC_SUCCESS); 8850 } 8851 8852 /*@ 8853 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8854 8855 Input Parameter: 8856 . dm - The `DMPLEX` object 8857 8858 Output Parameter: 8859 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8860 8861 Level: developer 8862 8863 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8864 @*/ 8865 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8866 { 8867 DM_Plex *mesh = (DM_Plex *)dm->data; 8868 8869 PetscFunctionBegin; 8870 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8871 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8872 *globalVertexNumbers = mesh->globalVertexNumbers; 8873 PetscFunctionReturn(PETSC_SUCCESS); 8874 } 8875 8876 /*@ 8877 DMPlexCreatePointNumbering - Create a global numbering for all points. 8878 8879 Collective 8880 8881 Input Parameter: 8882 . dm - The `DMPLEX` object 8883 8884 Output Parameter: 8885 . globalPointNumbers - Global numbers for all points on this process 8886 8887 Level: developer 8888 8889 Notes: 8890 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8891 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8892 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8893 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8894 8895 The partitioned mesh is 8896 ``` 8897 (2)--0--(3)--1--(4) (1)--0--(2) 8898 ``` 8899 and its global numbering is 8900 ``` 8901 (3)--0--(4)--1--(5)--2--(6) 8902 ``` 8903 Then the global numbering is provided as 8904 ``` 8905 [0] Number of indices in set 5 8906 [0] 0 0 8907 [0] 1 1 8908 [0] 2 3 8909 [0] 3 4 8910 [0] 4 -6 8911 [1] Number of indices in set 3 8912 [1] 0 2 8913 [1] 1 5 8914 [1] 2 6 8915 ``` 8916 8917 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8918 @*/ 8919 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8920 { 8921 IS nums[4]; 8922 PetscInt depths[4], gdepths[4], starts[4]; 8923 PetscInt depth, d, shift = 0; 8924 PetscBool empty = PETSC_FALSE; 8925 8926 PetscFunctionBegin; 8927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8928 PetscCall(DMPlexGetDepth(dm, &depth)); 8929 // For unstratified meshes use dim instead of depth 8930 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8931 // If any stratum is empty, we must mark all empty 8932 for (d = 0; d <= depth; ++d) { 8933 PetscInt end; 8934 8935 depths[d] = depth - d; 8936 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8937 if (!(starts[d] - end)) empty = PETSC_TRUE; 8938 } 8939 if (empty) 8940 for (d = 0; d <= depth; ++d) { 8941 depths[d] = -1; 8942 starts[d] = -1; 8943 } 8944 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8945 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8946 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]); 8947 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8948 for (d = 0; d <= depth; ++d) { 8949 PetscInt pStart, pEnd, gsize; 8950 8951 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8952 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8953 shift += gsize; 8954 } 8955 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8956 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8957 PetscFunctionReturn(PETSC_SUCCESS); 8958 } 8959 8960 /*@ 8961 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8962 8963 Collective 8964 8965 Input Parameter: 8966 . dm - The `DMPLEX` object 8967 8968 Output Parameter: 8969 . globalEdgeNumbers - Global numbers for all edges on this process 8970 8971 Level: developer 8972 8973 Notes: 8974 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). 8975 8976 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8977 @*/ 8978 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8979 { 8980 PetscSF sf; 8981 PetscInt eStart, eEnd; 8982 8983 PetscFunctionBegin; 8984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8985 PetscCall(DMGetPointSF(dm, &sf)); 8986 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8987 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8988 PetscFunctionReturn(PETSC_SUCCESS); 8989 } 8990 8991 /*@ 8992 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8993 8994 Input Parameter: 8995 . dm - The `DMPLEX` object 8996 8997 Output Parameter: 8998 . ranks - The rank field 8999 9000 Options Database Key: 9001 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9002 9003 Level: intermediate 9004 9005 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9006 @*/ 9007 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9008 { 9009 DM rdm; 9010 PetscFE fe; 9011 PetscScalar *r; 9012 PetscMPIInt rank; 9013 DMPolytopeType ct; 9014 PetscInt dim, cStart, cEnd, c; 9015 PetscBool simplex; 9016 9017 PetscFunctionBeginUser; 9018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9019 PetscAssertPointer(ranks, 2); 9020 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9021 PetscCall(DMClone(dm, &rdm)); 9022 PetscCall(DMGetDimension(rdm, &dim)); 9023 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9024 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9025 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9026 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9027 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9028 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9029 PetscCall(PetscFEDestroy(&fe)); 9030 PetscCall(DMCreateDS(rdm)); 9031 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9032 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9033 PetscCall(VecGetArray(*ranks, &r)); 9034 for (c = cStart; c < cEnd; ++c) { 9035 PetscScalar *lr; 9036 9037 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9038 if (lr) *lr = rank; 9039 } 9040 PetscCall(VecRestoreArray(*ranks, &r)); 9041 PetscCall(DMDestroy(&rdm)); 9042 PetscFunctionReturn(PETSC_SUCCESS); 9043 } 9044 9045 /*@ 9046 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9047 9048 Input Parameters: 9049 + dm - The `DMPLEX` 9050 - label - The `DMLabel` 9051 9052 Output Parameter: 9053 . val - The label value field 9054 9055 Options Database Key: 9056 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9057 9058 Level: intermediate 9059 9060 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9061 @*/ 9062 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9063 { 9064 DM rdm, plex; 9065 Vec lval; 9066 PetscSection section; 9067 PetscFE fe; 9068 PetscScalar *v; 9069 PetscInt dim, pStart, pEnd, p, cStart; 9070 DMPolytopeType ct; 9071 char name[PETSC_MAX_PATH_LEN]; 9072 const char *lname, *prefix; 9073 9074 PetscFunctionBeginUser; 9075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9076 PetscAssertPointer(label, 2); 9077 PetscAssertPointer(val, 3); 9078 PetscCall(DMClone(dm, &rdm)); 9079 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9080 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9081 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9082 PetscCall(DMDestroy(&plex)); 9083 PetscCall(DMGetDimension(rdm, &dim)); 9084 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9085 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9086 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9087 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9088 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9089 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9090 PetscCall(PetscFEDestroy(&fe)); 9091 PetscCall(DMCreateDS(rdm)); 9092 PetscCall(DMCreateGlobalVector(rdm, val)); 9093 PetscCall(DMCreateLocalVector(rdm, &lval)); 9094 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9095 PetscCall(DMGetLocalSection(rdm, §ion)); 9096 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9097 PetscCall(VecGetArray(lval, &v)); 9098 for (p = pStart; p < pEnd; ++p) { 9099 PetscInt cval, dof, off; 9100 9101 PetscCall(PetscSectionGetDof(section, p, &dof)); 9102 if (!dof) continue; 9103 PetscCall(DMLabelGetValue(label, p, &cval)); 9104 PetscCall(PetscSectionGetOffset(section, p, &off)); 9105 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9106 } 9107 PetscCall(VecRestoreArray(lval, &v)); 9108 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9109 PetscCall(VecDestroy(&lval)); 9110 PetscCall(DMDestroy(&rdm)); 9111 PetscFunctionReturn(PETSC_SUCCESS); 9112 } 9113 9114 /*@ 9115 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9116 9117 Input Parameter: 9118 . dm - The `DMPLEX` object 9119 9120 Level: developer 9121 9122 Notes: 9123 This is a useful diagnostic when creating meshes programmatically. 9124 9125 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9126 9127 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9128 @*/ 9129 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9130 { 9131 PetscSection coneSection, supportSection; 9132 const PetscInt *cone, *support; 9133 PetscInt coneSize, c, supportSize, s; 9134 PetscInt pStart, pEnd, p, pp, csize, ssize; 9135 PetscBool storagecheck = PETSC_TRUE; 9136 9137 PetscFunctionBegin; 9138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9139 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9140 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9141 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9142 /* Check that point p is found in the support of its cone points, and vice versa */ 9143 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9144 for (p = pStart; p < pEnd; ++p) { 9145 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9146 PetscCall(DMPlexGetCone(dm, p, &cone)); 9147 for (c = 0; c < coneSize; ++c) { 9148 PetscBool dup = PETSC_FALSE; 9149 PetscInt d; 9150 for (d = c - 1; d >= 0; --d) { 9151 if (cone[c] == cone[d]) { 9152 dup = PETSC_TRUE; 9153 break; 9154 } 9155 } 9156 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9157 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9158 for (s = 0; s < supportSize; ++s) { 9159 if (support[s] == p) break; 9160 } 9161 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9162 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9163 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9164 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9165 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9166 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9167 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9168 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]); 9169 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9170 } 9171 } 9172 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9173 if (p != pp) { 9174 storagecheck = PETSC_FALSE; 9175 continue; 9176 } 9177 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9178 PetscCall(DMPlexGetSupport(dm, p, &support)); 9179 for (s = 0; s < supportSize; ++s) { 9180 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9181 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9182 for (c = 0; c < coneSize; ++c) { 9183 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9184 if (cone[c] != pp) { 9185 c = 0; 9186 break; 9187 } 9188 if (cone[c] == p) break; 9189 } 9190 if (c >= coneSize) { 9191 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9192 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9193 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9194 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9195 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9196 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9197 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9198 } 9199 } 9200 } 9201 if (storagecheck) { 9202 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9203 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9204 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9205 } 9206 PetscFunctionReturn(PETSC_SUCCESS); 9207 } 9208 9209 /* 9210 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. 9211 */ 9212 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9213 { 9214 DMPolytopeType cct; 9215 PetscInt ptpoints[4]; 9216 const PetscInt *cone, *ccone, *ptcone; 9217 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9218 9219 PetscFunctionBegin; 9220 *unsplit = 0; 9221 switch (ct) { 9222 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9223 ptpoints[npt++] = c; 9224 break; 9225 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9226 PetscCall(DMPlexGetCone(dm, c, &cone)); 9227 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9228 for (cp = 0; cp < coneSize; ++cp) { 9229 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9230 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9231 } 9232 break; 9233 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9234 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9235 PetscCall(DMPlexGetCone(dm, c, &cone)); 9236 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9237 for (cp = 0; cp < coneSize; ++cp) { 9238 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9239 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9240 for (ccp = 0; ccp < cconeSize; ++ccp) { 9241 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9242 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9243 PetscInt p; 9244 for (p = 0; p < npt; ++p) 9245 if (ptpoints[p] == ccone[ccp]) break; 9246 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9247 } 9248 } 9249 } 9250 break; 9251 default: 9252 break; 9253 } 9254 for (pt = 0; pt < npt; ++pt) { 9255 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9256 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9257 } 9258 PetscFunctionReturn(PETSC_SUCCESS); 9259 } 9260 9261 /*@ 9262 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9263 9264 Input Parameters: 9265 + dm - The `DMPLEX` object 9266 - cellHeight - Normally 0 9267 9268 Level: developer 9269 9270 Notes: 9271 This is a useful diagnostic when creating meshes programmatically. 9272 Currently applicable only to homogeneous simplex or tensor meshes. 9273 9274 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9275 9276 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9277 @*/ 9278 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9279 { 9280 DMPlexInterpolatedFlag interp; 9281 DMPolytopeType ct; 9282 PetscInt vStart, vEnd, cStart, cEnd, c; 9283 9284 PetscFunctionBegin; 9285 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9286 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9287 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9288 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9289 for (c = cStart; c < cEnd; ++c) { 9290 PetscInt *closure = NULL; 9291 PetscInt coneSize, closureSize, cl, Nv = 0; 9292 9293 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9294 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9295 if (interp == DMPLEX_INTERPOLATED_FULL) { 9296 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9297 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)); 9298 } 9299 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9300 for (cl = 0; cl < closureSize * 2; cl += 2) { 9301 const PetscInt p = closure[cl]; 9302 if ((p >= vStart) && (p < vEnd)) ++Nv; 9303 } 9304 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9305 /* Special Case: Tensor faces with identified vertices */ 9306 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9307 PetscInt unsplit; 9308 9309 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9310 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9311 } 9312 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)); 9313 } 9314 PetscFunctionReturn(PETSC_SUCCESS); 9315 } 9316 9317 /*@ 9318 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9319 9320 Collective 9321 9322 Input Parameters: 9323 + dm - The `DMPLEX` object 9324 - cellHeight - Normally 0 9325 9326 Level: developer 9327 9328 Notes: 9329 This is a useful diagnostic when creating meshes programmatically. 9330 This routine is only relevant for meshes that are fully interpolated across all ranks. 9331 It will error out if a partially interpolated mesh is given on some rank. 9332 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9333 9334 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9335 9336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9337 @*/ 9338 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9339 { 9340 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9341 DMPlexInterpolatedFlag interpEnum; 9342 9343 PetscFunctionBegin; 9344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9345 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9346 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9347 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9348 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9349 PetscFunctionReturn(PETSC_SUCCESS); 9350 } 9351 9352 PetscCall(DMGetDimension(dm, &dim)); 9353 PetscCall(DMPlexGetDepth(dm, &depth)); 9354 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9355 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9356 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9357 for (c = cStart; c < cEnd; ++c) { 9358 const PetscInt *cone, *ornt, *faceSizes, *faces; 9359 const DMPolytopeType *faceTypes; 9360 DMPolytopeType ct; 9361 PetscInt numFaces, coneSize, f; 9362 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9363 9364 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9365 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9366 if (unsplit) continue; 9367 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9368 PetscCall(DMPlexGetCone(dm, c, &cone)); 9369 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9370 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9371 for (cl = 0; cl < closureSize * 2; cl += 2) { 9372 const PetscInt p = closure[cl]; 9373 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9374 } 9375 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9376 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); 9377 for (f = 0; f < numFaces; ++f) { 9378 DMPolytopeType fct; 9379 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9380 9381 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9382 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9383 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9384 const PetscInt p = fclosure[cl]; 9385 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9386 } 9387 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]); 9388 for (v = 0; v < fnumCorners; ++v) { 9389 if (fclosure[v] != faces[fOff + v]) { 9390 PetscInt v1; 9391 9392 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9393 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9394 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9395 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9396 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9397 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]); 9398 } 9399 } 9400 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9401 fOff += faceSizes[f]; 9402 } 9403 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9404 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9405 } 9406 } 9407 PetscFunctionReturn(PETSC_SUCCESS); 9408 } 9409 9410 /*@ 9411 DMPlexCheckGeometry - Check the geometry of mesh cells 9412 9413 Input Parameter: 9414 . dm - The `DMPLEX` object 9415 9416 Level: developer 9417 9418 Notes: 9419 This is a useful diagnostic when creating meshes programmatically. 9420 9421 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9422 9423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9424 @*/ 9425 PetscErrorCode DMPlexCheckGeometry(DM dm) 9426 { 9427 Vec coordinates; 9428 PetscReal detJ, J[9], refVol = 1.0; 9429 PetscReal vol; 9430 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9431 9432 PetscFunctionBegin; 9433 PetscCall(DMGetDimension(dm, &dim)); 9434 PetscCall(DMGetCoordinateDim(dm, &dE)); 9435 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9436 PetscCall(DMPlexGetDepth(dm, &depth)); 9437 for (d = 0; d < dim; ++d) refVol *= 2.0; 9438 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9439 /* Make sure local coordinates are created, because that step is collective */ 9440 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9441 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9442 for (c = cStart; c < cEnd; ++c) { 9443 DMPolytopeType ct; 9444 PetscInt unsplit; 9445 PetscBool ignoreZeroVol = PETSC_FALSE; 9446 9447 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9448 switch (ct) { 9449 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9450 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9451 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9452 ignoreZeroVol = PETSC_TRUE; 9453 break; 9454 default: 9455 break; 9456 } 9457 switch (ct) { 9458 case DM_POLYTOPE_TRI_PRISM: 9459 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9460 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9461 case DM_POLYTOPE_PYRAMID: 9462 continue; 9463 default: 9464 break; 9465 } 9466 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9467 if (unsplit) continue; 9468 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9469 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); 9470 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9471 /* This should work with periodicity since DG coordinates should be used */ 9472 if (depth > 1) { 9473 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9474 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); 9475 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9476 } 9477 } 9478 PetscFunctionReturn(PETSC_SUCCESS); 9479 } 9480 9481 /*@ 9482 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9483 9484 Collective 9485 9486 Input Parameters: 9487 + dm - The `DMPLEX` object 9488 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9489 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9490 9491 Level: developer 9492 9493 Notes: 9494 This is mainly intended for debugging/testing purposes. 9495 9496 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9497 9498 Extra roots can come from periodic cuts, where additional points appear on the boundary 9499 9500 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9501 @*/ 9502 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9503 { 9504 PetscInt l, nleaves, nroots, overlap; 9505 const PetscInt *locals; 9506 const PetscSFNode *remotes; 9507 PetscBool distributed; 9508 MPI_Comm comm; 9509 PetscMPIInt rank; 9510 9511 PetscFunctionBegin; 9512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9513 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9514 else pointSF = dm->sf; 9515 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9516 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9517 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9518 { 9519 PetscMPIInt mpiFlag; 9520 9521 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9522 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9523 } 9524 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9525 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9526 if (!distributed) { 9527 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); 9528 PetscFunctionReturn(PETSC_SUCCESS); 9529 } 9530 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); 9531 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9532 9533 /* Check SF graph is compatible with DMPlex chart */ 9534 { 9535 PetscInt pStart, pEnd, maxLeaf; 9536 9537 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9538 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9539 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9540 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9541 } 9542 9543 /* Check Point SF has no local points referenced */ 9544 for (l = 0; l < nleaves; l++) { 9545 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); 9546 } 9547 9548 /* Check there are no cells in interface */ 9549 if (!overlap) { 9550 PetscInt cellHeight, cStart, cEnd; 9551 9552 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9553 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9554 for (l = 0; l < nleaves; ++l) { 9555 const PetscInt point = locals ? locals[l] : l; 9556 9557 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9558 } 9559 } 9560 9561 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9562 { 9563 const PetscInt *rootdegree; 9564 9565 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9566 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9567 for (l = 0; l < nleaves; ++l) { 9568 const PetscInt point = locals ? locals[l] : l; 9569 const PetscInt *cone; 9570 PetscInt coneSize, c, idx; 9571 9572 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9573 PetscCall(DMPlexGetCone(dm, point, &cone)); 9574 for (c = 0; c < coneSize; ++c) { 9575 if (!rootdegree[cone[c]]) { 9576 if (locals) { 9577 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9578 } else { 9579 idx = (cone[c] < nleaves) ? cone[c] : -1; 9580 } 9581 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9582 } 9583 } 9584 } 9585 } 9586 PetscFunctionReturn(PETSC_SUCCESS); 9587 } 9588 9589 /*@ 9590 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9591 9592 Collective 9593 9594 Input Parameter: 9595 . dm - The `DMPLEX` object 9596 9597 Level: developer 9598 9599 Notes: 9600 This is mainly intended for debugging/testing purposes. 9601 9602 Other cell types which are disconnected would be caught by the symmetry and face checks. 9603 9604 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9605 9606 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9607 @*/ 9608 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9609 { 9610 PetscInt pStart, pEnd, vStart, vEnd; 9611 9612 PetscFunctionBegin; 9613 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9614 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9615 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9616 for (PetscInt v = vStart; v < vEnd; ++v) { 9617 PetscInt suppSize; 9618 9619 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9620 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9621 } 9622 PetscFunctionReturn(PETSC_SUCCESS); 9623 } 9624 9625 /*@ 9626 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9627 9628 Input Parameter: 9629 . dm - The `DMPLEX` object 9630 9631 Level: developer 9632 9633 Notes: 9634 This is a useful diagnostic when creating meshes programmatically. 9635 9636 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9637 9638 Currently does not include `DMPlexCheckCellShape()`. 9639 9640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9641 @*/ 9642 PetscErrorCode DMPlexCheck(DM dm) 9643 { 9644 PetscInt cellHeight; 9645 9646 PetscFunctionBegin; 9647 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9648 PetscCall(DMPlexCheckSymmetry(dm)); 9649 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9650 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9651 PetscCall(DMPlexCheckGeometry(dm)); 9652 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9653 PetscCall(DMPlexCheckInterfaceCones(dm)); 9654 PetscCall(DMPlexCheckOrphanVertices(dm)); 9655 PetscFunctionReturn(PETSC_SUCCESS); 9656 } 9657 9658 typedef struct cell_stats { 9659 PetscReal min, max, sum, squaresum; 9660 PetscInt count; 9661 } cell_stats_t; 9662 9663 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9664 { 9665 PetscInt i, N = *len; 9666 9667 for (i = 0; i < N; i++) { 9668 cell_stats_t *A = (cell_stats_t *)a; 9669 cell_stats_t *B = (cell_stats_t *)b; 9670 9671 B->min = PetscMin(A->min, B->min); 9672 B->max = PetscMax(A->max, B->max); 9673 B->sum += A->sum; 9674 B->squaresum += A->squaresum; 9675 B->count += A->count; 9676 } 9677 } 9678 9679 /*@ 9680 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9681 9682 Collective 9683 9684 Input Parameters: 9685 + dm - The `DMPLEX` object 9686 . output - If true, statistics will be displayed on `stdout` 9687 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9688 9689 Level: developer 9690 9691 Notes: 9692 This is mainly intended for debugging/testing purposes. 9693 9694 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9695 9696 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9697 @*/ 9698 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9699 { 9700 DM dmCoarse; 9701 cell_stats_t stats, globalStats; 9702 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9703 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9704 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9705 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9706 PetscMPIInt rank, size; 9707 9708 PetscFunctionBegin; 9709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9710 stats.min = PETSC_MAX_REAL; 9711 stats.max = PETSC_MIN_REAL; 9712 stats.sum = stats.squaresum = 0.; 9713 stats.count = 0; 9714 9715 PetscCallMPI(MPI_Comm_size(comm, &size)); 9716 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9717 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9718 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9719 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9720 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9721 for (c = cStart; c < cEnd; c++) { 9722 PetscInt i; 9723 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9724 9725 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9726 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9727 for (i = 0; i < PetscSqr(cdim); ++i) { 9728 frobJ += J[i] * J[i]; 9729 frobInvJ += invJ[i] * invJ[i]; 9730 } 9731 cond2 = frobJ * frobInvJ; 9732 cond = PetscSqrtReal(cond2); 9733 9734 stats.min = PetscMin(stats.min, cond); 9735 stats.max = PetscMax(stats.max, cond); 9736 stats.sum += cond; 9737 stats.squaresum += cond2; 9738 stats.count++; 9739 if (output && cond > limit) { 9740 PetscSection coordSection; 9741 Vec coordsLocal; 9742 PetscScalar *coords = NULL; 9743 PetscInt Nv, d, clSize, cl, *closure = NULL; 9744 9745 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9746 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9747 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9748 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9749 for (i = 0; i < Nv / cdim; ++i) { 9750 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9751 for (d = 0; d < cdim; ++d) { 9752 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9753 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9754 } 9755 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9756 } 9757 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9758 for (cl = 0; cl < clSize * 2; cl += 2) { 9759 const PetscInt edge = closure[cl]; 9760 9761 if ((edge >= eStart) && (edge < eEnd)) { 9762 PetscReal len; 9763 9764 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9765 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9766 } 9767 } 9768 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9769 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9770 } 9771 } 9772 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9773 9774 if (size > 1) { 9775 PetscMPIInt blockLengths[2] = {4, 1}; 9776 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9777 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9778 MPI_Op statReduce; 9779 9780 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9781 PetscCallMPI(MPI_Type_commit(&statType)); 9782 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9783 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9784 PetscCallMPI(MPI_Op_free(&statReduce)); 9785 PetscCallMPI(MPI_Type_free(&statType)); 9786 } else { 9787 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9788 } 9789 if (rank == 0) { 9790 count = globalStats.count; 9791 min = globalStats.min; 9792 max = globalStats.max; 9793 mean = globalStats.sum / globalStats.count; 9794 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9795 } 9796 9797 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)); 9798 PetscCall(PetscFree2(J, invJ)); 9799 9800 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9801 if (dmCoarse) { 9802 PetscBool isplex; 9803 9804 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9805 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9806 } 9807 PetscFunctionReturn(PETSC_SUCCESS); 9808 } 9809 9810 /*@ 9811 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9812 orthogonal quality below given tolerance. 9813 9814 Collective 9815 9816 Input Parameters: 9817 + dm - The `DMPLEX` object 9818 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9819 - atol - [0, 1] Absolute tolerance for tagging cells. 9820 9821 Output Parameters: 9822 + OrthQual - `Vec` containing orthogonal quality per cell 9823 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9824 9825 Options Database Keys: 9826 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9827 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9828 9829 Level: intermediate 9830 9831 Notes: 9832 Orthogonal quality is given by the following formula\: 9833 9834 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9835 9836 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 9837 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9838 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9839 calculating the cosine of the angle between these vectors. 9840 9841 Orthogonal quality ranges from 1 (best) to 0 (worst). 9842 9843 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9844 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9845 9846 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9847 9848 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9849 @*/ 9850 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9851 { 9852 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9853 PetscInt *idx; 9854 PetscScalar *oqVals; 9855 const PetscScalar *cellGeomArr, *faceGeomArr; 9856 PetscReal *ci, *fi, *Ai; 9857 MPI_Comm comm; 9858 Vec cellgeom, facegeom; 9859 DM dmFace, dmCell; 9860 IS glob; 9861 ISLocalToGlobalMapping ltog; 9862 PetscViewer vwr; 9863 9864 PetscFunctionBegin; 9865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9866 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9867 PetscAssertPointer(OrthQual, 4); 9868 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9869 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9870 PetscCall(DMGetDimension(dm, &nc)); 9871 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9872 { 9873 DMPlexInterpolatedFlag interpFlag; 9874 9875 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9876 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9877 PetscMPIInt rank; 9878 9879 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9880 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9881 } 9882 } 9883 if (OrthQualLabel) { 9884 PetscAssertPointer(OrthQualLabel, 5); 9885 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9886 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9887 } else { 9888 *OrthQualLabel = NULL; 9889 } 9890 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9891 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9892 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9893 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9894 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9895 PetscCall(VecCreate(comm, OrthQual)); 9896 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9897 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9898 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9899 PetscCall(VecSetUp(*OrthQual)); 9900 PetscCall(ISDestroy(&glob)); 9901 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9902 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9903 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9904 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9905 PetscCall(VecGetDM(cellgeom, &dmCell)); 9906 PetscCall(VecGetDM(facegeom, &dmFace)); 9907 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9908 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9909 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9910 PetscInt cellarr[2], *adj = NULL; 9911 PetscScalar *cArr, *fArr; 9912 PetscReal minvalc = 1.0, minvalf = 1.0; 9913 PetscFVCellGeom *cg; 9914 9915 idx[cellIter] = cell - cStart; 9916 cellarr[0] = cell; 9917 /* Make indexing into cellGeom easier */ 9918 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9919 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9920 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9921 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9922 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9923 PetscInt i; 9924 const PetscInt neigh = adj[cellneigh]; 9925 PetscReal normci = 0, normfi = 0, normai = 0; 9926 PetscFVCellGeom *cgneigh; 9927 PetscFVFaceGeom *fg; 9928 9929 /* Don't count ourselves in the neighbor list */ 9930 if (neigh == cell) continue; 9931 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9932 cellarr[1] = neigh; 9933 { 9934 PetscInt numcovpts; 9935 const PetscInt *covpts; 9936 9937 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9938 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9939 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9940 } 9941 9942 /* Compute c_i, f_i and their norms */ 9943 for (i = 0; i < nc; i++) { 9944 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9945 fi[i] = fg->centroid[i] - cg->centroid[i]; 9946 Ai[i] = fg->normal[i]; 9947 normci += PetscPowReal(ci[i], 2); 9948 normfi += PetscPowReal(fi[i], 2); 9949 normai += PetscPowReal(Ai[i], 2); 9950 } 9951 normci = PetscSqrtReal(normci); 9952 normfi = PetscSqrtReal(normfi); 9953 normai = PetscSqrtReal(normai); 9954 9955 /* Normalize and compute for each face-cell-normal pair */ 9956 for (i = 0; i < nc; i++) { 9957 ci[i] = ci[i] / normci; 9958 fi[i] = fi[i] / normfi; 9959 Ai[i] = Ai[i] / normai; 9960 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9961 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9962 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9963 } 9964 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9965 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9966 } 9967 PetscCall(PetscFree(adj)); 9968 PetscCall(PetscFree2(cArr, fArr)); 9969 /* Defer to cell if they're equal */ 9970 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9971 if (OrthQualLabel) { 9972 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9973 } 9974 } 9975 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9976 PetscCall(VecAssemblyBegin(*OrthQual)); 9977 PetscCall(VecAssemblyEnd(*OrthQual)); 9978 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9979 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9980 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9981 if (OrthQualLabel) { 9982 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9983 } 9984 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9985 PetscCall(PetscViewerDestroy(&vwr)); 9986 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9987 PetscFunctionReturn(PETSC_SUCCESS); 9988 } 9989 9990 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9991 * interpolator construction */ 9992 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9993 { 9994 PetscSection section, newSection, gsection; 9995 PetscSF sf; 9996 PetscBool hasConstraints, ghasConstraints; 9997 9998 PetscFunctionBegin; 9999 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10000 PetscAssertPointer(odm, 2); 10001 PetscCall(DMGetLocalSection(dm, §ion)); 10002 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10003 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10004 if (!ghasConstraints) { 10005 PetscCall(PetscObjectReference((PetscObject)dm)); 10006 *odm = dm; 10007 PetscFunctionReturn(PETSC_SUCCESS); 10008 } 10009 PetscCall(DMClone(dm, odm)); 10010 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10011 PetscCall(DMGetLocalSection(*odm, &newSection)); 10012 PetscCall(DMGetPointSF(*odm, &sf)); 10013 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10014 PetscCall(DMSetGlobalSection(*odm, gsection)); 10015 PetscCall(PetscSectionDestroy(&gsection)); 10016 PetscFunctionReturn(PETSC_SUCCESS); 10017 } 10018 10019 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10020 { 10021 DM dmco, dmfo; 10022 Mat interpo; 10023 Vec rscale; 10024 Vec cglobalo, clocal; 10025 Vec fglobal, fglobalo, flocal; 10026 PetscBool regular; 10027 10028 PetscFunctionBegin; 10029 PetscCall(DMGetFullDM(dmc, &dmco)); 10030 PetscCall(DMGetFullDM(dmf, &dmfo)); 10031 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10032 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10033 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10034 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10035 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10036 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10037 PetscCall(VecSet(cglobalo, 0.)); 10038 PetscCall(VecSet(clocal, 0.)); 10039 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10040 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10041 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10042 PetscCall(VecSet(fglobal, 0.)); 10043 PetscCall(VecSet(fglobalo, 0.)); 10044 PetscCall(VecSet(flocal, 0.)); 10045 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10046 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10047 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10048 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10049 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10050 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10051 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10052 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10053 *shift = fglobal; 10054 PetscCall(VecDestroy(&flocal)); 10055 PetscCall(VecDestroy(&fglobalo)); 10056 PetscCall(VecDestroy(&clocal)); 10057 PetscCall(VecDestroy(&cglobalo)); 10058 PetscCall(VecDestroy(&rscale)); 10059 PetscCall(MatDestroy(&interpo)); 10060 PetscCall(DMDestroy(&dmfo)); 10061 PetscCall(DMDestroy(&dmco)); 10062 PetscFunctionReturn(PETSC_SUCCESS); 10063 } 10064 10065 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10066 { 10067 PetscObject shifto; 10068 Vec shift; 10069 10070 PetscFunctionBegin; 10071 if (!interp) { 10072 Vec rscale; 10073 10074 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10075 PetscCall(VecDestroy(&rscale)); 10076 } else { 10077 PetscCall(PetscObjectReference((PetscObject)interp)); 10078 } 10079 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10080 if (!shifto) { 10081 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10082 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10083 shifto = (PetscObject)shift; 10084 PetscCall(VecDestroy(&shift)); 10085 } 10086 shift = (Vec)shifto; 10087 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10088 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10089 PetscCall(MatDestroy(&interp)); 10090 PetscFunctionReturn(PETSC_SUCCESS); 10091 } 10092 10093 /* Pointwise interpolation 10094 Just code FEM for now 10095 u^f = I u^c 10096 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10097 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10098 I_{ij} = psi^f_i phi^c_j 10099 */ 10100 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10101 { 10102 PetscSection gsc, gsf; 10103 PetscInt m, n; 10104 void *ctx; 10105 DM cdm; 10106 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10107 10108 PetscFunctionBegin; 10109 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10110 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10111 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10112 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10113 10114 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10115 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10116 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10117 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10118 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10119 10120 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10121 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10122 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10123 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10124 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10125 if (scaling) { 10126 /* Use naive scaling */ 10127 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10128 } 10129 PetscFunctionReturn(PETSC_SUCCESS); 10130 } 10131 10132 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10133 { 10134 VecScatter ctx; 10135 10136 PetscFunctionBegin; 10137 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10138 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10139 PetscCall(VecScatterDestroy(&ctx)); 10140 PetscFunctionReturn(PETSC_SUCCESS); 10141 } 10142 10143 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[]) 10144 { 10145 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10146 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10147 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10148 } 10149 10150 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10151 { 10152 DM dmc; 10153 PetscDS ds; 10154 Vec ones, locmass; 10155 IS cellIS; 10156 PetscFormKey key; 10157 PetscInt depth; 10158 10159 PetscFunctionBegin; 10160 PetscCall(DMClone(dm, &dmc)); 10161 PetscCall(DMCopyDisc(dm, dmc)); 10162 PetscCall(DMGetDS(dmc, &ds)); 10163 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10164 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10165 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10166 else PetscCall(DMGetLocalVector(dm, &locmass)); 10167 PetscCall(DMGetLocalVector(dm, &ones)); 10168 PetscCall(DMPlexGetDepth(dm, &depth)); 10169 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10170 PetscCall(VecSet(locmass, 0.0)); 10171 PetscCall(VecSet(ones, 1.0)); 10172 key.label = NULL; 10173 key.value = 0; 10174 key.field = 0; 10175 key.part = 0; 10176 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10177 PetscCall(ISDestroy(&cellIS)); 10178 if (mass) { 10179 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10180 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10181 } 10182 PetscCall(DMRestoreLocalVector(dm, &ones)); 10183 if (lmass) *lmass = locmass; 10184 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10185 PetscCall(DMDestroy(&dmc)); 10186 PetscFunctionReturn(PETSC_SUCCESS); 10187 } 10188 10189 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10190 { 10191 PetscSection gsc, gsf; 10192 PetscInt m, n; 10193 void *ctx; 10194 DM cdm; 10195 PetscBool regular; 10196 10197 PetscFunctionBegin; 10198 if (dmFine == dmCoarse) { 10199 DM dmc; 10200 PetscDS ds; 10201 PetscWeakForm wf; 10202 Vec u; 10203 IS cellIS; 10204 PetscFormKey key; 10205 PetscInt depth; 10206 10207 PetscCall(DMClone(dmFine, &dmc)); 10208 PetscCall(DMCopyDisc(dmFine, dmc)); 10209 PetscCall(DMGetDS(dmc, &ds)); 10210 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10211 PetscCall(PetscWeakFormClear(wf)); 10212 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10213 PetscCall(DMCreateMatrix(dmc, mass)); 10214 PetscCall(DMGetLocalVector(dmc, &u)); 10215 PetscCall(DMPlexGetDepth(dmc, &depth)); 10216 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10217 PetscCall(MatZeroEntries(*mass)); 10218 key.label = NULL; 10219 key.value = 0; 10220 key.field = 0; 10221 key.part = 0; 10222 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10223 PetscCall(ISDestroy(&cellIS)); 10224 PetscCall(DMRestoreLocalVector(dmc, &u)); 10225 PetscCall(DMDestroy(&dmc)); 10226 } else { 10227 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10228 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10229 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10230 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10231 10232 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10233 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10234 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10235 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10236 10237 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10238 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10239 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10240 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10241 } 10242 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10243 PetscFunctionReturn(PETSC_SUCCESS); 10244 } 10245 10246 /*@ 10247 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10248 10249 Input Parameter: 10250 . dm - The `DMPLEX` object 10251 10252 Output Parameter: 10253 . regular - The flag 10254 10255 Level: intermediate 10256 10257 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10258 @*/ 10259 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10260 { 10261 PetscFunctionBegin; 10262 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10263 PetscAssertPointer(regular, 2); 10264 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10265 PetscFunctionReturn(PETSC_SUCCESS); 10266 } 10267 10268 /*@ 10269 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10270 10271 Input Parameters: 10272 + dm - The `DMPLEX` object 10273 - regular - The flag 10274 10275 Level: intermediate 10276 10277 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10278 @*/ 10279 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10280 { 10281 PetscFunctionBegin; 10282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10283 ((DM_Plex *)dm->data)->regularRefinement = regular; 10284 PetscFunctionReturn(PETSC_SUCCESS); 10285 } 10286 10287 /*@ 10288 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10289 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10290 10291 Not Collective 10292 10293 Input Parameter: 10294 . dm - The `DMPLEX` object 10295 10296 Output Parameters: 10297 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10298 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10299 10300 Level: intermediate 10301 10302 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10303 @*/ 10304 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10305 { 10306 DM_Plex *plex = (DM_Plex *)dm->data; 10307 10308 PetscFunctionBegin; 10309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10310 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10311 if (anchorSection) *anchorSection = plex->anchorSection; 10312 if (anchorIS) *anchorIS = plex->anchorIS; 10313 PetscFunctionReturn(PETSC_SUCCESS); 10314 } 10315 10316 /*@ 10317 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10318 10319 Collective 10320 10321 Input Parameters: 10322 + dm - The `DMPLEX` object 10323 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10324 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10325 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10326 10327 Level: intermediate 10328 10329 Notes: 10330 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10331 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10332 combination of other points' degrees of freedom. 10333 10334 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10335 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10336 10337 The reference counts of `anchorSection` and `anchorIS` are incremented. 10338 10339 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10340 @*/ 10341 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10342 { 10343 DM_Plex *plex = (DM_Plex *)dm->data; 10344 PetscMPIInt result; 10345 10346 PetscFunctionBegin; 10347 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10348 if (anchorSection) { 10349 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10350 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10351 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10352 } 10353 if (anchorIS) { 10354 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10355 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10356 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10357 } 10358 10359 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10360 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10361 plex->anchorSection = anchorSection; 10362 10363 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10364 PetscCall(ISDestroy(&plex->anchorIS)); 10365 plex->anchorIS = anchorIS; 10366 10367 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10368 PetscInt size, a, pStart, pEnd; 10369 const PetscInt *anchors; 10370 10371 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10372 PetscCall(ISGetLocalSize(anchorIS, &size)); 10373 PetscCall(ISGetIndices(anchorIS, &anchors)); 10374 for (a = 0; a < size; a++) { 10375 PetscInt p; 10376 10377 p = anchors[a]; 10378 if (p >= pStart && p < pEnd) { 10379 PetscInt dof; 10380 10381 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10382 if (dof) { 10383 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10384 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10385 } 10386 } 10387 } 10388 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10389 } 10390 /* reset the generic constraints */ 10391 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10392 PetscFunctionReturn(PETSC_SUCCESS); 10393 } 10394 10395 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10396 { 10397 PetscSection anchorSection; 10398 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10399 10400 PetscFunctionBegin; 10401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10402 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10403 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10404 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10405 if (numFields) { 10406 PetscInt f; 10407 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10408 10409 for (f = 0; f < numFields; f++) { 10410 PetscInt numComp; 10411 10412 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10413 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10414 } 10415 } 10416 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10417 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10418 pStart = PetscMax(pStart, sStart); 10419 pEnd = PetscMin(pEnd, sEnd); 10420 pEnd = PetscMax(pStart, pEnd); 10421 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10422 for (p = pStart; p < pEnd; p++) { 10423 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10424 if (dof) { 10425 PetscCall(PetscSectionGetDof(section, p, &dof)); 10426 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10427 for (f = 0; f < numFields; f++) { 10428 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10429 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10430 } 10431 } 10432 } 10433 PetscCall(PetscSectionSetUp(*cSec)); 10434 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10435 PetscFunctionReturn(PETSC_SUCCESS); 10436 } 10437 10438 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10439 { 10440 PetscSection aSec; 10441 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10442 const PetscInt *anchors; 10443 PetscInt numFields, f; 10444 IS aIS; 10445 MatType mtype; 10446 PetscBool iscuda, iskokkos; 10447 10448 PetscFunctionBegin; 10449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10450 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10451 PetscCall(PetscSectionGetStorageSize(section, &n)); 10452 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10453 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10454 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10455 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10456 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10457 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10458 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10459 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10460 else mtype = MATSEQAIJ; 10461 PetscCall(MatSetType(*cMat, mtype)); 10462 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10463 PetscCall(ISGetIndices(aIS, &anchors)); 10464 /* cSec will be a subset of aSec and section */ 10465 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10466 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10467 PetscCall(PetscMalloc1(m + 1, &i)); 10468 i[0] = 0; 10469 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10470 for (p = pStart; p < pEnd; p++) { 10471 PetscInt rDof, rOff, r; 10472 10473 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10474 if (!rDof) continue; 10475 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10476 if (numFields) { 10477 for (f = 0; f < numFields; f++) { 10478 annz = 0; 10479 for (r = 0; r < rDof; r++) { 10480 a = anchors[rOff + r]; 10481 if (a < sStart || a >= sEnd) continue; 10482 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10483 annz += aDof; 10484 } 10485 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10486 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10487 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10488 } 10489 } else { 10490 annz = 0; 10491 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10492 for (q = 0; q < dof; q++) { 10493 a = anchors[rOff + q]; 10494 if (a < sStart || a >= sEnd) continue; 10495 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10496 annz += aDof; 10497 } 10498 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10499 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10500 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10501 } 10502 } 10503 nnz = i[m]; 10504 PetscCall(PetscMalloc1(nnz, &j)); 10505 offset = 0; 10506 for (p = pStart; p < pEnd; p++) { 10507 if (numFields) { 10508 for (f = 0; f < numFields; f++) { 10509 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10510 for (q = 0; q < dof; q++) { 10511 PetscInt rDof, rOff, r; 10512 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10513 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10514 for (r = 0; r < rDof; r++) { 10515 PetscInt s; 10516 10517 a = anchors[rOff + r]; 10518 if (a < sStart || a >= sEnd) continue; 10519 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10520 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10521 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10522 } 10523 } 10524 } 10525 } else { 10526 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10527 for (q = 0; q < dof; q++) { 10528 PetscInt rDof, rOff, r; 10529 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10530 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10531 for (r = 0; r < rDof; r++) { 10532 PetscInt s; 10533 10534 a = anchors[rOff + r]; 10535 if (a < sStart || a >= sEnd) continue; 10536 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10537 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10538 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10539 } 10540 } 10541 } 10542 } 10543 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10544 PetscCall(PetscFree(i)); 10545 PetscCall(PetscFree(j)); 10546 PetscCall(ISRestoreIndices(aIS, &anchors)); 10547 PetscFunctionReturn(PETSC_SUCCESS); 10548 } 10549 10550 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10551 { 10552 DM_Plex *plex = (DM_Plex *)dm->data; 10553 PetscSection anchorSection, section, cSec; 10554 Mat cMat; 10555 10556 PetscFunctionBegin; 10557 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10558 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10559 if (anchorSection) { 10560 PetscInt Nf; 10561 10562 PetscCall(DMGetLocalSection(dm, §ion)); 10563 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10564 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10565 PetscCall(DMGetNumFields(dm, &Nf)); 10566 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10567 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10568 PetscCall(PetscSectionDestroy(&cSec)); 10569 PetscCall(MatDestroy(&cMat)); 10570 } 10571 PetscFunctionReturn(PETSC_SUCCESS); 10572 } 10573 10574 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10575 { 10576 IS subis; 10577 PetscSection section, subsection; 10578 10579 PetscFunctionBegin; 10580 PetscCall(DMGetLocalSection(dm, §ion)); 10581 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10582 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10583 /* Create subdomain */ 10584 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10585 /* Create submodel */ 10586 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10587 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10588 PetscCall(DMSetLocalSection(*subdm, subsection)); 10589 PetscCall(PetscSectionDestroy(&subsection)); 10590 PetscCall(DMCopyDisc(dm, *subdm)); 10591 /* Create map from submodel to global model */ 10592 if (is) { 10593 PetscSection sectionGlobal, subsectionGlobal; 10594 IS spIS; 10595 const PetscInt *spmap; 10596 PetscInt *subIndices; 10597 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10598 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10599 10600 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10601 PetscCall(ISGetIndices(spIS, &spmap)); 10602 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10603 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10604 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10605 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10606 for (p = pStart; p < pEnd; ++p) { 10607 PetscInt gdof, pSubSize = 0; 10608 10609 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10610 if (gdof > 0) { 10611 for (f = 0; f < Nf; ++f) { 10612 PetscInt fdof, fcdof; 10613 10614 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10615 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10616 pSubSize += fdof - fcdof; 10617 } 10618 subSize += pSubSize; 10619 if (pSubSize) { 10620 if (bs < 0) { 10621 bs = pSubSize; 10622 } else if (bs != pSubSize) { 10623 /* Layout does not admit a pointwise block size */ 10624 bs = 1; 10625 } 10626 } 10627 } 10628 } 10629 /* Must have same blocksize on all procs (some might have no points) */ 10630 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10631 bsLocal[1] = bs; 10632 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10633 if (bsMinMax[0] != bsMinMax[1]) { 10634 bs = 1; 10635 } else { 10636 bs = bsMinMax[0]; 10637 } 10638 PetscCall(PetscMalloc1(subSize, &subIndices)); 10639 for (p = pStart; p < pEnd; ++p) { 10640 PetscInt gdof, goff; 10641 10642 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10643 if (gdof > 0) { 10644 const PetscInt point = spmap[p]; 10645 10646 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10647 for (f = 0; f < Nf; ++f) { 10648 PetscInt fdof, fcdof, fc, f2, poff = 0; 10649 10650 /* Can get rid of this loop by storing field information in the global section */ 10651 for (f2 = 0; f2 < f; ++f2) { 10652 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10653 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10654 poff += fdof - fcdof; 10655 } 10656 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10657 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10658 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10659 } 10660 } 10661 } 10662 PetscCall(ISRestoreIndices(spIS, &spmap)); 10663 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10664 if (bs > 1) { 10665 /* We need to check that the block size does not come from non-contiguous fields */ 10666 PetscInt i, j, set = 1; 10667 for (i = 0; i < subSize; i += bs) { 10668 for (j = 0; j < bs; ++j) { 10669 if (subIndices[i + j] != subIndices[i] + j) { 10670 set = 0; 10671 break; 10672 } 10673 } 10674 } 10675 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10676 } 10677 /* Attach nullspace */ 10678 for (f = 0; f < Nf; ++f) { 10679 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10680 if ((*subdm)->nullspaceConstructors[f]) break; 10681 } 10682 if (f < Nf) { 10683 MatNullSpace nullSpace; 10684 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10685 10686 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10687 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10688 } 10689 } 10690 PetscFunctionReturn(PETSC_SUCCESS); 10691 } 10692 10693 /*@ 10694 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10695 10696 Input Parameters: 10697 + dm - The `DM` 10698 - dummy - unused argument 10699 10700 Options Database Key: 10701 . -dm_plex_monitor_throughput - Activate the monitor 10702 10703 Level: developer 10704 10705 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10706 @*/ 10707 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10708 { 10709 PetscLogHandler default_handler; 10710 10711 PetscFunctionBegin; 10712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10713 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10714 if (default_handler) { 10715 PetscLogEvent event; 10716 PetscEventPerfInfo eventInfo; 10717 PetscReal cellRate, flopRate; 10718 PetscInt cStart, cEnd, Nf, N; 10719 const char *name; 10720 10721 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10722 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10723 PetscCall(DMGetNumFields(dm, &Nf)); 10724 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10725 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10726 N = (cEnd - cStart) * Nf * eventInfo.count; 10727 flopRate = eventInfo.flops / eventInfo.time; 10728 cellRate = N / eventInfo.time; 10729 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))); 10730 } else { 10731 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."); 10732 } 10733 PetscFunctionReturn(PETSC_SUCCESS); 10734 } 10735