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 12 /* Logging support */ 13 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; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 162 } 163 164 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 165 *types = 0; 166 167 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 168 if (globalvcdof[c]) ++(*types); 169 } 170 171 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 172 t = 0; 173 if (globalvcdof[DM_NUM_POLYTOPES]) { 174 sStart[t] = vStart; 175 sEnd[t] = vEnd; 176 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 177 ++t; 178 } 179 180 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 181 if (globalvcdof[c]) { 182 const DMPolytopeType ict = (DMPolytopeType)c; 183 184 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 185 sStart[t] = cStart; 186 sEnd[t] = cEnd; 187 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 188 ++t; 189 } 190 } 191 192 if (!(*types)) { 193 if (field >= 0) { 194 const char *fieldname; 195 196 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 198 } else { 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 200 } 201 } 202 203 *ssStart = sStart; 204 *ssEnd = sEnd; 205 *sft = ft; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 210 { 211 PetscFunctionBegin; 212 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 213 PetscFunctionReturn(PETSC_SUCCESS); 214 } 215 216 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 217 { 218 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 219 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 220 221 PetscFunctionBegin; 222 *ft = PETSC_VTK_INVALID; 223 PetscCall(DMGetCoordinateDim(dm, &cdim)); 224 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 225 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 226 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 227 if (field >= 0) { 228 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 229 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 230 } else { 231 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 232 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 233 } 234 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 235 if (globalvcdof[0]) { 236 *sStart = vStart; 237 *sEnd = vEnd; 238 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 239 else *ft = PETSC_VTK_POINT_FIELD; 240 } else if (globalvcdof[1]) { 241 *sStart = cStart; 242 *sEnd = cEnd; 243 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 244 else *ft = PETSC_VTK_CELL_FIELD; 245 } else { 246 if (field >= 0) { 247 const char *fieldname; 248 249 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 251 } else { 252 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 253 } 254 } 255 PetscFunctionReturn(PETSC_SUCCESS); 256 } 257 258 /*@ 259 DMPlexVecView1D - Plot many 1D solutions on the same line graph 260 261 Collective 262 263 Input Parameters: 264 + dm - The `DMPLEX` object 265 . n - The number of vectors 266 . u - The array of local vectors 267 - viewer - The `PetscViewer` 268 269 Level: advanced 270 271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 272 @*/ 273 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 274 { 275 PetscDS ds; 276 PetscDraw draw = NULL; 277 PetscDrawLG lg; 278 Vec coordinates; 279 const PetscScalar *coords, **sol; 280 PetscReal *vals; 281 PetscInt *Nc; 282 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 283 char **names; 284 285 PetscFunctionBegin; 286 PetscCall(DMGetDS(dm, &ds)); 287 PetscCall(PetscDSGetNumFields(ds, &Nf)); 288 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 289 PetscCall(PetscDSGetComponents(ds, &Nc)); 290 291 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 292 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 293 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 294 295 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 296 for (i = 0, l = 0; i < n; ++i) { 297 const char *vname; 298 299 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 300 for (f = 0; f < Nf; ++f) { 301 PetscObject disc; 302 const char *fname; 303 char tmpname[PETSC_MAX_PATH_LEN]; 304 305 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 306 /* TODO Create names for components */ 307 for (c = 0; c < Nc[f]; ++c, ++l) { 308 PetscCall(PetscObjectGetName(disc, &fname)); 309 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 312 PetscCall(PetscStrallocpy(tmpname, &names[l])); 313 } 314 } 315 } 316 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 317 /* Just add P_1 support for now */ 318 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 319 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 320 PetscCall(VecGetArrayRead(coordinates, &coords)); 321 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 322 for (v = vStart; v < vEnd; ++v) { 323 PetscScalar *x, *svals; 324 325 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 326 for (i = 0; i < n; ++i) { 327 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 328 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 329 } 330 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 331 } 332 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 333 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 334 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 335 PetscCall(PetscFree3(sol, names, vals)); 336 337 PetscCall(PetscDrawLGDraw(lg)); 338 PetscCall(PetscDrawLGDestroy(&lg)); 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 343 { 344 DM dm; 345 346 PetscFunctionBegin; 347 PetscCall(VecGetDM(u, &dm)); 348 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 353 { 354 DM dm; 355 PetscSection s; 356 PetscDraw draw, popup; 357 DM cdm; 358 PetscSection coordSection; 359 Vec coordinates; 360 const PetscScalar *array; 361 PetscReal lbound[3], ubound[3]; 362 PetscReal vbound[2], time; 363 PetscBool flg; 364 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 365 const char *name; 366 char title[PETSC_MAX_PATH_LEN]; 367 368 PetscFunctionBegin; 369 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 370 PetscCall(VecGetDM(v, &dm)); 371 PetscCall(DMGetCoordinateDim(dm, &dim)); 372 PetscCall(DMGetLocalSection(dm, &s)); 373 PetscCall(PetscSectionGetNumFields(s, &Nf)); 374 PetscCall(DMGetCoarsenLevel(dm, &level)); 375 PetscCall(DMGetCoordinateDM(dm, &cdm)); 376 PetscCall(DMGetLocalSection(cdm, &coordSection)); 377 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 378 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 379 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 380 381 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 382 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 383 384 PetscCall(VecGetLocalSize(coordinates, &N)); 385 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 386 PetscCall(PetscDrawClear(draw)); 387 388 /* Could implement something like DMDASelectFields() */ 389 for (f = 0; f < Nf; ++f) { 390 DM fdm = dm; 391 Vec fv = v; 392 IS fis; 393 char prefix[PETSC_MAX_PATH_LEN]; 394 const char *fname; 395 396 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 397 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 398 399 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 400 else prefix[0] = '\0'; 401 if (Nf > 1) { 402 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 403 PetscCall(VecGetSubVector(v, fis, &fv)); 404 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 405 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 406 } 407 for (comp = 0; comp < Nc; ++comp, ++w) { 408 PetscInt nmax = 2; 409 410 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 411 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 412 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 413 PetscCall(PetscDrawSetTitle(draw, title)); 414 415 /* TODO Get max and min only for this component */ 416 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 417 if (!flg) { 418 PetscCall(VecMin(fv, NULL, &vbound[0])); 419 PetscCall(VecMax(fv, NULL, &vbound[1])); 420 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 421 } 422 423 PetscCall(PetscDrawGetPopup(draw, &popup)); 424 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 425 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 426 PetscCall(VecGetArrayRead(fv, &array)); 427 for (c = cStart; c < cEnd; ++c) { 428 PetscScalar *coords = NULL, *a = NULL; 429 const PetscScalar *coords_arr; 430 PetscBool isDG; 431 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 432 433 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 434 if (a) { 435 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 436 color[1] = color[2] = color[3] = color[0]; 437 } else { 438 PetscScalar *vals = NULL; 439 PetscInt numVals, va; 440 441 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 442 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); 443 switch (numVals / Nc) { 444 case 3: /* P1 Triangle */ 445 case 4: /* P1 Quadrangle */ 446 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 447 break; 448 case 6: /* P2 Triangle */ 449 case 8: /* P2 Quadrangle */ 450 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 451 break; 452 default: 453 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 454 } 455 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 456 } 457 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 458 switch (numCoords) { 459 case 6: 460 case 12: /* Localized triangle */ 461 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])); 462 break; 463 case 8: 464 case 16: /* Localized quadrilateral */ 465 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])); 466 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])); 467 break; 468 default: 469 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 470 } 471 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 } 473 PetscCall(VecRestoreArrayRead(fv, &array)); 474 PetscCall(PetscDrawFlush(draw)); 475 PetscCall(PetscDrawPause(draw)); 476 PetscCall(PetscDrawSave(draw)); 477 } 478 if (Nf > 1) { 479 PetscCall(VecRestoreSubVector(v, fis, &fv)); 480 PetscCall(ISDestroy(&fis)); 481 PetscCall(DMDestroy(&fdm)); 482 } 483 } 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 488 { 489 DM dm; 490 PetscDraw draw; 491 PetscInt dim; 492 PetscBool isnull; 493 494 PetscFunctionBegin; 495 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 496 PetscCall(PetscDrawIsNull(draw, &isnull)); 497 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 498 499 PetscCall(VecGetDM(v, &dm)); 500 PetscCall(DMGetCoordinateDim(dm, &dim)); 501 switch (dim) { 502 case 1: 503 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 504 break; 505 case 2: 506 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 507 break; 508 default: 509 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 510 } 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 515 { 516 DM dm; 517 Vec locv; 518 const char *name; 519 PetscSection section; 520 PetscInt pStart, pEnd; 521 PetscInt numFields; 522 PetscViewerVTKFieldType ft; 523 524 PetscFunctionBegin; 525 PetscCall(VecGetDM(v, &dm)); 526 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 527 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 528 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 529 PetscCall(VecCopy(v, locv)); 530 PetscCall(DMGetLocalSection(dm, §ion)); 531 PetscCall(PetscSectionGetNumFields(section, &numFields)); 532 if (!numFields) { 533 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 534 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 535 } else { 536 PetscInt f; 537 538 for (f = 0; f < numFields; f++) { 539 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 540 if (ft == PETSC_VTK_INVALID) continue; 541 PetscCall(PetscObjectReference((PetscObject)locv)); 542 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 543 } 544 PetscCall(VecDestroy(&locv)); 545 } 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 550 { 551 DM dm; 552 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 553 554 PetscFunctionBegin; 555 PetscCall(VecGetDM(v, &dm)); 556 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 562 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 563 PetscInt i, numFields; 564 PetscObject fe; 565 PetscBool fem = PETSC_FALSE; 566 Vec locv = v; 567 const char *name; 568 PetscInt step; 569 PetscReal time; 570 571 PetscCall(DMGetNumFields(dm, &numFields)); 572 for (i = 0; i < numFields; i++) { 573 PetscCall(DMGetField(dm, i, NULL, &fe)); 574 if (fe->classid == PETSCFE_CLASSID) { 575 fem = PETSC_TRUE; 576 break; 577 } 578 } 579 if (fem) { 580 PetscObject isZero; 581 582 PetscCall(DMGetLocalVector(dm, &locv)); 583 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 584 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 585 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 586 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 587 PetscCall(VecCopy(v, locv)); 588 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 589 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 590 } 591 if (isvtk) { 592 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 593 } else if (ishdf5) { 594 #if defined(PETSC_HAVE_HDF5) 595 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 596 #else 597 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 598 #endif 599 } else if (isdraw) { 600 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 601 } else if (isglvis) { 602 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 603 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 604 PetscCall(VecView_GLVis(locv, viewer)); 605 } else if (iscgns) { 606 #if defined(PETSC_HAVE_CGNS) 607 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 608 #else 609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 610 #endif 611 } 612 if (fem) { 613 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 614 PetscCall(DMRestoreLocalVector(dm, &locv)); 615 } 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (isvtk || isdraw || isglvis || iscgns) { 641 Vec locv; 642 PetscObject isZero; 643 const char *name; 644 645 PetscCall(DMGetLocalVector(dm, &locv)); 646 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 647 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 648 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 649 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 650 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 652 PetscCall(VecView_Plex_Local(locv, viewer)); 653 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 654 PetscCall(DMRestoreLocalVector(dm, &locv)); 655 } else if (ishdf5) { 656 #if defined(PETSC_HAVE_HDF5) 657 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 658 #else 659 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 660 #endif 661 } else if (isexodusii) { 662 #if defined(PETSC_HAVE_EXODUSII) 663 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 664 #else 665 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 666 #endif 667 } else { 668 PetscBool isseq; 669 670 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 671 if (isseq) PetscCall(VecView_Seq(v, viewer)); 672 else PetscCall(VecView_MPI(v, viewer)); 673 } 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 678 { 679 DM dm; 680 MPI_Comm comm; 681 PetscViewerFormat format; 682 Vec v; 683 PetscBool isvtk, ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 688 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 689 PetscCall(PetscViewerGetFormat(viewer, &format)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 694 /* this need a better fix */ 695 if (dm->useNatural) { 696 if (dm->sfNatural) { 697 const char *vecname; 698 PetscInt n, nroots; 699 700 PetscCall(VecGetLocalSize(originalv, &n)); 701 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 702 if (n == nroots) { 703 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 704 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 705 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 706 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 707 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 710 } else v = originalv; 711 } else v = originalv; 712 713 if (ishdf5) { 714 #if defined(PETSC_HAVE_HDF5) 715 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 716 #else 717 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 718 #endif 719 } else if (isvtk) { 720 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 721 } else { 722 PetscBool isseq; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 725 if (isseq) PetscCall(VecView_Seq(v, viewer)); 726 else PetscCall(VecView_MPI(v, viewer)); 727 } 728 if (v != originalv) PetscCall(VecDestroy(&v)); 729 PetscFunctionReturn(PETSC_SUCCESS); 730 } 731 732 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 733 { 734 DM dm; 735 PetscBool ishdf5; 736 737 PetscFunctionBegin; 738 PetscCall(VecGetDM(v, &dm)); 739 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 740 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 741 if (ishdf5) { 742 DM dmBC; 743 Vec gv; 744 const char *name; 745 746 PetscCall(DMGetOutputDM(dm, &dmBC)); 747 PetscCall(DMGetGlobalVector(dmBC, &gv)); 748 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 749 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 750 PetscCall(VecLoad_Default(gv, viewer)); 751 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 754 } else PetscCall(VecLoad_Default(v, viewer)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 759 { 760 DM dm; 761 PetscBool ishdf5, isexodusii; 762 763 PetscFunctionBegin; 764 PetscCall(VecGetDM(v, &dm)); 765 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 768 if (ishdf5) { 769 #if defined(PETSC_HAVE_HDF5) 770 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 771 #else 772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 773 #endif 774 } else if (isexodusii) { 775 #if defined(PETSC_HAVE_EXODUSII) 776 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 777 #else 778 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 779 #endif 780 } else PetscCall(VecLoad_Default(v, viewer)); 781 PetscFunctionReturn(PETSC_SUCCESS); 782 } 783 784 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 785 { 786 DM dm; 787 PetscViewerFormat format; 788 PetscBool ishdf5; 789 790 PetscFunctionBegin; 791 PetscCall(VecGetDM(originalv, &dm)); 792 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 793 PetscCall(PetscViewerGetFormat(viewer, &format)); 794 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 795 if (format == PETSC_VIEWER_NATIVE) { 796 if (dm->useNatural) { 797 if (dm->sfNatural) { 798 if (ishdf5) { 799 #if defined(PETSC_HAVE_HDF5) 800 Vec v; 801 const char *vecname; 802 803 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 804 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 805 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 806 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 807 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 808 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 809 PetscCall(VecDestroy(&v)); 810 #else 811 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 812 #endif 813 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 814 } 815 } else PetscCall(VecLoad_Default(originalv, viewer)); 816 } 817 PetscFunctionReturn(PETSC_SUCCESS); 818 } 819 820 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 821 { 822 PetscSection coordSection; 823 Vec coordinates; 824 DMLabel depthLabel, celltypeLabel; 825 const char *name[4]; 826 const PetscScalar *a; 827 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetDimension(dm, &dim)); 831 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 833 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 834 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 835 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 836 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 837 PetscCall(VecGetArrayRead(coordinates, &a)); 838 name[0] = "vertex"; 839 name[1] = "edge"; 840 name[dim - 1] = "face"; 841 name[dim] = "cell"; 842 for (c = cStart; c < cEnd; ++c) { 843 PetscInt *closure = NULL; 844 PetscInt closureSize, cl, ct; 845 846 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 847 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 848 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 849 PetscCall(PetscViewerASCIIPushTab(viewer)); 850 for (cl = 0; cl < closureSize * 2; cl += 2) { 851 PetscInt point = closure[cl], depth, dof, off, d, p; 852 853 if ((point < pStart) || (point >= pEnd)) continue; 854 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 855 if (!dof) continue; 856 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 857 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 859 for (p = 0; p < dof / dim; ++p) { 860 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 861 for (d = 0; d < dim; ++d) { 862 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 863 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPopTab(viewer)); 871 } 872 PetscCall(VecRestoreArrayRead(coordinates, &a)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 typedef enum { 877 CS_CARTESIAN, 878 CS_POLAR, 879 CS_CYLINDRICAL, 880 CS_SPHERICAL 881 } CoordSystem; 882 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 883 884 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 885 { 886 PetscInt i; 887 888 PetscFunctionBegin; 889 if (dim > 3) { 890 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 891 } else { 892 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 893 894 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 895 switch (cs) { 896 case CS_CARTESIAN: 897 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 898 break; 899 case CS_POLAR: 900 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 901 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 902 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 903 break; 904 case CS_CYLINDRICAL: 905 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 906 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 907 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 908 trcoords[2] = coords[2]; 909 break; 910 case CS_SPHERICAL: 911 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 912 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 913 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 914 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 915 break; 916 } 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 923 { 924 DM_Plex *mesh = (DM_Plex *)dm->data; 925 DM cdm, cdmCell; 926 PetscSection coordSection, coordSectionCell; 927 Vec coordinates, coordinatesCell; 928 PetscViewerFormat format; 929 930 PetscFunctionBegin; 931 PetscCall(PetscViewerGetFormat(viewer, &format)); 932 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 933 const char *name; 934 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 935 PetscInt pStart, pEnd, p, numLabels, l; 936 PetscMPIInt rank, size; 937 938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 939 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 940 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 941 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 942 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 943 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 944 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 945 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 946 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 947 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 951 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 952 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 953 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 955 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 956 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 957 for (p = pStart; p < pEnd; ++p) { 958 PetscInt dof, off, s; 959 960 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 961 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 962 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 963 } 964 PetscCall(PetscViewerFlush(viewer)); 965 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 966 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 967 for (p = pStart; p < pEnd; ++p) { 968 PetscInt dof, off, c; 969 970 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 971 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 972 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])); 973 } 974 PetscCall(PetscViewerFlush(viewer)); 975 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 976 if (coordSection && coordinates) { 977 CoordSystem cs = CS_CARTESIAN; 978 const PetscScalar *array, *arrayCell = NULL; 979 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 980 PetscMPIInt rank; 981 const char *name; 982 983 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 985 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 986 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 987 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 988 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 989 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 990 pStart = PetscMin(pvStart, pcStart); 991 pEnd = PetscMax(pvEnd, pcEnd); 992 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 995 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 996 997 PetscCall(VecGetArrayRead(coordinates, &array)); 998 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 999 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1000 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1001 for (p = pStart; p < pEnd; ++p) { 1002 PetscInt dof, off; 1003 1004 if (p >= pvStart && p < pvEnd) { 1005 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1006 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1007 if (dof) { 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1009 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1010 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1011 } 1012 } 1013 if (cdmCell && p >= pcStart && p < pcEnd) { 1014 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1015 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1016 if (dof) { 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1018 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1019 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1020 } 1021 } 1022 } 1023 PetscCall(PetscViewerFlush(viewer)); 1024 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1025 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1027 } 1028 PetscCall(DMGetNumLabels(dm, &numLabels)); 1029 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1030 for (l = 0; l < numLabels; ++l) { 1031 DMLabel label; 1032 PetscBool isdepth; 1033 const char *name; 1034 1035 PetscCall(DMGetLabelName(dm, l, &name)); 1036 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1037 if (isdepth) continue; 1038 PetscCall(DMGetLabel(dm, name, &label)); 1039 PetscCall(DMLabelView(label, viewer)); 1040 } 1041 if (size > 1) { 1042 PetscSF sf; 1043 1044 PetscCall(DMGetPointSF(dm, &sf)); 1045 PetscCall(PetscSFView(sf, viewer)); 1046 } 1047 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1088 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1089 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1090 if (!useLabels) numLabels = 0; 1091 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1092 if (!useColors) { 1093 numColors = 3; 1094 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1095 } 1096 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1097 if (!useColors) { 1098 numLColors = 4; 1099 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1100 } 1101 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1102 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1103 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1104 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1105 if (depth < dim) plotEdges = PETSC_FALSE; 1106 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1107 1108 /* filter points with labelvalue != labeldefaultvalue */ 1109 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1110 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1112 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1113 if (lflg) { 1114 DMLabel lbl; 1115 1116 PetscCall(DMGetLabel(dm, lname, &lbl)); 1117 if (lbl) { 1118 PetscInt val, defval; 1119 1120 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1121 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1122 for (c = pStart; c < pEnd; c++) { 1123 PetscInt *closure = NULL; 1124 PetscInt closureSize; 1125 1126 PetscCall(DMLabelGetValue(lbl, c, &val)); 1127 if (val == defval) continue; 1128 1129 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1130 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1131 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1132 } 1133 } 1134 } 1135 1136 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1137 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1138 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1139 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1140 \\documentclass[tikz]{standalone}\n\n\ 1141 \\usepackage{pgflibraryshapes}\n\ 1142 \\usetikzlibrary{backgrounds}\n\ 1143 \\usetikzlibrary{arrows}\n\ 1144 \\begin{document}\n")); 1145 if (size > 1) { 1146 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1147 for (p = 0; p < size; ++p) { 1148 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1149 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1150 } 1151 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1152 } 1153 if (drawHasse) { 1154 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1155 1156 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1168 } 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1170 1171 /* Plot vertices */ 1172 PetscCall(VecGetArray(coordinates, &coords)); 1173 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1174 for (v = vStart; v < vEnd; ++v) { 1175 PetscInt off, dof, d; 1176 PetscBool isLabeled = PETSC_FALSE; 1177 1178 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1181 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1182 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1183 for (d = 0; d < dof; ++d) { 1184 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1185 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1186 } 1187 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1188 if (dim == 3) { 1189 PetscReal tmp = tcoords[1]; 1190 tcoords[1] = tcoords[2]; 1191 tcoords[2] = -tmp; 1192 } 1193 for (d = 0; d < dof; ++d) { 1194 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1195 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1196 } 1197 if (drawHasse) color = colors[0 % numColors]; 1198 else color = colors[rank % numColors]; 1199 for (l = 0; l < numLabels; ++l) { 1200 PetscInt val; 1201 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1202 if (val >= 0) { 1203 color = lcolors[l % numLColors]; 1204 isLabeled = PETSC_TRUE; 1205 break; 1206 } 1207 } 1208 if (drawNumbers[0]) { 1209 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1210 } else if (drawColors[0]) { 1211 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1212 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1213 } 1214 PetscCall(VecRestoreArray(coordinates, &coords)); 1215 PetscCall(PetscViewerFlush(viewer)); 1216 /* Plot edges */ 1217 if (plotEdges) { 1218 PetscCall(VecGetArray(coordinates, &coords)); 1219 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1220 for (e = eStart; e < eEnd; ++e) { 1221 const PetscInt *cone; 1222 PetscInt coneSize, offA, offB, dof, d; 1223 1224 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1225 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1226 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1227 PetscCall(DMPlexGetCone(dm, e, &cone)); 1228 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1229 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1231 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1232 for (d = 0; d < dof; ++d) { 1233 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1234 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1235 } 1236 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1237 if (dim == 3) { 1238 PetscReal tmp = tcoords[1]; 1239 tcoords[1] = tcoords[2]; 1240 tcoords[2] = -tmp; 1241 } 1242 for (d = 0; d < dof; ++d) { 1243 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1244 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1245 } 1246 if (drawHasse) color = colors[1 % numColors]; 1247 else color = colors[rank % numColors]; 1248 for (l = 0; l < numLabels; ++l) { 1249 PetscInt val; 1250 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1251 if (val >= 0) { 1252 color = lcolors[l % numLColors]; 1253 break; 1254 } 1255 } 1256 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1257 } 1258 PetscCall(VecRestoreArray(coordinates, &coords)); 1259 PetscCall(PetscViewerFlush(viewer)); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1261 } 1262 /* Plot cells */ 1263 if (dim == 3 || !drawNumbers[1]) { 1264 for (e = eStart; e < eEnd; ++e) { 1265 const PetscInt *cone; 1266 1267 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1268 color = colors[rank % numColors]; 1269 for (l = 0; l < numLabels; ++l) { 1270 PetscInt val; 1271 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1272 if (val >= 0) { 1273 color = lcolors[l % numLColors]; 1274 break; 1275 } 1276 } 1277 PetscCall(DMPlexGetCone(dm, e, &cone)); 1278 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1279 } 1280 } else { 1281 DMPolytopeType ct; 1282 1283 /* Drawing a 2D polygon */ 1284 for (c = cStart; c < cEnd; ++c) { 1285 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1286 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1287 if (DMPolytopeTypeIsHybrid(ct)) { 1288 const PetscInt *cone; 1289 PetscInt coneSize, e; 1290 1291 PetscCall(DMPlexGetCone(dm, c, &cone)); 1292 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1293 for (e = 0; e < coneSize; ++e) { 1294 const PetscInt *econe; 1295 1296 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1297 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)); 1298 } 1299 } else { 1300 PetscInt *closure = NULL; 1301 PetscInt closureSize, Nv = 0, v; 1302 1303 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1304 for (p = 0; p < closureSize * 2; p += 2) { 1305 const PetscInt point = closure[p]; 1306 1307 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1308 } 1309 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1310 for (v = 0; v <= Nv; ++v) { 1311 const PetscInt vertex = closure[v % Nv]; 1312 1313 if (v > 0) { 1314 if (plotEdges) { 1315 const PetscInt *edge; 1316 PetscInt endpoints[2], ne; 1317 1318 endpoints[0] = closure[v - 1]; 1319 endpoints[1] = vertex; 1320 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1321 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1322 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1323 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1324 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1325 } 1326 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1327 } 1328 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1329 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1330 } 1331 } 1332 } 1333 for (c = cStart; c < cEnd; ++c) { 1334 double ccoords[3] = {0.0, 0.0, 0.0}; 1335 PetscBool isLabeled = PETSC_FALSE; 1336 PetscScalar *cellCoords = NULL; 1337 const PetscScalar *array; 1338 PetscInt numCoords, cdim, d; 1339 PetscBool isDG; 1340 1341 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1342 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1343 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1344 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1345 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1346 for (p = 0; p < numCoords / cdim; ++p) { 1347 for (d = 0; d < cdim; ++d) { 1348 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1349 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1350 } 1351 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1352 if (cdim == 3) { 1353 PetscReal tmp = tcoords[1]; 1354 tcoords[1] = tcoords[2]; 1355 tcoords[2] = -tmp; 1356 } 1357 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1358 } 1359 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1360 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1361 for (d = 0; d < cdim; ++d) { 1362 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1363 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1364 } 1365 if (drawHasse) color = colors[depth % numColors]; 1366 else color = colors[rank % numColors]; 1367 for (l = 0; l < numLabels; ++l) { 1368 PetscInt val; 1369 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1370 if (val >= 0) { 1371 color = lcolors[l % numLColors]; 1372 isLabeled = PETSC_TRUE; 1373 break; 1374 } 1375 } 1376 if (drawNumbers[dim]) { 1377 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1378 } else if (drawColors[dim]) { 1379 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1380 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1381 } 1382 if (drawHasse) { 1383 color = colors[depth % numColors]; 1384 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1389 1390 color = colors[1 % numColors]; 1391 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1396 1397 color = colors[0 % numColors]; 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1403 1404 for (p = pStart; p < pEnd; ++p) { 1405 const PetscInt *cone; 1406 PetscInt coneSize, cp; 1407 1408 PetscCall(DMPlexGetCone(dm, p, &cone)); 1409 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1410 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1411 } 1412 } 1413 PetscCall(PetscViewerFlush(viewer)); 1414 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1417 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1418 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1419 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1420 PetscCall(PetscFree3(names, colors, lcolors)); 1421 PetscCall(PetscBTDestroy(&wp)); 1422 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1423 Vec cown, acown; 1424 VecScatter sct; 1425 ISLocalToGlobalMapping g2l; 1426 IS gid, acis; 1427 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1428 MPI_Group ggroup, ngroup; 1429 PetscScalar *array, nid; 1430 const PetscInt *idxs; 1431 PetscInt *idxs2, *start, *adjacency, *work; 1432 PetscInt64 lm[3], gm[3]; 1433 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1434 PetscMPIInt d1, d2, rank; 1435 1436 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1437 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1438 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1439 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1440 #endif 1441 if (ncomm != MPI_COMM_NULL) { 1442 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1443 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1444 d1 = 0; 1445 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1446 nid = d2; 1447 PetscCallMPI(MPI_Group_free(&ggroup)); 1448 PetscCallMPI(MPI_Group_free(&ngroup)); 1449 PetscCallMPI(MPI_Comm_free(&ncomm)); 1450 } else nid = 0.0; 1451 1452 /* Get connectivity */ 1453 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1454 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1455 1456 /* filter overlapped local cells */ 1457 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1458 PetscCall(ISGetIndices(gid, &idxs)); 1459 PetscCall(ISGetLocalSize(gid, &cum)); 1460 PetscCall(PetscMalloc1(cum, &idxs2)); 1461 for (c = cStart, cum = 0; c < cEnd; c++) { 1462 if (idxs[c - cStart] < 0) continue; 1463 idxs2[cum++] = idxs[c - cStart]; 1464 } 1465 PetscCall(ISRestoreIndices(gid, &idxs)); 1466 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1467 PetscCall(ISDestroy(&gid)); 1468 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1469 1470 /* support for node-aware cell locality */ 1471 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1472 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1473 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1474 PetscCall(VecGetArray(cown, &array)); 1475 for (c = 0; c < numVertices; c++) array[c] = nid; 1476 PetscCall(VecRestoreArray(cown, &array)); 1477 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1478 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1479 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(ISDestroy(&acis)); 1481 PetscCall(VecScatterDestroy(&sct)); 1482 PetscCall(VecDestroy(&cown)); 1483 1484 /* compute edgeCut */ 1485 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1486 PetscCall(PetscMalloc1(cum, &work)); 1487 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1488 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1489 PetscCall(ISDestroy(&gid)); 1490 PetscCall(VecGetArray(acown, &array)); 1491 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1492 PetscInt totl; 1493 1494 totl = start[c + 1] - start[c]; 1495 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1496 for (i = 0; i < totl; i++) { 1497 if (work[i] < 0) { 1498 ect += 1; 1499 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1500 } 1501 } 1502 } 1503 PetscCall(PetscFree(work)); 1504 PetscCall(VecRestoreArray(acown, &array)); 1505 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1506 lm[1] = -numVertices; 1507 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1509 lm[0] = ect; /* edgeCut */ 1510 lm[1] = ectn; /* node-aware edgeCut */ 1511 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1512 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1513 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1514 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1515 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1516 #else 1517 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1518 #endif 1519 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1520 PetscCall(PetscFree(start)); 1521 PetscCall(PetscFree(adjacency)); 1522 PetscCall(VecDestroy(&acown)); 1523 } else { 1524 const char *name; 1525 PetscInt *sizes, *hybsizes, *ghostsizes; 1526 PetscInt locDepth, depth, cellHeight, dim, d; 1527 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1528 PetscInt numLabels, l, maxSize = 17; 1529 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1530 MPI_Comm comm; 1531 PetscMPIInt size, rank; 1532 1533 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1534 PetscCallMPI(MPI_Comm_size(comm, &size)); 1535 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1536 PetscCall(DMGetDimension(dm, &dim)); 1537 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1538 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1539 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1541 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1542 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1543 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1544 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1545 gcNum = gcEnd - gcStart; 1546 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1547 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1548 for (d = 0; d <= depth; d++) { 1549 PetscInt Nc[2] = {0, 0}, ict; 1550 1551 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1552 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1553 ict = ct0; 1554 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1555 ct0 = (DMPolytopeType)ict; 1556 for (p = pStart; p < pEnd; ++p) { 1557 DMPolytopeType ct; 1558 1559 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1560 if (ct == ct0) ++Nc[0]; 1561 else ++Nc[1]; 1562 } 1563 if (size < maxSize) { 1564 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1565 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1566 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1567 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1568 for (p = 0; p < size; ++p) { 1569 if (rank == 0) { 1570 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1571 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1572 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1573 } 1574 } 1575 } else { 1576 PetscInt locMinMax[2]; 1577 1578 locMinMax[0] = Nc[0] + Nc[1]; 1579 locMinMax[1] = Nc[0] + Nc[1]; 1580 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1581 locMinMax[0] = Nc[1]; 1582 locMinMax[1] = Nc[1]; 1583 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1584 if (d == depth) { 1585 locMinMax[0] = gcNum; 1586 locMinMax[1] = gcNum; 1587 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1588 } 1589 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1591 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1592 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1593 } 1594 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1595 } 1596 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1597 { 1598 const PetscReal *maxCell; 1599 const PetscReal *L; 1600 PetscBool localized; 1601 1602 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1603 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1604 if (L || localized) { 1605 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1606 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1607 if (L) { 1608 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1609 for (d = 0; d < dim; ++d) { 1610 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1611 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1612 } 1613 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1614 } 1615 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1616 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1617 } 1618 } 1619 PetscCall(DMGetNumLabels(dm, &numLabels)); 1620 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1621 for (l = 0; l < numLabels; ++l) { 1622 DMLabel label; 1623 const char *name; 1624 IS valueIS; 1625 const PetscInt *values; 1626 PetscInt numValues, v; 1627 1628 PetscCall(DMGetLabelName(dm, l, &name)); 1629 PetscCall(DMGetLabel(dm, name, &label)); 1630 PetscCall(DMLabelGetNumValues(label, &numValues)); 1631 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1632 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1633 PetscCall(ISGetIndices(valueIS, &values)); 1634 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1635 for (v = 0; v < numValues; ++v) { 1636 PetscInt size; 1637 1638 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1639 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1640 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1641 } 1642 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1643 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1644 PetscCall(ISRestoreIndices(valueIS, &values)); 1645 PetscCall(ISDestroy(&valueIS)); 1646 } 1647 { 1648 char **labelNames; 1649 PetscInt Nl = numLabels; 1650 PetscBool flg; 1651 1652 PetscCall(PetscMalloc1(Nl, &labelNames)); 1653 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1654 for (l = 0; l < Nl; ++l) { 1655 DMLabel label; 1656 1657 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1658 if (flg) { 1659 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1660 PetscCall(DMLabelView(label, viewer)); 1661 } 1662 PetscCall(PetscFree(labelNames[l])); 1663 } 1664 PetscCall(PetscFree(labelNames)); 1665 } 1666 /* If no fields are specified, people do not want to see adjacency */ 1667 if (dm->Nf) { 1668 PetscInt f; 1669 1670 for (f = 0; f < dm->Nf; ++f) { 1671 const char *name; 1672 1673 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1674 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1675 PetscCall(PetscViewerASCIIPushTab(viewer)); 1676 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1677 if (dm->fields[f].adjacency[0]) { 1678 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1679 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1680 } else { 1681 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1682 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1683 } 1684 PetscCall(PetscViewerASCIIPopTab(viewer)); 1685 } 1686 } 1687 PetscCall(DMGetCoarseDM(dm, &cdm)); 1688 if (cdm) { 1689 PetscCall(PetscViewerASCIIPushTab(viewer)); 1690 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1691 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1692 PetscCall(PetscViewerASCIIPopTab(viewer)); 1693 } 1694 } 1695 PetscFunctionReturn(PETSC_SUCCESS); 1696 } 1697 1698 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1699 { 1700 DMPolytopeType ct; 1701 PetscMPIInt rank; 1702 PetscInt cdim; 1703 1704 PetscFunctionBegin; 1705 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1706 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1707 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1708 switch (ct) { 1709 case DM_POLYTOPE_SEGMENT: 1710 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1711 switch (cdim) { 1712 case 1: { 1713 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1714 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1715 1716 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1719 } break; 1720 case 2: { 1721 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1722 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1723 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1724 1725 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1726 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)); 1727 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)); 1728 } break; 1729 default: 1730 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1731 } 1732 break; 1733 case DM_POLYTOPE_TRIANGLE: 1734 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)); 1735 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1738 break; 1739 case DM_POLYTOPE_QUADRILATERAL: 1740 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)); 1741 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)); 1742 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1746 break; 1747 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1748 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)); 1749 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)); 1750 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1754 break; 1755 case DM_POLYTOPE_FV_GHOST: 1756 break; 1757 default: 1758 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1759 } 1760 PetscFunctionReturn(PETSC_SUCCESS); 1761 } 1762 1763 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1764 { 1765 DMPolytopeType ct; 1766 PetscReal centroid[2] = {0., 0.}; 1767 PetscMPIInt rank; 1768 PetscInt fillColor, v, e, d; 1769 1770 PetscFunctionBegin; 1771 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1772 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1773 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1774 switch (ct) { 1775 case DM_POLYTOPE_TRIANGLE: { 1776 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1777 1778 for (v = 0; v < 3; ++v) { 1779 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1780 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1781 } 1782 for (e = 0; e < 3; ++e) { 1783 refCoords[0] = refVertices[e * 2 + 0]; 1784 refCoords[1] = refVertices[e * 2 + 1]; 1785 for (d = 1; d <= edgeDiv; ++d) { 1786 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1787 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1788 } 1789 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1790 for (d = 0; d < edgeDiv; ++d) { 1791 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)); 1792 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1793 } 1794 } 1795 } break; 1796 default: 1797 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1798 } 1799 PetscFunctionReturn(PETSC_SUCCESS); 1800 } 1801 1802 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1803 { 1804 PetscDraw draw; 1805 DM cdm; 1806 PetscSection coordSection; 1807 Vec coordinates; 1808 PetscReal xyl[3], xyr[3]; 1809 PetscReal *refCoords, *edgeCoords; 1810 PetscBool isnull, drawAffine = PETSC_TRUE; 1811 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1812 1813 PetscFunctionBegin; 1814 PetscCall(DMGetCoordinateDim(dm, &dim)); 1815 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1816 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1817 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1818 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1819 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1820 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1821 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1822 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1823 1824 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1825 PetscCall(PetscDrawIsNull(draw, &isnull)); 1826 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1827 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1828 1829 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1830 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1831 PetscCall(PetscDrawClear(draw)); 1832 1833 for (c = cStart; c < cEnd; ++c) { 1834 PetscScalar *coords = NULL; 1835 const PetscScalar *coords_arr; 1836 PetscInt numCoords; 1837 PetscBool isDG; 1838 1839 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1840 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1841 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1842 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1843 } 1844 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1845 PetscCall(PetscDrawFlush(draw)); 1846 PetscCall(PetscDrawPause(draw)); 1847 PetscCall(PetscDrawSave(draw)); 1848 PetscFunctionReturn(PETSC_SUCCESS); 1849 } 1850 1851 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1852 { 1853 DM odm = dm, rdm = dm, cdm; 1854 PetscFE fe; 1855 PetscSpace sp; 1856 PetscClassId id; 1857 PetscInt degree; 1858 PetscBool hoView = PETSC_TRUE; 1859 1860 PetscFunctionBegin; 1861 PetscObjectOptionsBegin((PetscObject)dm); 1862 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1863 PetscOptionsEnd(); 1864 PetscCall(PetscObjectReference((PetscObject)dm)); 1865 *hdm = dm; 1866 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1867 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1868 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1869 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1870 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1871 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1872 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1873 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1874 DM cdm, rcdm; 1875 Mat In; 1876 Vec cl, rcl; 1877 1878 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1879 if (rd > 1) PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1880 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1881 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1882 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1883 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1884 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1885 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1886 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1887 PetscCall(MatMult(In, cl, rcl)); 1888 PetscCall(MatDestroy(&In)); 1889 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1890 PetscCall(DMDestroy(&odm)); 1891 odm = rdm; 1892 } 1893 *hdm = rdm; 1894 PetscFunctionReturn(PETSC_SUCCESS); 1895 } 1896 1897 #if defined(PETSC_HAVE_EXODUSII) 1898 #include <exodusII.h> 1899 #include <petscviewerexodusii.h> 1900 #endif 1901 1902 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1903 { 1904 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1905 char name[PETSC_MAX_PATH_LEN]; 1906 1907 PetscFunctionBegin; 1908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1909 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1910 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1911 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1912 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1913 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1914 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1916 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1917 if (iascii) { 1918 PetscViewerFormat format; 1919 PetscCall(PetscViewerGetFormat(viewer, &format)); 1920 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1921 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1922 } else if (ishdf5) { 1923 #if defined(PETSC_HAVE_HDF5) 1924 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1925 #else 1926 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1927 #endif 1928 } else if (isvtk) { 1929 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1930 } else if (isdraw) { 1931 DM hdm; 1932 1933 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1934 PetscCall(DMPlexView_Draw(hdm, viewer)); 1935 PetscCall(DMDestroy(&hdm)); 1936 } else if (isglvis) { 1937 PetscCall(DMPlexView_GLVis(dm, viewer)); 1938 #if defined(PETSC_HAVE_EXODUSII) 1939 } else if (isexodus) { 1940 /* 1941 exodusII requires that all sets be part of exactly one cell set. 1942 If the dm does not have a "Cell Sets" label defined, we create one 1943 with ID 1, containing all cells. 1944 Note that if the Cell Sets label is defined but does not cover all cells, 1945 we may still have a problem. This should probably be checked here or in the viewer; 1946 */ 1947 PetscInt numCS; 1948 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1949 if (!numCS) { 1950 PetscInt cStart, cEnd, c; 1951 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1952 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1953 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1954 } 1955 PetscCall(DMView_PlexExodusII(dm, viewer)); 1956 #endif 1957 #if defined(PETSC_HAVE_CGNS) 1958 } else if (iscgns) { 1959 PetscCall(DMView_PlexCGNS(dm, viewer)); 1960 #endif 1961 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1962 /* Optionally view the partition */ 1963 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1964 if (flg) { 1965 Vec ranks; 1966 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1967 PetscCall(VecView(ranks, viewer)); 1968 PetscCall(VecDestroy(&ranks)); 1969 } 1970 /* Optionally view a label */ 1971 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1972 if (flg) { 1973 DMLabel label; 1974 Vec val; 1975 1976 PetscCall(DMGetLabel(dm, name, &label)); 1977 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1978 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1979 PetscCall(VecView(val, viewer)); 1980 PetscCall(VecDestroy(&val)); 1981 } 1982 PetscFunctionReturn(PETSC_SUCCESS); 1983 } 1984 1985 /*@ 1986 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1987 1988 Collective 1989 1990 Input Parameters: 1991 + dm - The `DM` whose topology is to be saved 1992 - viewer - The `PetscViewer` to save it in 1993 1994 Level: advanced 1995 1996 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1997 @*/ 1998 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1999 { 2000 PetscBool ishdf5; 2001 2002 PetscFunctionBegin; 2003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2004 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2005 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2006 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2007 if (ishdf5) { 2008 #if defined(PETSC_HAVE_HDF5) 2009 PetscViewerFormat format; 2010 PetscCall(PetscViewerGetFormat(viewer, &format)); 2011 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2012 IS globalPointNumbering; 2013 2014 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2015 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2016 PetscCall(ISDestroy(&globalPointNumbering)); 2017 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2018 #else 2019 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2020 #endif 2021 } 2022 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2023 PetscFunctionReturn(PETSC_SUCCESS); 2024 } 2025 2026 /*@ 2027 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2028 2029 Collective 2030 2031 Input Parameters: 2032 + dm - The `DM` whose coordinates are to be saved 2033 - viewer - The `PetscViewer` for saving 2034 2035 Level: advanced 2036 2037 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2038 @*/ 2039 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2040 { 2041 PetscBool ishdf5; 2042 2043 PetscFunctionBegin; 2044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2045 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2046 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2047 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2048 if (ishdf5) { 2049 #if defined(PETSC_HAVE_HDF5) 2050 PetscViewerFormat format; 2051 PetscCall(PetscViewerGetFormat(viewer, &format)); 2052 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2053 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2054 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2055 #else 2056 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2057 #endif 2058 } 2059 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2060 PetscFunctionReturn(PETSC_SUCCESS); 2061 } 2062 2063 /*@ 2064 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2065 2066 Collective 2067 2068 Input Parameters: 2069 + dm - The `DM` whose labels are to be saved 2070 - viewer - The `PetscViewer` for saving 2071 2072 Level: advanced 2073 2074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2075 @*/ 2076 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2077 { 2078 PetscBool ishdf5; 2079 2080 PetscFunctionBegin; 2081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2082 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2083 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2084 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2085 if (ishdf5) { 2086 #if defined(PETSC_HAVE_HDF5) 2087 IS globalPointNumbering; 2088 PetscViewerFormat format; 2089 2090 PetscCall(PetscViewerGetFormat(viewer, &format)); 2091 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2092 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2093 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2094 PetscCall(ISDestroy(&globalPointNumbering)); 2095 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2096 #else 2097 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2098 #endif 2099 } 2100 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2101 PetscFunctionReturn(PETSC_SUCCESS); 2102 } 2103 2104 /*@ 2105 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2106 2107 Collective 2108 2109 Input Parameters: 2110 + dm - The `DM` that contains the topology on which the section to be saved is defined 2111 . viewer - The `PetscViewer` for saving 2112 - sectiondm - The `DM` that contains the section to be saved 2113 2114 Level: advanced 2115 2116 Notes: 2117 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. 2118 2119 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 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. 2120 2121 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2122 @*/ 2123 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2124 { 2125 PetscBool ishdf5; 2126 2127 PetscFunctionBegin; 2128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2129 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2130 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2131 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2132 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2133 if (ishdf5) { 2134 #if defined(PETSC_HAVE_HDF5) 2135 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2136 #else 2137 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2138 #endif 2139 } 2140 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2141 PetscFunctionReturn(PETSC_SUCCESS); 2142 } 2143 2144 /*@ 2145 DMPlexGlobalVectorView - Saves a global vector 2146 2147 Collective 2148 2149 Input Parameters: 2150 + dm - The `DM` that represents the topology 2151 . viewer - The `PetscViewer` to save data with 2152 . sectiondm - The `DM` that contains the global section on which vec is defined 2153 - vec - The global vector to be saved 2154 2155 Level: advanced 2156 2157 Notes: 2158 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 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. 2159 2160 Calling sequence: 2161 .vb 2162 DMCreate(PETSC_COMM_WORLD, &dm); 2163 DMSetType(dm, DMPLEX); 2164 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2165 DMClone(dm, §iondm); 2166 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2167 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2168 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2169 PetscSectionSetChart(section, pStart, pEnd); 2170 PetscSectionSetUp(section); 2171 DMSetLocalSection(sectiondm, section); 2172 PetscSectionDestroy(§ion); 2173 DMGetGlobalVector(sectiondm, &vec); 2174 PetscObjectSetName((PetscObject)vec, "vec_name"); 2175 DMPlexTopologyView(dm, viewer); 2176 DMPlexSectionView(dm, viewer, sectiondm); 2177 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2178 DMRestoreGlobalVector(sectiondm, &vec); 2179 DMDestroy(§iondm); 2180 DMDestroy(&dm); 2181 .ve 2182 2183 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2184 @*/ 2185 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2186 { 2187 PetscBool ishdf5; 2188 2189 PetscFunctionBegin; 2190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2191 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2192 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2193 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2194 /* Check consistency */ 2195 { 2196 PetscSection section; 2197 PetscBool includesConstraints; 2198 PetscInt m, m1; 2199 2200 PetscCall(VecGetLocalSize(vec, &m1)); 2201 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2202 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2203 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2204 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2205 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2206 } 2207 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2208 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2209 if (ishdf5) { 2210 #if defined(PETSC_HAVE_HDF5) 2211 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2212 #else 2213 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2214 #endif 2215 } 2216 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2217 PetscFunctionReturn(PETSC_SUCCESS); 2218 } 2219 2220 /*@ 2221 DMPlexLocalVectorView - Saves a local vector 2222 2223 Collective 2224 2225 Input Parameters: 2226 + dm - The `DM` that represents the topology 2227 . viewer - The `PetscViewer` to save data with 2228 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2229 - vec - The local vector to be saved 2230 2231 Level: advanced 2232 2233 Note: 2234 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 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. 2235 2236 Calling sequence: 2237 .vb 2238 DMCreate(PETSC_COMM_WORLD, &dm); 2239 DMSetType(dm, DMPLEX); 2240 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2241 DMClone(dm, §iondm); 2242 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2243 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2244 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2245 PetscSectionSetChart(section, pStart, pEnd); 2246 PetscSectionSetUp(section); 2247 DMSetLocalSection(sectiondm, section); 2248 DMGetLocalVector(sectiondm, &vec); 2249 PetscObjectSetName((PetscObject)vec, "vec_name"); 2250 DMPlexTopologyView(dm, viewer); 2251 DMPlexSectionView(dm, viewer, sectiondm); 2252 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2253 DMRestoreLocalVector(sectiondm, &vec); 2254 DMDestroy(§iondm); 2255 DMDestroy(&dm); 2256 .ve 2257 2258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2259 @*/ 2260 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2261 { 2262 PetscBool ishdf5; 2263 2264 PetscFunctionBegin; 2265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2266 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2267 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2268 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2269 /* Check consistency */ 2270 { 2271 PetscSection section; 2272 PetscBool includesConstraints; 2273 PetscInt m, m1; 2274 2275 PetscCall(VecGetLocalSize(vec, &m1)); 2276 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2277 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2278 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2279 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2280 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2281 } 2282 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2283 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2284 if (ishdf5) { 2285 #if defined(PETSC_HAVE_HDF5) 2286 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2287 #else 2288 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2289 #endif 2290 } 2291 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2292 PetscFunctionReturn(PETSC_SUCCESS); 2293 } 2294 2295 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2296 { 2297 PetscBool ishdf5; 2298 2299 PetscFunctionBegin; 2300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2301 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2303 if (ishdf5) { 2304 #if defined(PETSC_HAVE_HDF5) 2305 PetscViewerFormat format; 2306 PetscCall(PetscViewerGetFormat(viewer, &format)); 2307 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2308 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2309 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2310 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2311 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2312 PetscFunctionReturn(PETSC_SUCCESS); 2313 #else 2314 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2315 #endif 2316 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2317 } 2318 2319 /*@ 2320 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2321 2322 Collective 2323 2324 Input Parameters: 2325 + dm - The `DM` into which the topology is loaded 2326 - viewer - The `PetscViewer` for the saved topology 2327 2328 Output Parameter: 2329 . 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; `NULL` if unneeded 2330 2331 Level: advanced 2332 2333 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2334 `PetscViewer`, `PetscSF` 2335 @*/ 2336 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2344 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2345 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2346 if (ishdf5) { 2347 #if defined(PETSC_HAVE_HDF5) 2348 PetscViewerFormat format; 2349 PetscCall(PetscViewerGetFormat(viewer, &format)); 2350 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2351 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2352 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2353 #else 2354 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2355 #endif 2356 } 2357 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2358 PetscFunctionReturn(PETSC_SUCCESS); 2359 } 2360 2361 /*@ 2362 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2363 2364 Collective 2365 2366 Input Parameters: 2367 + dm - The `DM` into which the coordinates are loaded 2368 . viewer - The `PetscViewer` for the saved coordinates 2369 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2370 2371 Level: advanced 2372 2373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2374 `PetscSF`, `PetscViewer` 2375 @*/ 2376 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2377 { 2378 PetscBool ishdf5; 2379 2380 PetscFunctionBegin; 2381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2382 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2383 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2384 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2385 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2386 if (ishdf5) { 2387 #if defined(PETSC_HAVE_HDF5) 2388 PetscViewerFormat format; 2389 PetscCall(PetscViewerGetFormat(viewer, &format)); 2390 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2391 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2392 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2393 #else 2394 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2395 #endif 2396 } 2397 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2398 PetscFunctionReturn(PETSC_SUCCESS); 2399 } 2400 2401 /*@ 2402 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2403 2404 Collective 2405 2406 Input Parameters: 2407 + dm - The `DM` into which the labels are loaded 2408 . viewer - The `PetscViewer` for the saved labels 2409 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2410 2411 Level: advanced 2412 2413 Note: 2414 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2415 2416 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2417 `PetscSF`, `PetscViewer` 2418 @*/ 2419 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2420 { 2421 PetscBool ishdf5; 2422 2423 PetscFunctionBegin; 2424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2425 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2426 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2427 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2428 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2429 if (ishdf5) { 2430 #if defined(PETSC_HAVE_HDF5) 2431 PetscViewerFormat format; 2432 2433 PetscCall(PetscViewerGetFormat(viewer, &format)); 2434 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2435 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2436 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2437 #else 2438 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2439 #endif 2440 } 2441 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2442 PetscFunctionReturn(PETSC_SUCCESS); 2443 } 2444 2445 /*@ 2446 DMPlexSectionLoad - Loads section into a `DMPLEX` 2447 2448 Collective 2449 2450 Input Parameters: 2451 + dm - The `DM` that represents the topology 2452 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2453 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2454 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2455 2456 Output Parameters: 2457 + 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) 2458 - 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) 2459 2460 Level: advanced 2461 2462 Notes: 2463 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. 2464 2465 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 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. 2466 2467 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. 2468 2469 Example using 2 processes: 2470 .vb 2471 NX (number of points on dm): 4 2472 sectionA : the on-disk section 2473 vecA : a vector associated with sectionA 2474 sectionB : sectiondm's local section constructed in this function 2475 vecB (local) : a vector associated with sectiondm's local section 2476 vecB (global) : a vector associated with sectiondm's global section 2477 2478 rank 0 rank 1 2479 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2480 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2481 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2482 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2483 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2484 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2485 sectionB->atlasDof : 1 0 1 | 1 3 2486 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2487 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2488 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2489 .ve 2490 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2491 2492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2493 @*/ 2494 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2495 { 2496 PetscBool ishdf5; 2497 2498 PetscFunctionBegin; 2499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2500 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2501 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2502 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2503 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2504 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2505 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2506 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2507 if (ishdf5) { 2508 #if defined(PETSC_HAVE_HDF5) 2509 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2510 #else 2511 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2512 #endif 2513 } 2514 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2515 PetscFunctionReturn(PETSC_SUCCESS); 2516 } 2517 2518 /*@ 2519 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2520 2521 Collective 2522 2523 Input Parameters: 2524 + dm - The `DM` that represents the topology 2525 . viewer - The `PetscViewer` that represents the on-disk vector data 2526 . sectiondm - The `DM` that contains the global section on which vec is defined 2527 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2528 - vec - The global vector to set values of 2529 2530 Level: advanced 2531 2532 Notes: 2533 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2534 2535 Calling sequence: 2536 .vb 2537 DMCreate(PETSC_COMM_WORLD, &dm); 2538 DMSetType(dm, DMPLEX); 2539 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2540 DMPlexTopologyLoad(dm, viewer, &sfX); 2541 DMClone(dm, §iondm); 2542 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2543 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2544 DMGetGlobalVector(sectiondm, &vec); 2545 PetscObjectSetName((PetscObject)vec, "vec_name"); 2546 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2547 DMRestoreGlobalVector(sectiondm, &vec); 2548 PetscSFDestroy(&gsf); 2549 PetscSFDestroy(&sfX); 2550 DMDestroy(§iondm); 2551 DMDestroy(&dm); 2552 .ve 2553 2554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2555 `PetscSF`, `PetscViewer` 2556 @*/ 2557 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2558 { 2559 PetscBool ishdf5; 2560 2561 PetscFunctionBegin; 2562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2563 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2564 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2565 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2566 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2567 /* Check consistency */ 2568 { 2569 PetscSection section; 2570 PetscBool includesConstraints; 2571 PetscInt m, m1; 2572 2573 PetscCall(VecGetLocalSize(vec, &m1)); 2574 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2575 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2576 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2577 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2578 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2579 } 2580 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2581 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2582 if (ishdf5) { 2583 #if defined(PETSC_HAVE_HDF5) 2584 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 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_GlobalVectorLoad, viewer, 0, 0, 0)); 2590 PetscFunctionReturn(PETSC_SUCCESS); 2591 } 2592 2593 /*@ 2594 DMPlexLocalVectorLoad - Loads on-disk vector data into a local 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 local section on which vec is defined 2602 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2603 - vec - The local 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 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, NULL, &lsf); 2619 DMGetLocalVector(sectiondm, &vec); 2620 PetscObjectSetName((PetscObject)vec, "vec_name"); 2621 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2622 DMRestoreLocalVector(sectiondm, &vec); 2623 PetscSFDestroy(&lsf); 2624 PetscSFDestroy(&sfX); 2625 DMDestroy(§iondm); 2626 DMDestroy(&dm); 2627 .ve 2628 2629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2630 `PetscSF`, `PetscViewer` 2631 @*/ 2632 PetscErrorCode DMPlexLocalVectorLoad(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 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2640 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2641 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2642 /* Check consistency */ 2643 { 2644 PetscSection section; 2645 PetscBool includesConstraints; 2646 PetscInt m, m1; 2647 2648 PetscCall(VecGetLocalSize(vec, &m1)); 2649 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2650 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2651 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2652 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2653 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2654 } 2655 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2656 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2657 if (ishdf5) { 2658 #if defined(PETSC_HAVE_HDF5) 2659 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2660 #else 2661 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2662 #endif 2663 } 2664 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2665 PetscFunctionReturn(PETSC_SUCCESS); 2666 } 2667 2668 PetscErrorCode DMDestroy_Plex(DM dm) 2669 { 2670 DM_Plex *mesh = (DM_Plex *)dm->data; 2671 2672 PetscFunctionBegin; 2673 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2674 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2675 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2676 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2677 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2678 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2679 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2680 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2681 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2682 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2683 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2684 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2685 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2686 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2687 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2688 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2689 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2690 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2691 PetscCall(PetscFree(mesh->cones)); 2692 PetscCall(PetscFree(mesh->coneOrientations)); 2693 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2694 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2695 PetscCall(PetscFree(mesh->supports)); 2696 PetscCall(PetscFree(mesh->cellTypes)); 2697 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2698 PetscCall(PetscFree(mesh->tetgenOpts)); 2699 PetscCall(PetscFree(mesh->triangleOpts)); 2700 PetscCall(PetscFree(mesh->transformType)); 2701 PetscCall(PetscFree(mesh->distributionName)); 2702 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2703 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2704 PetscCall(ISDestroy(&mesh->subpointIS)); 2705 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2706 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2707 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2708 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2709 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2710 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2711 PetscCall(ISDestroy(&mesh->anchorIS)); 2712 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2713 PetscCall(PetscFree(mesh->parents)); 2714 PetscCall(PetscFree(mesh->childIDs)); 2715 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2716 PetscCall(PetscFree(mesh->children)); 2717 PetscCall(DMDestroy(&mesh->referenceTree)); 2718 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2719 PetscCall(PetscFree(mesh->neighbors)); 2720 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2721 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2722 PetscCall(PetscFree(mesh)); 2723 PetscFunctionReturn(PETSC_SUCCESS); 2724 } 2725 2726 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2727 { 2728 PetscSection sectionGlobal; 2729 PetscInt bs = -1, mbs; 2730 PetscInt localSize, localStart = 0; 2731 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2732 MatType mtype; 2733 ISLocalToGlobalMapping ltog; 2734 2735 PetscFunctionBegin; 2736 PetscCall(MatInitializePackage()); 2737 mtype = dm->mattype; 2738 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2739 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2740 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2741 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2742 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2743 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2744 PetscCall(MatSetType(*J, mtype)); 2745 PetscCall(MatSetFromOptions(*J)); 2746 PetscCall(MatGetBlockSize(*J, &mbs)); 2747 if (mbs > 1) bs = mbs; 2748 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2749 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2750 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2751 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2752 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2753 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2754 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2755 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2756 if (!isShell) { 2757 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2758 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2759 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2760 2761 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2762 2763 PetscCall(PetscCalloc1(localSize, &pblocks)); 2764 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2765 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2766 for (p = pStart; p < pEnd; ++p) { 2767 switch (dm->blocking_type) { 2768 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2769 PetscInt bdof, offset; 2770 2771 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2772 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2773 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2774 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2775 dof = dof < 0 ? -(dof + 1) : dof; 2776 bdof = cdof && (dof - cdof) ? 1 : dof; 2777 if (dof) { 2778 if (bs < 0) { 2779 bs = bdof; 2780 } else if (bs != bdof) { 2781 bs = 1; 2782 } 2783 } 2784 } break; 2785 case DM_BLOCKING_FIELD_NODE: { 2786 for (PetscInt field = 0; field < num_fields; field++) { 2787 PetscInt num_comp, bdof, offset; 2788 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2789 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2790 if (dof < 0) continue; 2791 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2792 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2793 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); 2794 PetscInt num_nodes = dof / num_comp; 2795 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2796 // Handle possibly constant block size (unlikely) 2797 bdof = cdof && (dof - cdof) ? 1 : dof; 2798 if (dof) { 2799 if (bs < 0) { 2800 bs = bdof; 2801 } else if (bs != bdof) { 2802 bs = 1; 2803 } 2804 } 2805 } 2806 } break; 2807 } 2808 } 2809 /* Must have same blocksize on all procs (some might have no points) */ 2810 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2811 bsLocal[1] = bs; 2812 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2813 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2814 else bs = bsMinMax[0]; 2815 bs = PetscMax(1, bs); 2816 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2817 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2818 PetscCall(MatSetBlockSize(*J, bs)); 2819 PetscCall(MatSetUp(*J)); 2820 } else { 2821 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2822 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2823 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2824 } 2825 { // Consolidate blocks 2826 PetscInt nblocks = 0; 2827 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2828 if (pblocks[i] == 0) continue; 2829 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2830 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2831 } 2832 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2833 } 2834 PetscCall(PetscFree(pblocks)); 2835 } 2836 PetscCall(MatSetDM(*J, dm)); 2837 PetscFunctionReturn(PETSC_SUCCESS); 2838 } 2839 2840 /*@ 2841 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2842 2843 Not Collective 2844 2845 Input Parameter: 2846 . dm - The `DMPLEX` 2847 2848 Output Parameter: 2849 . subsection - The subdomain section 2850 2851 Level: developer 2852 2853 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2854 @*/ 2855 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2856 { 2857 DM_Plex *mesh = (DM_Plex *)dm->data; 2858 2859 PetscFunctionBegin; 2860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2861 if (!mesh->subdomainSection) { 2862 PetscSection section; 2863 PetscSF sf; 2864 2865 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2866 PetscCall(DMGetLocalSection(dm, §ion)); 2867 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2868 PetscCall(PetscSFDestroy(&sf)); 2869 } 2870 *subsection = mesh->subdomainSection; 2871 PetscFunctionReturn(PETSC_SUCCESS); 2872 } 2873 2874 /*@ 2875 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2876 2877 Not Collective 2878 2879 Input Parameter: 2880 . dm - The `DMPLEX` 2881 2882 Output Parameters: 2883 + pStart - The first mesh point 2884 - pEnd - The upper bound for mesh points 2885 2886 Level: beginner 2887 2888 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2889 @*/ 2890 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2891 { 2892 DM_Plex *mesh = (DM_Plex *)dm->data; 2893 2894 PetscFunctionBegin; 2895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2896 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2897 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2898 PetscFunctionReturn(PETSC_SUCCESS); 2899 } 2900 2901 /*@ 2902 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2903 2904 Not Collective 2905 2906 Input Parameters: 2907 + dm - The `DMPLEX` 2908 . pStart - The first mesh point 2909 - pEnd - The upper bound for mesh points 2910 2911 Level: beginner 2912 2913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2914 @*/ 2915 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2916 { 2917 DM_Plex *mesh = (DM_Plex *)dm->data; 2918 2919 PetscFunctionBegin; 2920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2921 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2922 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2923 PetscCall(PetscFree(mesh->cellTypes)); 2924 PetscFunctionReturn(PETSC_SUCCESS); 2925 } 2926 2927 /*@ 2928 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2929 2930 Not Collective 2931 2932 Input Parameters: 2933 + dm - The `DMPLEX` 2934 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2935 2936 Output Parameter: 2937 . size - The cone size for point `p` 2938 2939 Level: beginner 2940 2941 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2942 @*/ 2943 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2944 { 2945 DM_Plex *mesh = (DM_Plex *)dm->data; 2946 2947 PetscFunctionBegin; 2948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2949 PetscAssertPointer(size, 3); 2950 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2951 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2952 PetscFunctionReturn(PETSC_SUCCESS); 2953 } 2954 2955 /*@ 2956 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2957 2958 Not Collective 2959 2960 Input Parameters: 2961 + dm - The `DMPLEX` 2962 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2963 - size - The cone size for point `p` 2964 2965 Level: beginner 2966 2967 Note: 2968 This should be called after `DMPlexSetChart()`. 2969 2970 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2971 @*/ 2972 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2973 { 2974 DM_Plex *mesh = (DM_Plex *)dm->data; 2975 2976 PetscFunctionBegin; 2977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2978 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2979 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2980 PetscFunctionReturn(PETSC_SUCCESS); 2981 } 2982 2983 /*@C 2984 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2985 2986 Not Collective 2987 2988 Input Parameters: 2989 + dm - The `DMPLEX` 2990 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2991 2992 Output Parameter: 2993 . cone - An array of points which are on the in-edges for point `p` 2994 2995 Level: beginner 2996 2997 Fortran Notes: 2998 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2999 `DMPlexRestoreCone()` is not needed/available in C. 3000 3001 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3002 @*/ 3003 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3004 { 3005 DM_Plex *mesh = (DM_Plex *)dm->data; 3006 PetscInt off; 3007 3008 PetscFunctionBegin; 3009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3010 PetscAssertPointer(cone, 3); 3011 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3012 *cone = &mesh->cones[off]; 3013 PetscFunctionReturn(PETSC_SUCCESS); 3014 } 3015 3016 /*@C 3017 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3018 3019 Not Collective 3020 3021 Input Parameters: 3022 + dm - The `DMPLEX` 3023 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3024 3025 Output Parameters: 3026 + pConesSection - `PetscSection` describing the layout of `pCones` 3027 - pCones - An array of points which are on the in-edges for the point set `p` 3028 3029 Level: intermediate 3030 3031 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3032 @*/ 3033 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3034 { 3035 PetscSection cs, newcs; 3036 PetscInt *cones; 3037 PetscInt *newarr = NULL; 3038 PetscInt n; 3039 3040 PetscFunctionBegin; 3041 PetscCall(DMPlexGetCones(dm, &cones)); 3042 PetscCall(DMPlexGetConeSection(dm, &cs)); 3043 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3044 if (pConesSection) *pConesSection = newcs; 3045 if (pCones) { 3046 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3047 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3048 } 3049 PetscFunctionReturn(PETSC_SUCCESS); 3050 } 3051 3052 /*@ 3053 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3054 3055 Not Collective 3056 3057 Input Parameters: 3058 + dm - The `DMPLEX` 3059 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3060 3061 Output Parameter: 3062 . expandedPoints - An array of vertices recursively expanded from input points 3063 3064 Level: advanced 3065 3066 Notes: 3067 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3068 3069 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3070 3071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3072 `DMPlexGetDepth()`, `IS` 3073 @*/ 3074 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3075 { 3076 IS *expandedPointsAll; 3077 PetscInt depth; 3078 3079 PetscFunctionBegin; 3080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3081 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3082 PetscAssertPointer(expandedPoints, 3); 3083 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3084 *expandedPoints = expandedPointsAll[0]; 3085 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3086 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3087 PetscFunctionReturn(PETSC_SUCCESS); 3088 } 3089 3090 /*@ 3091 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3092 3093 Not Collective 3094 3095 Input Parameters: 3096 + dm - The `DMPLEX` 3097 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3098 3099 Output Parameters: 3100 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3101 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3102 - sections - (optional) An array of sections which describe mappings from points to their cone points 3103 3104 Level: advanced 3105 3106 Notes: 3107 Like `DMPlexGetConeTuple()` but recursive. 3108 3109 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. 3110 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3111 3112 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\: 3113 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3114 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3115 3116 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3117 `DMPlexGetDepth()`, `PetscSection`, `IS` 3118 @*/ 3119 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3120 { 3121 const PetscInt *arr0 = NULL, *cone = NULL; 3122 PetscInt *arr = NULL, *newarr = NULL; 3123 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3124 IS *expandedPoints_; 3125 PetscSection *sections_; 3126 3127 PetscFunctionBegin; 3128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3129 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3130 if (depth) PetscAssertPointer(depth, 3); 3131 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3132 if (sections) PetscAssertPointer(sections, 5); 3133 PetscCall(ISGetLocalSize(points, &n)); 3134 PetscCall(ISGetIndices(points, &arr0)); 3135 PetscCall(DMPlexGetDepth(dm, &depth_)); 3136 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3137 PetscCall(PetscCalloc1(depth_, §ions_)); 3138 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3139 for (d = depth_ - 1; d >= 0; d--) { 3140 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3141 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3142 for (i = 0; i < n; i++) { 3143 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3144 if (arr[i] >= start && arr[i] < end) { 3145 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3146 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3147 } else { 3148 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3149 } 3150 } 3151 PetscCall(PetscSectionSetUp(sections_[d])); 3152 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3153 PetscCall(PetscMalloc1(newn, &newarr)); 3154 for (i = 0; i < n; i++) { 3155 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3156 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3157 if (cn > 1) { 3158 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3159 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3160 } else { 3161 newarr[co] = arr[i]; 3162 } 3163 } 3164 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3165 arr = newarr; 3166 n = newn; 3167 } 3168 PetscCall(ISRestoreIndices(points, &arr0)); 3169 *depth = depth_; 3170 if (expandedPoints) *expandedPoints = expandedPoints_; 3171 else { 3172 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3173 PetscCall(PetscFree(expandedPoints_)); 3174 } 3175 if (sections) *sections = sections_; 3176 else { 3177 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3178 PetscCall(PetscFree(sections_)); 3179 } 3180 PetscFunctionReturn(PETSC_SUCCESS); 3181 } 3182 3183 /*@ 3184 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3185 3186 Not Collective 3187 3188 Input Parameters: 3189 + dm - The `DMPLEX` 3190 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3191 3192 Output Parameters: 3193 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3194 . expandedPoints - (optional) An array of recursively expanded cones 3195 - sections - (optional) An array of sections which describe mappings from points to their cone points 3196 3197 Level: advanced 3198 3199 Note: 3200 See `DMPlexGetConeRecursive()` 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3203 `DMPlexGetDepth()`, `IS`, `PetscSection` 3204 @*/ 3205 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3206 { 3207 PetscInt d, depth_; 3208 3209 PetscFunctionBegin; 3210 PetscCall(DMPlexGetDepth(dm, &depth_)); 3211 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3212 if (depth) *depth = 0; 3213 if (expandedPoints) { 3214 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3215 PetscCall(PetscFree(*expandedPoints)); 3216 } 3217 if (sections) { 3218 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3219 PetscCall(PetscFree(*sections)); 3220 } 3221 PetscFunctionReturn(PETSC_SUCCESS); 3222 } 3223 3224 /*@ 3225 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 3226 3227 Not Collective 3228 3229 Input Parameters: 3230 + dm - The `DMPLEX` 3231 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3232 - cone - An array of points which are on the in-edges for point `p` 3233 3234 Level: beginner 3235 3236 Note: 3237 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3238 3239 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3240 @*/ 3241 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3242 { 3243 DM_Plex *mesh = (DM_Plex *)dm->data; 3244 PetscInt dof, off, c; 3245 3246 PetscFunctionBegin; 3247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3248 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3249 if (dof) PetscAssertPointer(cone, 3); 3250 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3251 if (PetscDefined(USE_DEBUG)) { 3252 PetscInt pStart, pEnd; 3253 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3254 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); 3255 for (c = 0; c < dof; ++c) { 3256 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); 3257 mesh->cones[off + c] = cone[c]; 3258 } 3259 } else { 3260 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3261 } 3262 PetscFunctionReturn(PETSC_SUCCESS); 3263 } 3264 3265 /*@C 3266 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3267 3268 Not Collective 3269 3270 Input Parameters: 3271 + dm - The `DMPLEX` 3272 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3273 3274 Output Parameter: 3275 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3276 integer giving the prescription for cone traversal. 3277 3278 Level: beginner 3279 3280 Note: 3281 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3282 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3283 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3284 with the identity. 3285 3286 Fortran Notes: 3287 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3288 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3289 3290 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3291 @*/ 3292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3293 { 3294 DM_Plex *mesh = (DM_Plex *)dm->data; 3295 PetscInt off; 3296 3297 PetscFunctionBegin; 3298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3299 if (PetscDefined(USE_DEBUG)) { 3300 PetscInt dof; 3301 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3302 if (dof) PetscAssertPointer(coneOrientation, 3); 3303 } 3304 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3305 3306 *coneOrientation = &mesh->coneOrientations[off]; 3307 PetscFunctionReturn(PETSC_SUCCESS); 3308 } 3309 3310 /*@ 3311 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3312 3313 Not Collective 3314 3315 Input Parameters: 3316 + dm - The `DMPLEX` 3317 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3318 - coneOrientation - An array of orientations 3319 3320 Level: beginner 3321 3322 Notes: 3323 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3324 3325 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3326 3327 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3328 @*/ 3329 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3330 { 3331 DM_Plex *mesh = (DM_Plex *)dm->data; 3332 PetscInt pStart, pEnd; 3333 PetscInt dof, off, c; 3334 3335 PetscFunctionBegin; 3336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3337 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3338 if (dof) PetscAssertPointer(coneOrientation, 3); 3339 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3340 if (PetscDefined(USE_DEBUG)) { 3341 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3342 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); 3343 for (c = 0; c < dof; ++c) { 3344 PetscInt cdof, o = coneOrientation[c]; 3345 3346 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3347 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); 3348 mesh->coneOrientations[off + c] = o; 3349 } 3350 } else { 3351 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3352 } 3353 PetscFunctionReturn(PETSC_SUCCESS); 3354 } 3355 3356 /*@ 3357 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3358 3359 Not Collective 3360 3361 Input Parameters: 3362 + dm - The `DMPLEX` 3363 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3364 . conePos - The local index in the cone where the point should be put 3365 - conePoint - The mesh point to insert 3366 3367 Level: beginner 3368 3369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3370 @*/ 3371 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3372 { 3373 DM_Plex *mesh = (DM_Plex *)dm->data; 3374 PetscInt pStart, pEnd; 3375 PetscInt dof, off; 3376 3377 PetscFunctionBegin; 3378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3379 if (PetscDefined(USE_DEBUG)) { 3380 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3381 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); 3382 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); 3383 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3384 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); 3385 } 3386 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3387 mesh->cones[off + conePos] = conePoint; 3388 PetscFunctionReturn(PETSC_SUCCESS); 3389 } 3390 3391 /*@ 3392 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p 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 . conePos - The local index in the cone where the point should be put 3400 - coneOrientation - The point orientation to insert 3401 3402 Level: beginner 3403 3404 Note: 3405 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3406 3407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3408 @*/ 3409 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3410 { 3411 DM_Plex *mesh = (DM_Plex *)dm->data; 3412 PetscInt pStart, pEnd; 3413 PetscInt dof, off; 3414 3415 PetscFunctionBegin; 3416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3417 if (PetscDefined(USE_DEBUG)) { 3418 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3419 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); 3420 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3421 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); 3422 } 3423 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3424 mesh->coneOrientations[off + conePos] = coneOrientation; 3425 PetscFunctionReturn(PETSC_SUCCESS); 3426 } 3427 3428 /*@C 3429 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3430 3431 Not collective 3432 3433 Input Parameters: 3434 + dm - The DMPlex 3435 - p - The point, which must lie in the chart set with DMPlexSetChart() 3436 3437 Output Parameters: 3438 + cone - An array of points which are on the in-edges for point `p` 3439 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3440 integer giving the prescription for cone traversal. 3441 3442 Level: beginner 3443 3444 Notes: 3445 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3446 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3447 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3448 with the identity. 3449 3450 Fortran Notes: 3451 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3452 `DMPlexRestoreCone()` is not needed/available in C. 3453 3454 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3455 @*/ 3456 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3457 { 3458 DM_Plex *mesh = (DM_Plex *)dm->data; 3459 3460 PetscFunctionBegin; 3461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3462 if (mesh->tr) { 3463 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3464 } else { 3465 PetscInt off; 3466 if (PetscDefined(USE_DEBUG)) { 3467 PetscInt dof; 3468 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3469 if (dof) { 3470 if (cone) PetscAssertPointer(cone, 3); 3471 if (ornt) PetscAssertPointer(ornt, 4); 3472 } 3473 } 3474 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3475 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3476 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3477 } 3478 PetscFunctionReturn(PETSC_SUCCESS); 3479 } 3480 3481 /*@C 3482 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3483 3484 Not Collective 3485 3486 Input Parameters: 3487 + dm - The DMPlex 3488 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3489 . cone - An array of points which are on the in-edges for point p 3490 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3491 integer giving the prescription for cone traversal. 3492 3493 Level: beginner 3494 3495 Notes: 3496 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3497 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3498 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3499 with the identity. 3500 3501 Fortran Notes: 3502 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3503 `DMPlexRestoreCone()` is not needed/available in C. 3504 3505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3506 @*/ 3507 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3508 { 3509 DM_Plex *mesh = (DM_Plex *)dm->data; 3510 3511 PetscFunctionBegin; 3512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3513 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3514 PetscFunctionReturn(PETSC_SUCCESS); 3515 } 3516 3517 /*@ 3518 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3519 3520 Not Collective 3521 3522 Input Parameters: 3523 + dm - The `DMPLEX` 3524 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3525 3526 Output Parameter: 3527 . size - The support size for point `p` 3528 3529 Level: beginner 3530 3531 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3532 @*/ 3533 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3534 { 3535 DM_Plex *mesh = (DM_Plex *)dm->data; 3536 3537 PetscFunctionBegin; 3538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3539 PetscAssertPointer(size, 3); 3540 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3541 PetscFunctionReturn(PETSC_SUCCESS); 3542 } 3543 3544 /*@ 3545 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3546 3547 Not Collective 3548 3549 Input Parameters: 3550 + dm - The `DMPLEX` 3551 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3552 - size - The support size for point `p` 3553 3554 Level: beginner 3555 3556 Note: 3557 This should be called after `DMPlexSetChart()`. 3558 3559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3560 @*/ 3561 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3562 { 3563 DM_Plex *mesh = (DM_Plex *)dm->data; 3564 3565 PetscFunctionBegin; 3566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3567 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3568 PetscFunctionReturn(PETSC_SUCCESS); 3569 } 3570 3571 /*@C 3572 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3573 3574 Not Collective 3575 3576 Input Parameters: 3577 + dm - The `DMPLEX` 3578 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3579 3580 Output Parameter: 3581 . support - An array of points which are on the out-edges for point `p` 3582 3583 Level: beginner 3584 3585 Fortran Notes: 3586 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3587 `DMPlexRestoreSupport()` is not needed/available in C. 3588 3589 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3590 @*/ 3591 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3592 { 3593 DM_Plex *mesh = (DM_Plex *)dm->data; 3594 PetscInt off; 3595 3596 PetscFunctionBegin; 3597 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3598 PetscAssertPointer(support, 3); 3599 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3600 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3601 PetscFunctionReturn(PETSC_SUCCESS); 3602 } 3603 3604 /*@ 3605 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3606 3607 Not Collective 3608 3609 Input Parameters: 3610 + dm - The `DMPLEX` 3611 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3612 - support - An array of points which are on the out-edges for point `p` 3613 3614 Level: beginner 3615 3616 Note: 3617 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3618 3619 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3620 @*/ 3621 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3622 { 3623 DM_Plex *mesh = (DM_Plex *)dm->data; 3624 PetscInt pStart, pEnd; 3625 PetscInt dof, off, c; 3626 3627 PetscFunctionBegin; 3628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3629 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3630 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3631 if (dof) PetscAssertPointer(support, 3); 3632 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3633 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); 3634 for (c = 0; c < dof; ++c) { 3635 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); 3636 mesh->supports[off + c] = support[c]; 3637 } 3638 PetscFunctionReturn(PETSC_SUCCESS); 3639 } 3640 3641 /*@ 3642 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3643 3644 Not Collective 3645 3646 Input Parameters: 3647 + dm - The `DMPLEX` 3648 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3649 . supportPos - The local index in the cone where the point should be put 3650 - supportPoint - The mesh point to insert 3651 3652 Level: beginner 3653 3654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3655 @*/ 3656 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3657 { 3658 DM_Plex *mesh = (DM_Plex *)dm->data; 3659 PetscInt pStart, pEnd; 3660 PetscInt dof, off; 3661 3662 PetscFunctionBegin; 3663 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3664 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3665 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3666 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3667 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); 3668 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); 3669 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); 3670 mesh->supports[off + supportPos] = supportPoint; 3671 PetscFunctionReturn(PETSC_SUCCESS); 3672 } 3673 3674 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3675 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3676 { 3677 switch (ct) { 3678 case DM_POLYTOPE_SEGMENT: 3679 if (o == -1) return -2; 3680 break; 3681 case DM_POLYTOPE_TRIANGLE: 3682 if (o == -3) return -1; 3683 if (o == -2) return -3; 3684 if (o == -1) return -2; 3685 break; 3686 case DM_POLYTOPE_QUADRILATERAL: 3687 if (o == -4) return -2; 3688 if (o == -3) return -1; 3689 if (o == -2) return -4; 3690 if (o == -1) return -3; 3691 break; 3692 default: 3693 return o; 3694 } 3695 return o; 3696 } 3697 3698 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3699 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3700 { 3701 switch (ct) { 3702 case DM_POLYTOPE_SEGMENT: 3703 if ((o == -2) || (o == 1)) return -1; 3704 if (o == -1) return 0; 3705 break; 3706 case DM_POLYTOPE_TRIANGLE: 3707 if (o == -3) return -2; 3708 if (o == -2) return -1; 3709 if (o == -1) return -3; 3710 break; 3711 case DM_POLYTOPE_QUADRILATERAL: 3712 if (o == -4) return -2; 3713 if (o == -3) return -1; 3714 if (o == -2) return -4; 3715 if (o == -1) return -3; 3716 break; 3717 default: 3718 return o; 3719 } 3720 return o; 3721 } 3722 3723 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3724 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3725 { 3726 PetscInt pStart, pEnd, p; 3727 3728 PetscFunctionBegin; 3729 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3730 for (p = pStart; p < pEnd; ++p) { 3731 const PetscInt *cone, *ornt; 3732 PetscInt coneSize, c; 3733 3734 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3735 PetscCall(DMPlexGetCone(dm, p, &cone)); 3736 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3737 for (c = 0; c < coneSize; ++c) { 3738 DMPolytopeType ct; 3739 const PetscInt o = ornt[c]; 3740 3741 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3742 switch (ct) { 3743 case DM_POLYTOPE_SEGMENT: 3744 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3745 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3746 break; 3747 case DM_POLYTOPE_TRIANGLE: 3748 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3749 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3750 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3751 break; 3752 case DM_POLYTOPE_QUADRILATERAL: 3753 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3754 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3755 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3756 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3757 break; 3758 default: 3759 break; 3760 } 3761 } 3762 } 3763 PetscFunctionReturn(PETSC_SUCCESS); 3764 } 3765 3766 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3767 { 3768 DM_Plex *mesh = (DM_Plex *)dm->data; 3769 3770 PetscFunctionBeginHot; 3771 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3772 if (useCone) { 3773 PetscCall(DMPlexGetConeSize(dm, p, size)); 3774 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3775 } else { 3776 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3777 PetscCall(DMPlexGetSupport(dm, p, arr)); 3778 } 3779 } else { 3780 if (useCone) { 3781 const PetscSection s = mesh->coneSection; 3782 const PetscInt ps = p - s->pStart; 3783 const PetscInt off = s->atlasOff[ps]; 3784 3785 *size = s->atlasDof[ps]; 3786 *arr = mesh->cones + off; 3787 *ornt = mesh->coneOrientations + off; 3788 } else { 3789 const PetscSection s = mesh->supportSection; 3790 const PetscInt ps = p - s->pStart; 3791 const PetscInt off = s->atlasOff[ps]; 3792 3793 *size = s->atlasDof[ps]; 3794 *arr = mesh->supports + off; 3795 } 3796 } 3797 PetscFunctionReturn(PETSC_SUCCESS); 3798 } 3799 3800 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3801 { 3802 DM_Plex *mesh = (DM_Plex *)dm->data; 3803 3804 PetscFunctionBeginHot; 3805 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3806 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3807 } 3808 PetscFunctionReturn(PETSC_SUCCESS); 3809 } 3810 3811 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3812 { 3813 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3814 PetscInt *closure; 3815 const PetscInt *tmp = NULL, *tmpO = NULL; 3816 PetscInt off = 0, tmpSize, t; 3817 3818 PetscFunctionBeginHot; 3819 if (ornt) { 3820 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3821 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; 3822 } 3823 if (*points) { 3824 closure = *points; 3825 } else { 3826 PetscInt maxConeSize, maxSupportSize; 3827 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3828 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3829 } 3830 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3831 if (ct == DM_POLYTOPE_UNKNOWN) { 3832 closure[off++] = p; 3833 closure[off++] = 0; 3834 for (t = 0; t < tmpSize; ++t) { 3835 closure[off++] = tmp[t]; 3836 closure[off++] = tmpO ? tmpO[t] : 0; 3837 } 3838 } else { 3839 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3840 3841 /* We assume that cells with a valid type have faces with a valid type */ 3842 closure[off++] = p; 3843 closure[off++] = ornt; 3844 for (t = 0; t < tmpSize; ++t) { 3845 DMPolytopeType ft; 3846 3847 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3848 closure[off++] = tmp[arr[t]]; 3849 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3850 } 3851 } 3852 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3853 if (numPoints) *numPoints = tmpSize + 1; 3854 if (points) *points = closure; 3855 PetscFunctionReturn(PETSC_SUCCESS); 3856 } 3857 3858 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3859 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3860 { 3861 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3862 const PetscInt *cone, *ornt; 3863 PetscInt *pts, *closure = NULL; 3864 DMPolytopeType ft; 3865 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3866 PetscInt dim, coneSize, c, d, clSize, cl; 3867 3868 PetscFunctionBeginHot; 3869 PetscCall(DMGetDimension(dm, &dim)); 3870 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3871 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3872 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3873 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3874 maxSize = PetscMax(coneSeries, supportSeries); 3875 if (*points) { 3876 pts = *points; 3877 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3878 c = 0; 3879 pts[c++] = point; 3880 pts[c++] = o; 3881 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3882 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3883 for (cl = 0; cl < clSize * 2; cl += 2) { 3884 pts[c++] = closure[cl]; 3885 pts[c++] = closure[cl + 1]; 3886 } 3887 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3888 for (cl = 0; cl < clSize * 2; cl += 2) { 3889 pts[c++] = closure[cl]; 3890 pts[c++] = closure[cl + 1]; 3891 } 3892 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3893 for (d = 2; d < coneSize; ++d) { 3894 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3895 pts[c++] = cone[arr[d * 2 + 0]]; 3896 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3897 } 3898 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3899 if (dim >= 3) { 3900 for (d = 2; d < coneSize; ++d) { 3901 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3902 const PetscInt *fcone, *fornt; 3903 PetscInt fconeSize, fc, i; 3904 3905 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3906 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3907 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3908 for (fc = 0; fc < fconeSize; ++fc) { 3909 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3910 const PetscInt co = farr[fc * 2 + 1]; 3911 3912 for (i = 0; i < c; i += 2) 3913 if (pts[i] == cp) break; 3914 if (i == c) { 3915 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3916 pts[c++] = cp; 3917 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3918 } 3919 } 3920 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3921 } 3922 } 3923 *numPoints = c / 2; 3924 *points = pts; 3925 PetscFunctionReturn(PETSC_SUCCESS); 3926 } 3927 3928 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3929 { 3930 DMPolytopeType ct; 3931 PetscInt *closure, *fifo; 3932 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3933 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3934 PetscInt depth, maxSize; 3935 3936 PetscFunctionBeginHot; 3937 PetscCall(DMPlexGetDepth(dm, &depth)); 3938 if (depth == 1) { 3939 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3940 PetscFunctionReturn(PETSC_SUCCESS); 3941 } 3942 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3943 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; 3944 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3945 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3946 PetscFunctionReturn(PETSC_SUCCESS); 3947 } 3948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3949 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3950 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3951 maxSize = PetscMax(coneSeries, supportSeries); 3952 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3953 if (*points) { 3954 closure = *points; 3955 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3956 closure[closureSize++] = p; 3957 closure[closureSize++] = ornt; 3958 fifo[fifoSize++] = p; 3959 fifo[fifoSize++] = ornt; 3960 fifo[fifoSize++] = ct; 3961 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3962 while (fifoSize - fifoStart) { 3963 const PetscInt q = fifo[fifoStart++]; 3964 const PetscInt o = fifo[fifoStart++]; 3965 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3966 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3967 const PetscInt *tmp, *tmpO = NULL; 3968 PetscInt tmpSize, t; 3969 3970 if (PetscDefined(USE_DEBUG)) { 3971 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3972 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); 3973 } 3974 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3975 for (t = 0; t < tmpSize; ++t) { 3976 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3977 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3978 const PetscInt cp = tmp[ip]; 3979 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3980 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3981 PetscInt c; 3982 3983 /* Check for duplicate */ 3984 for (c = 0; c < closureSize; c += 2) { 3985 if (closure[c] == cp) break; 3986 } 3987 if (c == closureSize) { 3988 closure[closureSize++] = cp; 3989 closure[closureSize++] = co; 3990 fifo[fifoSize++] = cp; 3991 fifo[fifoSize++] = co; 3992 fifo[fifoSize++] = ct; 3993 } 3994 } 3995 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3996 } 3997 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3998 if (numPoints) *numPoints = closureSize / 2; 3999 if (points) *points = closure; 4000 PetscFunctionReturn(PETSC_SUCCESS); 4001 } 4002 4003 /*@C 4004 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4005 4006 Not Collective 4007 4008 Input Parameters: 4009 + dm - The `DMPLEX` 4010 . p - The mesh point 4011 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4012 4013 Input/Output Parameter: 4014 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4015 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4016 4017 Output Parameter: 4018 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4019 4020 Level: beginner 4021 4022 Note: 4023 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4024 4025 Fortran Notes: 4026 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4027 4028 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4029 @*/ 4030 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4031 { 4032 PetscFunctionBeginHot; 4033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4034 if (numPoints) PetscAssertPointer(numPoints, 4); 4035 if (points) PetscAssertPointer(points, 5); 4036 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4037 PetscFunctionReturn(PETSC_SUCCESS); 4038 } 4039 4040 /*@C 4041 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4042 4043 Not Collective 4044 4045 Input Parameters: 4046 + dm - The `DMPLEX` 4047 . p - The mesh point 4048 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4049 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4050 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4051 4052 Level: beginner 4053 4054 Note: 4055 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4056 4057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4058 @*/ 4059 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4060 { 4061 PetscFunctionBeginHot; 4062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4063 if (numPoints) *numPoints = 0; 4064 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4065 PetscFunctionReturn(PETSC_SUCCESS); 4066 } 4067 4068 /*@ 4069 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4070 4071 Not Collective 4072 4073 Input Parameter: 4074 . dm - The `DMPLEX` 4075 4076 Output Parameters: 4077 + maxConeSize - The maximum number of in-edges 4078 - maxSupportSize - The maximum number of out-edges 4079 4080 Level: beginner 4081 4082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4083 @*/ 4084 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4085 { 4086 DM_Plex *mesh = (DM_Plex *)dm->data; 4087 4088 PetscFunctionBegin; 4089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4090 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4091 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4092 PetscFunctionReturn(PETSC_SUCCESS); 4093 } 4094 4095 PetscErrorCode DMSetUp_Plex(DM dm) 4096 { 4097 DM_Plex *mesh = (DM_Plex *)dm->data; 4098 PetscInt size, maxSupportSize; 4099 4100 PetscFunctionBegin; 4101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4102 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4103 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4104 PetscCall(PetscMalloc1(size, &mesh->cones)); 4105 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4106 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4107 if (maxSupportSize) { 4108 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4109 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4110 PetscCall(PetscMalloc1(size, &mesh->supports)); 4111 } 4112 PetscFunctionReturn(PETSC_SUCCESS); 4113 } 4114 4115 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4116 { 4117 PetscFunctionBegin; 4118 if (subdm) PetscCall(DMClone(dm, subdm)); 4119 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4120 if (subdm) (*subdm)->useNatural = dm->useNatural; 4121 if (dm->useNatural && dm->sfMigration) { 4122 PetscSF sfNatural; 4123 4124 (*subdm)->sfMigration = dm->sfMigration; 4125 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4126 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4127 (*subdm)->sfNatural = sfNatural; 4128 } 4129 PetscFunctionReturn(PETSC_SUCCESS); 4130 } 4131 4132 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4133 { 4134 PetscInt i = 0; 4135 4136 PetscFunctionBegin; 4137 PetscCall(DMClone(dms[0], superdm)); 4138 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4139 (*superdm)->useNatural = PETSC_FALSE; 4140 for (i = 0; i < len; i++) { 4141 if (dms[i]->useNatural && dms[i]->sfMigration) { 4142 PetscSF sfNatural; 4143 4144 (*superdm)->sfMigration = dms[i]->sfMigration; 4145 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4146 (*superdm)->useNatural = PETSC_TRUE; 4147 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4148 (*superdm)->sfNatural = sfNatural; 4149 break; 4150 } 4151 } 4152 PetscFunctionReturn(PETSC_SUCCESS); 4153 } 4154 4155 /*@ 4156 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4157 4158 Not Collective 4159 4160 Input Parameter: 4161 . dm - The `DMPLEX` 4162 4163 Level: beginner 4164 4165 Note: 4166 This should be called after all calls to `DMPlexSetCone()` 4167 4168 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4169 @*/ 4170 PetscErrorCode DMPlexSymmetrize(DM dm) 4171 { 4172 DM_Plex *mesh = (DM_Plex *)dm->data; 4173 PetscInt *offsets; 4174 PetscInt supportSize; 4175 PetscInt pStart, pEnd, p; 4176 4177 PetscFunctionBegin; 4178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4179 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4180 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4181 /* Calculate support sizes */ 4182 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4183 for (p = pStart; p < pEnd; ++p) { 4184 PetscInt dof, off, c; 4185 4186 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4187 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4188 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4189 } 4190 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4191 /* Calculate supports */ 4192 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4193 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4194 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4195 for (p = pStart; p < pEnd; ++p) { 4196 PetscInt dof, off, c; 4197 4198 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4199 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4200 for (c = off; c < off + dof; ++c) { 4201 const PetscInt q = mesh->cones[c]; 4202 PetscInt offS; 4203 4204 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4205 4206 mesh->supports[offS + offsets[q]] = p; 4207 ++offsets[q]; 4208 } 4209 } 4210 PetscCall(PetscFree(offsets)); 4211 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4212 PetscFunctionReturn(PETSC_SUCCESS); 4213 } 4214 4215 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4216 { 4217 IS stratumIS; 4218 4219 PetscFunctionBegin; 4220 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4221 if (PetscDefined(USE_DEBUG)) { 4222 PetscInt qStart, qEnd, numLevels, level; 4223 PetscBool overlap = PETSC_FALSE; 4224 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4225 for (level = 0; level < numLevels; level++) { 4226 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4227 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4228 overlap = PETSC_TRUE; 4229 break; 4230 } 4231 } 4232 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); 4233 } 4234 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4235 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4236 PetscCall(ISDestroy(&stratumIS)); 4237 PetscFunctionReturn(PETSC_SUCCESS); 4238 } 4239 4240 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4241 { 4242 PetscInt *pMin, *pMax; 4243 PetscInt pStart, pEnd; 4244 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4245 4246 PetscFunctionBegin; 4247 { 4248 DMLabel label2; 4249 4250 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4251 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4252 } 4253 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4254 for (PetscInt p = pStart; p < pEnd; ++p) { 4255 DMPolytopeType ct; 4256 4257 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4258 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4259 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4260 } 4261 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4262 for (PetscInt d = dmin; d <= dmax; ++d) { 4263 pMin[d] = PETSC_MAX_INT; 4264 pMax[d] = PETSC_MIN_INT; 4265 } 4266 for (PetscInt p = pStart; p < pEnd; ++p) { 4267 DMPolytopeType ct; 4268 PetscInt d; 4269 4270 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4271 d = DMPolytopeTypeGetDim(ct); 4272 pMin[d] = PetscMin(p, pMin[d]); 4273 pMax[d] = PetscMax(p, pMax[d]); 4274 } 4275 for (PetscInt d = dmin; d <= dmax; ++d) { 4276 if (pMin[d] > pMax[d]) continue; 4277 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4278 } 4279 PetscCall(PetscFree2(pMin, pMax)); 4280 PetscFunctionReturn(PETSC_SUCCESS); 4281 } 4282 4283 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4284 { 4285 PetscInt pStart, pEnd; 4286 PetscInt numRoots = 0, numLeaves = 0; 4287 4288 PetscFunctionBegin; 4289 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4290 { 4291 /* Initialize roots and count leaves */ 4292 PetscInt sMin = PETSC_MAX_INT; 4293 PetscInt sMax = PETSC_MIN_INT; 4294 PetscInt coneSize, supportSize; 4295 4296 for (PetscInt p = pStart; p < pEnd; ++p) { 4297 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4298 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4299 if (!coneSize && supportSize) { 4300 sMin = PetscMin(p, sMin); 4301 sMax = PetscMax(p, sMax); 4302 ++numRoots; 4303 } else if (!supportSize && coneSize) { 4304 ++numLeaves; 4305 } else if (!supportSize && !coneSize) { 4306 /* Isolated points */ 4307 sMin = PetscMin(p, sMin); 4308 sMax = PetscMax(p, sMax); 4309 } 4310 } 4311 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4312 } 4313 4314 if (numRoots + numLeaves == (pEnd - pStart)) { 4315 PetscInt sMin = PETSC_MAX_INT; 4316 PetscInt sMax = PETSC_MIN_INT; 4317 PetscInt coneSize, supportSize; 4318 4319 for (PetscInt p = pStart; p < pEnd; ++p) { 4320 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4321 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4322 if (!supportSize && coneSize) { 4323 sMin = PetscMin(p, sMin); 4324 sMax = PetscMax(p, sMax); 4325 } 4326 } 4327 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4328 } else { 4329 PetscInt level = 0; 4330 PetscInt qStart, qEnd; 4331 4332 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4333 while (qEnd > qStart) { 4334 PetscInt sMin = PETSC_MAX_INT; 4335 PetscInt sMax = PETSC_MIN_INT; 4336 4337 for (PetscInt q = qStart; q < qEnd; ++q) { 4338 const PetscInt *support; 4339 PetscInt supportSize; 4340 4341 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4342 PetscCall(DMPlexGetSupport(dm, q, &support)); 4343 for (PetscInt s = 0; s < supportSize; ++s) { 4344 sMin = PetscMin(support[s], sMin); 4345 sMax = PetscMax(support[s], sMax); 4346 } 4347 } 4348 PetscCall(DMLabelGetNumValues(label, &level)); 4349 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4350 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4351 } 4352 } 4353 PetscFunctionReturn(PETSC_SUCCESS); 4354 } 4355 4356 /*@ 4357 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4358 4359 Collective 4360 4361 Input Parameter: 4362 . dm - The `DMPLEX` 4363 4364 Level: beginner 4365 4366 Notes: 4367 The strata group all points of the same grade, and this function calculates the strata. This 4368 grade can be seen as the height (or depth) of the point in the DAG. 4369 4370 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4371 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4372 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4373 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4374 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4375 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4376 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4377 4378 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4379 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4380 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 4381 to interpolate only that one (e0), so that 4382 .vb 4383 cone(c0) = {e0, v2} 4384 cone(e0) = {v0, v1} 4385 .ve 4386 If `DMPlexStratify()` is run on this mesh, it will give depths 4387 .vb 4388 depth 0 = {v0, v1, v2} 4389 depth 1 = {e0, c0} 4390 .ve 4391 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4392 4393 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4394 4395 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4396 @*/ 4397 PetscErrorCode DMPlexStratify(DM dm) 4398 { 4399 DM_Plex *mesh = (DM_Plex *)dm->data; 4400 DMLabel label; 4401 PetscBool flg = PETSC_FALSE; 4402 4403 PetscFunctionBegin; 4404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4405 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4406 4407 // Create depth label 4408 PetscCall(DMCreateLabel(dm, "depth")); 4409 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4410 4411 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4412 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4413 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4414 4415 { /* just in case there is an empty process */ 4416 PetscInt numValues, maxValues = 0, v; 4417 4418 PetscCall(DMLabelGetNumValues(label, &numValues)); 4419 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4420 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4421 } 4422 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4423 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4424 PetscFunctionReturn(PETSC_SUCCESS); 4425 } 4426 4427 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4428 { 4429 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4430 PetscInt dim, depth, pheight, coneSize; 4431 4432 PetscFunctionBeginHot; 4433 PetscCall(DMGetDimension(dm, &dim)); 4434 PetscCall(DMPlexGetDepth(dm, &depth)); 4435 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4436 pheight = depth - pdepth; 4437 if (depth <= 1) { 4438 switch (pdepth) { 4439 case 0: 4440 ct = DM_POLYTOPE_POINT; 4441 break; 4442 case 1: 4443 switch (coneSize) { 4444 case 2: 4445 ct = DM_POLYTOPE_SEGMENT; 4446 break; 4447 case 3: 4448 ct = DM_POLYTOPE_TRIANGLE; 4449 break; 4450 case 4: 4451 switch (dim) { 4452 case 2: 4453 ct = DM_POLYTOPE_QUADRILATERAL; 4454 break; 4455 case 3: 4456 ct = DM_POLYTOPE_TETRAHEDRON; 4457 break; 4458 default: 4459 break; 4460 } 4461 break; 4462 case 5: 4463 ct = DM_POLYTOPE_PYRAMID; 4464 break; 4465 case 6: 4466 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4467 break; 4468 case 8: 4469 ct = DM_POLYTOPE_HEXAHEDRON; 4470 break; 4471 default: 4472 break; 4473 } 4474 } 4475 } else { 4476 if (pdepth == 0) { 4477 ct = DM_POLYTOPE_POINT; 4478 } else if (pheight == 0) { 4479 switch (dim) { 4480 case 1: 4481 switch (coneSize) { 4482 case 2: 4483 ct = DM_POLYTOPE_SEGMENT; 4484 break; 4485 default: 4486 break; 4487 } 4488 break; 4489 case 2: 4490 switch (coneSize) { 4491 case 3: 4492 ct = DM_POLYTOPE_TRIANGLE; 4493 break; 4494 case 4: 4495 ct = DM_POLYTOPE_QUADRILATERAL; 4496 break; 4497 default: 4498 break; 4499 } 4500 break; 4501 case 3: 4502 switch (coneSize) { 4503 case 4: 4504 ct = DM_POLYTOPE_TETRAHEDRON; 4505 break; 4506 case 5: { 4507 const PetscInt *cone; 4508 PetscInt faceConeSize; 4509 4510 PetscCall(DMPlexGetCone(dm, p, &cone)); 4511 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4512 switch (faceConeSize) { 4513 case 3: 4514 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4515 break; 4516 case 4: 4517 ct = DM_POLYTOPE_PYRAMID; 4518 break; 4519 } 4520 } break; 4521 case 6: 4522 ct = DM_POLYTOPE_HEXAHEDRON; 4523 break; 4524 default: 4525 break; 4526 } 4527 break; 4528 default: 4529 break; 4530 } 4531 } else if (pheight > 0) { 4532 switch (coneSize) { 4533 case 2: 4534 ct = DM_POLYTOPE_SEGMENT; 4535 break; 4536 case 3: 4537 ct = DM_POLYTOPE_TRIANGLE; 4538 break; 4539 case 4: 4540 ct = DM_POLYTOPE_QUADRILATERAL; 4541 break; 4542 default: 4543 break; 4544 } 4545 } 4546 } 4547 *pt = ct; 4548 PetscFunctionReturn(PETSC_SUCCESS); 4549 } 4550 4551 /*@ 4552 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4553 4554 Collective 4555 4556 Input Parameter: 4557 . dm - The `DMPLEX` 4558 4559 Level: developer 4560 4561 Note: 4562 This function is normally called automatically when a cell type is requested. It creates an 4563 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4564 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4565 4566 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4567 4568 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4569 @*/ 4570 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4571 { 4572 DM_Plex *mesh; 4573 DMLabel ctLabel; 4574 PetscInt pStart, pEnd, p; 4575 4576 PetscFunctionBegin; 4577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4578 mesh = (DM_Plex *)dm->data; 4579 PetscCall(DMCreateLabel(dm, "celltype")); 4580 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4581 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4582 PetscCall(PetscFree(mesh->cellTypes)); 4583 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4584 for (p = pStart; p < pEnd; ++p) { 4585 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4586 PetscInt pdepth; 4587 4588 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4589 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4590 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4591 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4592 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4593 } 4594 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4595 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4596 PetscFunctionReturn(PETSC_SUCCESS); 4597 } 4598 4599 /*@C 4600 DMPlexGetJoin - Get an array for the join of the set of points 4601 4602 Not Collective 4603 4604 Input Parameters: 4605 + dm - The `DMPLEX` object 4606 . numPoints - The number of input points for the join 4607 - points - The input points 4608 4609 Output Parameters: 4610 + numCoveredPoints - The number of points in the join 4611 - coveredPoints - The points in the join 4612 4613 Level: intermediate 4614 4615 Note: 4616 Currently, this is restricted to a single level join 4617 4618 Fortran Notes: 4619 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4620 4621 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4622 @*/ 4623 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4624 { 4625 DM_Plex *mesh = (DM_Plex *)dm->data; 4626 PetscInt *join[2]; 4627 PetscInt joinSize, i = 0; 4628 PetscInt dof, off, p, c, m; 4629 PetscInt maxSupportSize; 4630 4631 PetscFunctionBegin; 4632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4633 PetscAssertPointer(points, 3); 4634 PetscAssertPointer(numCoveredPoints, 4); 4635 PetscAssertPointer(coveredPoints, 5); 4636 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4637 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4638 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4639 /* Copy in support of first point */ 4640 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4641 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4642 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4643 /* Check each successive support */ 4644 for (p = 1; p < numPoints; ++p) { 4645 PetscInt newJoinSize = 0; 4646 4647 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4648 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4649 for (c = 0; c < dof; ++c) { 4650 const PetscInt point = mesh->supports[off + c]; 4651 4652 for (m = 0; m < joinSize; ++m) { 4653 if (point == join[i][m]) { 4654 join[1 - i][newJoinSize++] = point; 4655 break; 4656 } 4657 } 4658 } 4659 joinSize = newJoinSize; 4660 i = 1 - i; 4661 } 4662 *numCoveredPoints = joinSize; 4663 *coveredPoints = join[i]; 4664 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4665 PetscFunctionReturn(PETSC_SUCCESS); 4666 } 4667 4668 /*@C 4669 DMPlexRestoreJoin - Restore an array for the join of the set of points 4670 4671 Not Collective 4672 4673 Input Parameters: 4674 + dm - The `DMPLEX` object 4675 . numPoints - The number of input points for the join 4676 - points - The input points 4677 4678 Output Parameters: 4679 + numCoveredPoints - The number of points in the join 4680 - coveredPoints - The points in the join 4681 4682 Level: intermediate 4683 4684 Fortran Notes: 4685 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4686 4687 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4688 @*/ 4689 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4690 { 4691 PetscFunctionBegin; 4692 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4693 if (points) PetscAssertPointer(points, 3); 4694 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4695 PetscAssertPointer(coveredPoints, 5); 4696 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4697 if (numCoveredPoints) *numCoveredPoints = 0; 4698 PetscFunctionReturn(PETSC_SUCCESS); 4699 } 4700 4701 /*@C 4702 DMPlexGetFullJoin - Get an array for the join of the set of points 4703 4704 Not Collective 4705 4706 Input Parameters: 4707 + dm - The `DMPLEX` object 4708 . numPoints - The number of input points for the join 4709 - points - The input points 4710 4711 Output Parameters: 4712 + numCoveredPoints - The number of points in the join 4713 - coveredPoints - The points in the join 4714 4715 Level: intermediate 4716 4717 Fortran Notes: 4718 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4719 4720 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4721 @*/ 4722 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4723 { 4724 PetscInt *offsets, **closures; 4725 PetscInt *join[2]; 4726 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4727 PetscInt p, d, c, m, ms; 4728 4729 PetscFunctionBegin; 4730 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4731 PetscAssertPointer(points, 3); 4732 PetscAssertPointer(numCoveredPoints, 4); 4733 PetscAssertPointer(coveredPoints, 5); 4734 4735 PetscCall(DMPlexGetDepth(dm, &depth)); 4736 PetscCall(PetscCalloc1(numPoints, &closures)); 4737 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4738 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4739 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4740 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4741 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4742 4743 for (p = 0; p < numPoints; ++p) { 4744 PetscInt closureSize; 4745 4746 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4747 4748 offsets[p * (depth + 2) + 0] = 0; 4749 for (d = 0; d < depth + 1; ++d) { 4750 PetscInt pStart, pEnd, i; 4751 4752 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4753 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4754 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4755 offsets[p * (depth + 2) + d + 1] = i; 4756 break; 4757 } 4758 } 4759 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4760 } 4761 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); 4762 } 4763 for (d = 0; d < depth + 1; ++d) { 4764 PetscInt dof; 4765 4766 /* Copy in support of first point */ 4767 dof = offsets[d + 1] - offsets[d]; 4768 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4769 /* Check each successive cone */ 4770 for (p = 1; p < numPoints && joinSize; ++p) { 4771 PetscInt newJoinSize = 0; 4772 4773 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4774 for (c = 0; c < dof; ++c) { 4775 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4776 4777 for (m = 0; m < joinSize; ++m) { 4778 if (point == join[i][m]) { 4779 join[1 - i][newJoinSize++] = point; 4780 break; 4781 } 4782 } 4783 } 4784 joinSize = newJoinSize; 4785 i = 1 - i; 4786 } 4787 if (joinSize) break; 4788 } 4789 *numCoveredPoints = joinSize; 4790 *coveredPoints = join[i]; 4791 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4792 PetscCall(PetscFree(closures)); 4793 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4794 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4795 PetscFunctionReturn(PETSC_SUCCESS); 4796 } 4797 4798 /*@C 4799 DMPlexGetMeet - Get an array for the meet of the set of points 4800 4801 Not Collective 4802 4803 Input Parameters: 4804 + dm - The `DMPLEX` object 4805 . numPoints - The number of input points for the meet 4806 - points - The input points 4807 4808 Output Parameters: 4809 + numCoveringPoints - The number of points in the meet 4810 - coveringPoints - The points in the meet 4811 4812 Level: intermediate 4813 4814 Note: 4815 Currently, this is restricted to a single level meet 4816 4817 Fortran Notes: 4818 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4819 4820 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4821 @*/ 4822 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4823 { 4824 DM_Plex *mesh = (DM_Plex *)dm->data; 4825 PetscInt *meet[2]; 4826 PetscInt meetSize, i = 0; 4827 PetscInt dof, off, p, c, m; 4828 PetscInt maxConeSize; 4829 4830 PetscFunctionBegin; 4831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4832 PetscAssertPointer(points, 3); 4833 PetscAssertPointer(numCoveringPoints, 4); 4834 PetscAssertPointer(coveringPoints, 5); 4835 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4836 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4837 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4838 /* Copy in cone of first point */ 4839 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4840 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4841 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4842 /* Check each successive cone */ 4843 for (p = 1; p < numPoints; ++p) { 4844 PetscInt newMeetSize = 0; 4845 4846 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4847 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4848 for (c = 0; c < dof; ++c) { 4849 const PetscInt point = mesh->cones[off + c]; 4850 4851 for (m = 0; m < meetSize; ++m) { 4852 if (point == meet[i][m]) { 4853 meet[1 - i][newMeetSize++] = point; 4854 break; 4855 } 4856 } 4857 } 4858 meetSize = newMeetSize; 4859 i = 1 - i; 4860 } 4861 *numCoveringPoints = meetSize; 4862 *coveringPoints = meet[i]; 4863 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4864 PetscFunctionReturn(PETSC_SUCCESS); 4865 } 4866 4867 /*@C 4868 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4869 4870 Not Collective 4871 4872 Input Parameters: 4873 + dm - The `DMPLEX` object 4874 . numPoints - The number of input points for the meet 4875 - points - The input points 4876 4877 Output Parameters: 4878 + numCoveredPoints - The number of points in the meet 4879 - coveredPoints - The points in the meet 4880 4881 Level: intermediate 4882 4883 Fortran Notes: 4884 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4885 4886 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4887 @*/ 4888 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4889 { 4890 PetscFunctionBegin; 4891 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4892 if (points) PetscAssertPointer(points, 3); 4893 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4894 PetscAssertPointer(coveredPoints, 5); 4895 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4896 if (numCoveredPoints) *numCoveredPoints = 0; 4897 PetscFunctionReturn(PETSC_SUCCESS); 4898 } 4899 4900 /*@C 4901 DMPlexGetFullMeet - Get an array for the meet of the set of points 4902 4903 Not Collective 4904 4905 Input Parameters: 4906 + dm - The `DMPLEX` object 4907 . numPoints - The number of input points for the meet 4908 - points - The input points 4909 4910 Output Parameters: 4911 + numCoveredPoints - The number of points in the meet 4912 - coveredPoints - The points in the meet 4913 4914 Level: intermediate 4915 4916 Fortran Notes: 4917 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4918 4919 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4920 @*/ 4921 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4922 { 4923 PetscInt *offsets, **closures; 4924 PetscInt *meet[2]; 4925 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4926 PetscInt p, h, c, m, mc; 4927 4928 PetscFunctionBegin; 4929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4930 PetscAssertPointer(points, 3); 4931 PetscAssertPointer(numCoveredPoints, 4); 4932 PetscAssertPointer(coveredPoints, 5); 4933 4934 PetscCall(DMPlexGetDepth(dm, &height)); 4935 PetscCall(PetscMalloc1(numPoints, &closures)); 4936 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4937 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4938 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4939 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4940 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4941 4942 for (p = 0; p < numPoints; ++p) { 4943 PetscInt closureSize; 4944 4945 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4946 4947 offsets[p * (height + 2) + 0] = 0; 4948 for (h = 0; h < height + 1; ++h) { 4949 PetscInt pStart, pEnd, i; 4950 4951 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4952 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4953 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4954 offsets[p * (height + 2) + h + 1] = i; 4955 break; 4956 } 4957 } 4958 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4959 } 4960 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); 4961 } 4962 for (h = 0; h < height + 1; ++h) { 4963 PetscInt dof; 4964 4965 /* Copy in cone of first point */ 4966 dof = offsets[h + 1] - offsets[h]; 4967 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4968 /* Check each successive cone */ 4969 for (p = 1; p < numPoints && meetSize; ++p) { 4970 PetscInt newMeetSize = 0; 4971 4972 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4973 for (c = 0; c < dof; ++c) { 4974 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4975 4976 for (m = 0; m < meetSize; ++m) { 4977 if (point == meet[i][m]) { 4978 meet[1 - i][newMeetSize++] = point; 4979 break; 4980 } 4981 } 4982 } 4983 meetSize = newMeetSize; 4984 i = 1 - i; 4985 } 4986 if (meetSize) break; 4987 } 4988 *numCoveredPoints = meetSize; 4989 *coveredPoints = meet[i]; 4990 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4991 PetscCall(PetscFree(closures)); 4992 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4993 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4994 PetscFunctionReturn(PETSC_SUCCESS); 4995 } 4996 4997 /*@C 4998 DMPlexEqual - Determine if two `DM` have the same topology 4999 5000 Not Collective 5001 5002 Input Parameters: 5003 + dmA - A `DMPLEX` object 5004 - dmB - A `DMPLEX` object 5005 5006 Output Parameter: 5007 . equal - `PETSC_TRUE` if the topologies are identical 5008 5009 Level: intermediate 5010 5011 Note: 5012 We are not solving graph isomorphism, so we do not permute. 5013 5014 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5015 @*/ 5016 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5017 { 5018 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5019 5020 PetscFunctionBegin; 5021 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5022 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5023 PetscAssertPointer(equal, 3); 5024 5025 *equal = PETSC_FALSE; 5026 PetscCall(DMPlexGetDepth(dmA, &depth)); 5027 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5028 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5029 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5030 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5031 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5032 for (p = pStart; p < pEnd; ++p) { 5033 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5034 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5035 5036 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5037 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5038 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5039 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5040 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5041 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5042 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5043 for (c = 0; c < coneSize; ++c) { 5044 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5045 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5046 } 5047 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5048 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5049 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5050 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5051 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5052 for (s = 0; s < supportSize; ++s) { 5053 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5054 } 5055 } 5056 *equal = PETSC_TRUE; 5057 PetscFunctionReturn(PETSC_SUCCESS); 5058 } 5059 5060 /*@C 5061 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5062 5063 Not Collective 5064 5065 Input Parameters: 5066 + dm - The `DMPLEX` 5067 . cellDim - The cell dimension 5068 - numCorners - The number of vertices on a cell 5069 5070 Output Parameter: 5071 . numFaceVertices - The number of vertices on a face 5072 5073 Level: developer 5074 5075 Note: 5076 Of course this can only work for a restricted set of symmetric shapes 5077 5078 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5079 @*/ 5080 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5081 { 5082 MPI_Comm comm; 5083 5084 PetscFunctionBegin; 5085 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5086 PetscAssertPointer(numFaceVertices, 4); 5087 switch (cellDim) { 5088 case 0: 5089 *numFaceVertices = 0; 5090 break; 5091 case 1: 5092 *numFaceVertices = 1; 5093 break; 5094 case 2: 5095 switch (numCorners) { 5096 case 3: /* triangle */ 5097 *numFaceVertices = 2; /* Edge has 2 vertices */ 5098 break; 5099 case 4: /* quadrilateral */ 5100 *numFaceVertices = 2; /* Edge has 2 vertices */ 5101 break; 5102 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5103 *numFaceVertices = 3; /* Edge has 3 vertices */ 5104 break; 5105 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5106 *numFaceVertices = 3; /* Edge has 3 vertices */ 5107 break; 5108 default: 5109 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5110 } 5111 break; 5112 case 3: 5113 switch (numCorners) { 5114 case 4: /* tetradehdron */ 5115 *numFaceVertices = 3; /* Face has 3 vertices */ 5116 break; 5117 case 6: /* tet cohesive cells */ 5118 *numFaceVertices = 4; /* Face has 4 vertices */ 5119 break; 5120 case 8: /* hexahedron */ 5121 *numFaceVertices = 4; /* Face has 4 vertices */ 5122 break; 5123 case 9: /* tet cohesive Lagrange cells */ 5124 *numFaceVertices = 6; /* Face has 6 vertices */ 5125 break; 5126 case 10: /* quadratic tetrahedron */ 5127 *numFaceVertices = 6; /* Face has 6 vertices */ 5128 break; 5129 case 12: /* hex cohesive Lagrange cells */ 5130 *numFaceVertices = 6; /* Face has 6 vertices */ 5131 break; 5132 case 18: /* quadratic tet cohesive Lagrange cells */ 5133 *numFaceVertices = 6; /* Face has 6 vertices */ 5134 break; 5135 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5136 *numFaceVertices = 9; /* Face has 9 vertices */ 5137 break; 5138 default: 5139 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5140 } 5141 break; 5142 default: 5143 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5144 } 5145 PetscFunctionReturn(PETSC_SUCCESS); 5146 } 5147 5148 /*@ 5149 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5150 5151 Not Collective 5152 5153 Input Parameter: 5154 . dm - The `DMPLEX` object 5155 5156 Output Parameter: 5157 . depthLabel - The `DMLabel` recording point depth 5158 5159 Level: developer 5160 5161 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5162 @*/ 5163 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5164 { 5165 PetscFunctionBegin; 5166 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5167 PetscAssertPointer(depthLabel, 2); 5168 *depthLabel = dm->depthLabel; 5169 PetscFunctionReturn(PETSC_SUCCESS); 5170 } 5171 5172 /*@ 5173 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5174 5175 Not Collective 5176 5177 Input Parameter: 5178 . dm - The `DMPLEX` object 5179 5180 Output Parameter: 5181 . depth - The number of strata (breadth first levels) in the DAG 5182 5183 Level: developer 5184 5185 Notes: 5186 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5187 5188 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5189 5190 An empty mesh gives -1. 5191 5192 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5193 @*/ 5194 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5195 { 5196 DM_Plex *mesh = (DM_Plex *)dm->data; 5197 DMLabel label; 5198 PetscInt d = 0; 5199 5200 PetscFunctionBegin; 5201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5202 PetscAssertPointer(depth, 2); 5203 if (mesh->tr) { 5204 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5205 } else { 5206 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5207 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5208 *depth = d - 1; 5209 } 5210 PetscFunctionReturn(PETSC_SUCCESS); 5211 } 5212 5213 /*@ 5214 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5215 5216 Not Collective 5217 5218 Input Parameters: 5219 + dm - The `DMPLEX` object 5220 - depth - The requested depth 5221 5222 Output Parameters: 5223 + start - The first point at this `depth` 5224 - end - One beyond the last point at this `depth` 5225 5226 Level: developer 5227 5228 Notes: 5229 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5230 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5231 higher dimension, e.g., "edges". 5232 5233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5234 @*/ 5235 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5236 { 5237 DM_Plex *mesh = (DM_Plex *)dm->data; 5238 DMLabel label; 5239 PetscInt pStart, pEnd; 5240 5241 PetscFunctionBegin; 5242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5243 if (start) { 5244 PetscAssertPointer(start, 3); 5245 *start = 0; 5246 } 5247 if (end) { 5248 PetscAssertPointer(end, 4); 5249 *end = 0; 5250 } 5251 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5252 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5253 if (depth < 0) { 5254 if (start) *start = pStart; 5255 if (end) *end = pEnd; 5256 PetscFunctionReturn(PETSC_SUCCESS); 5257 } 5258 if (mesh->tr) { 5259 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5260 } else { 5261 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5262 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5263 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5264 } 5265 PetscFunctionReturn(PETSC_SUCCESS); 5266 } 5267 5268 /*@ 5269 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5270 5271 Not Collective 5272 5273 Input Parameters: 5274 + dm - The `DMPLEX` object 5275 - height - The requested height 5276 5277 Output Parameters: 5278 + start - The first point at this `height` 5279 - end - One beyond the last point at this `height` 5280 5281 Level: developer 5282 5283 Notes: 5284 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5285 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5286 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5287 5288 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5289 @*/ 5290 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5291 { 5292 DMLabel label; 5293 PetscInt depth, pStart, pEnd; 5294 5295 PetscFunctionBegin; 5296 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5297 if (start) { 5298 PetscAssertPointer(start, 3); 5299 *start = 0; 5300 } 5301 if (end) { 5302 PetscAssertPointer(end, 4); 5303 *end = 0; 5304 } 5305 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5306 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5307 if (height < 0) { 5308 if (start) *start = pStart; 5309 if (end) *end = pEnd; 5310 PetscFunctionReturn(PETSC_SUCCESS); 5311 } 5312 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5313 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5314 else PetscCall(DMGetDimension(dm, &depth)); 5315 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5316 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5317 PetscFunctionReturn(PETSC_SUCCESS); 5318 } 5319 5320 /*@ 5321 DMPlexGetPointDepth - Get the `depth` of a given point 5322 5323 Not Collective 5324 5325 Input Parameters: 5326 + dm - The `DMPLEX` object 5327 - point - The point 5328 5329 Output Parameter: 5330 . depth - The depth of the `point` 5331 5332 Level: intermediate 5333 5334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5335 @*/ 5336 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5337 { 5338 PetscFunctionBegin; 5339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5340 PetscAssertPointer(depth, 3); 5341 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5342 PetscFunctionReturn(PETSC_SUCCESS); 5343 } 5344 5345 /*@ 5346 DMPlexGetPointHeight - Get the `height` of a given point 5347 5348 Not Collective 5349 5350 Input Parameters: 5351 + dm - The `DMPLEX` object 5352 - point - The point 5353 5354 Output Parameter: 5355 . height - The height of the `point` 5356 5357 Level: intermediate 5358 5359 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5360 @*/ 5361 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5362 { 5363 PetscInt n, pDepth; 5364 5365 PetscFunctionBegin; 5366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5367 PetscAssertPointer(height, 3); 5368 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5369 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5370 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5371 PetscFunctionReturn(PETSC_SUCCESS); 5372 } 5373 5374 /*@ 5375 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5376 5377 Not Collective 5378 5379 Input Parameter: 5380 . dm - The `DMPLEX` object 5381 5382 Output Parameter: 5383 . celltypeLabel - The `DMLabel` recording cell polytope type 5384 5385 Level: developer 5386 5387 Note: 5388 This function will trigger automatica computation of cell types. This can be disabled by calling 5389 `DMCreateLabel`(dm, "celltype") beforehand. 5390 5391 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5392 @*/ 5393 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5394 { 5395 PetscFunctionBegin; 5396 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5397 PetscAssertPointer(celltypeLabel, 2); 5398 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5399 *celltypeLabel = dm->celltypeLabel; 5400 PetscFunctionReturn(PETSC_SUCCESS); 5401 } 5402 5403 /*@ 5404 DMPlexGetCellType - Get the polytope type of a given cell 5405 5406 Not Collective 5407 5408 Input Parameters: 5409 + dm - The `DMPLEX` object 5410 - cell - The cell 5411 5412 Output Parameter: 5413 . celltype - The polytope type of the cell 5414 5415 Level: intermediate 5416 5417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5418 @*/ 5419 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5420 { 5421 DM_Plex *mesh = (DM_Plex *)dm->data; 5422 DMLabel label; 5423 PetscInt ct; 5424 5425 PetscFunctionBegin; 5426 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5427 PetscAssertPointer(celltype, 3); 5428 if (mesh->tr) { 5429 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5430 } else { 5431 PetscInt pStart, pEnd; 5432 5433 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5434 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5435 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5436 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5437 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5438 for (PetscInt p = pStart; p < pEnd; p++) { 5439 PetscCall(DMLabelGetValue(label, p, &ct)); 5440 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5441 } 5442 } 5443 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5444 if (PetscDefined(USE_DEBUG)) { 5445 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5446 PetscCall(DMLabelGetValue(label, cell, &ct)); 5447 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5448 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5449 } 5450 } 5451 PetscFunctionReturn(PETSC_SUCCESS); 5452 } 5453 5454 /*@ 5455 DMPlexSetCellType - Set the polytope type of a given cell 5456 5457 Not Collective 5458 5459 Input Parameters: 5460 + dm - The `DMPLEX` object 5461 . cell - The cell 5462 - celltype - The polytope type of the cell 5463 5464 Level: advanced 5465 5466 Note: 5467 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5468 is executed. This function will override the computed type. However, if automatic classification will not succeed 5469 and a user wants to manually specify all types, the classification must be disabled by calling 5470 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5471 5472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5473 @*/ 5474 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5475 { 5476 DM_Plex *mesh = (DM_Plex *)dm->data; 5477 DMLabel label; 5478 PetscInt pStart, pEnd; 5479 5480 PetscFunctionBegin; 5481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5482 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5483 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5484 PetscCall(DMLabelSetValue(label, cell, celltype)); 5485 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5486 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5487 PetscFunctionReturn(PETSC_SUCCESS); 5488 } 5489 5490 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5491 { 5492 PetscSection section, s; 5493 Mat m; 5494 PetscInt maxHeight; 5495 const char *prefix; 5496 5497 PetscFunctionBegin; 5498 PetscCall(DMClone(dm, cdm)); 5499 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5500 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5501 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5502 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5503 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5504 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5505 PetscCall(DMSetLocalSection(*cdm, section)); 5506 PetscCall(PetscSectionDestroy(§ion)); 5507 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5508 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5509 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5510 PetscCall(PetscSectionDestroy(&s)); 5511 PetscCall(MatDestroy(&m)); 5512 5513 PetscCall(DMSetNumFields(*cdm, 1)); 5514 PetscCall(DMCreateDS(*cdm)); 5515 (*cdm)->cloneOpts = PETSC_TRUE; 5516 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5517 PetscFunctionReturn(PETSC_SUCCESS); 5518 } 5519 5520 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5521 { 5522 Vec coordsLocal, cellCoordsLocal; 5523 DM coordsDM, cellCoordsDM; 5524 5525 PetscFunctionBegin; 5526 *field = NULL; 5527 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5528 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5529 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5530 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5531 if (coordsLocal && coordsDM) { 5532 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5533 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5534 } 5535 PetscFunctionReturn(PETSC_SUCCESS); 5536 } 5537 5538 /*@C 5539 DMPlexGetConeSection - Return a section which describes the layout of cone data 5540 5541 Not Collective 5542 5543 Input Parameter: 5544 . dm - The `DMPLEX` object 5545 5546 Output Parameter: 5547 . section - The `PetscSection` object 5548 5549 Level: developer 5550 5551 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5552 @*/ 5553 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5554 { 5555 DM_Plex *mesh = (DM_Plex *)dm->data; 5556 5557 PetscFunctionBegin; 5558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5559 if (section) *section = mesh->coneSection; 5560 PetscFunctionReturn(PETSC_SUCCESS); 5561 } 5562 5563 /*@C 5564 DMPlexGetSupportSection - Return a section which describes the layout of support data 5565 5566 Not Collective 5567 5568 Input Parameter: 5569 . dm - The `DMPLEX` object 5570 5571 Output Parameter: 5572 . section - The `PetscSection` object 5573 5574 Level: developer 5575 5576 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5577 @*/ 5578 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5579 { 5580 DM_Plex *mesh = (DM_Plex *)dm->data; 5581 5582 PetscFunctionBegin; 5583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5584 if (section) *section = mesh->supportSection; 5585 PetscFunctionReturn(PETSC_SUCCESS); 5586 } 5587 5588 /*@C 5589 DMPlexGetCones - Return cone data 5590 5591 Not Collective 5592 5593 Input Parameter: 5594 . dm - The `DMPLEX` object 5595 5596 Output Parameter: 5597 . cones - The cone for each point 5598 5599 Level: developer 5600 5601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5602 @*/ 5603 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5604 { 5605 DM_Plex *mesh = (DM_Plex *)dm->data; 5606 5607 PetscFunctionBegin; 5608 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5609 if (cones) *cones = mesh->cones; 5610 PetscFunctionReturn(PETSC_SUCCESS); 5611 } 5612 5613 /*@C 5614 DMPlexGetConeOrientations - Return cone orientation data 5615 5616 Not Collective 5617 5618 Input Parameter: 5619 . dm - The `DMPLEX` object 5620 5621 Output Parameter: 5622 . coneOrientations - The array of cone orientations for all points 5623 5624 Level: developer 5625 5626 Notes: 5627 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5628 5629 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5630 5631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5632 @*/ 5633 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5634 { 5635 DM_Plex *mesh = (DM_Plex *)dm->data; 5636 5637 PetscFunctionBegin; 5638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5639 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5640 PetscFunctionReturn(PETSC_SUCCESS); 5641 } 5642 5643 /******************************** FEM Support **********************************/ 5644 5645 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5646 { 5647 PetscInt depth; 5648 5649 PetscFunctionBegin; 5650 PetscCall(DMPlexGetDepth(plex, &depth)); 5651 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5652 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5653 PetscFunctionReturn(PETSC_SUCCESS); 5654 } 5655 5656 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5657 { 5658 PetscInt depth; 5659 5660 PetscFunctionBegin; 5661 PetscCall(DMPlexGetDepth(plex, &depth)); 5662 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5663 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5664 PetscFunctionReturn(PETSC_SUCCESS); 5665 } 5666 5667 /* 5668 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5669 representing a line in the section. 5670 */ 5671 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous) 5672 { 5673 PetscObject obj; 5674 PetscClassId id; 5675 PetscFE fe = NULL; 5676 5677 PetscFunctionBeginHot; 5678 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5679 PetscCall(DMGetField(dm, field, NULL, &obj)); 5680 PetscCall(PetscObjectGetClassId(obj, &id)); 5681 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5682 5683 if (!fe) { 5684 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5685 /* An order k SEM disc has k-1 dofs on an edge */ 5686 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5687 *k = *k / *Nc + 1; 5688 } else { 5689 PetscInt dual_space_size, dim; 5690 PetscDualSpace dual_space; 5691 PetscCall(DMGetDimension(dm, &dim)); 5692 PetscCall(PetscFEGetDualSpace(fe, &dual_space)); 5693 PetscCall(PetscDualSpaceGetDimension(dual_space, &dual_space_size)); 5694 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5695 PetscCall(PetscDualSpaceLagrangeGetContinuity(dual_space, continuous)); 5696 } 5697 PetscFunctionReturn(PETSC_SUCCESS); 5698 } 5699 5700 /*@ 5701 5702 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5703 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5704 section provided (or the section of the `DM`). 5705 5706 Input Parameters: 5707 + dm - The `DM` 5708 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5709 - section - The `PetscSection` to reorder, or `NULL` for the default section 5710 5711 Example: 5712 A typical interpolated single-quad mesh might order points as 5713 .vb 5714 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5715 5716 v4 -- e6 -- v3 5717 | | 5718 e7 c0 e8 5719 | | 5720 v1 -- e5 -- v2 5721 .ve 5722 5723 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5724 dofs in the order of points, e.g., 5725 .vb 5726 c0 -> [0,1,2,3] 5727 v1 -> [4] 5728 ... 5729 e5 -> [8, 9] 5730 .ve 5731 5732 which corresponds to the dofs 5733 .vb 5734 6 10 11 7 5735 13 2 3 15 5736 12 0 1 14 5737 4 8 9 5 5738 .ve 5739 5740 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5741 .vb 5742 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5743 .ve 5744 5745 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5746 .vb 5747 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5748 .ve 5749 5750 Level: developer 5751 5752 Notes: 5753 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5754 degree of the basis. 5755 5756 This is required to run with libCEED. 5757 5758 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5759 @*/ 5760 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5761 { 5762 DMLabel label; 5763 PetscInt dim, depth = -1, eStart = -1, Nf; 5764 PetscBool continuous = PETSC_TRUE; 5765 5766 PetscFunctionBegin; 5767 PetscCall(DMGetDimension(dm, &dim)); 5768 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5769 if (point < 0) { 5770 PetscInt sStart, sEnd; 5771 5772 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5773 point = sEnd - sStart ? sStart : point; 5774 } 5775 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5776 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5777 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5778 if (depth == 1) { 5779 eStart = point; 5780 } else if (depth == dim) { 5781 const PetscInt *cone; 5782 5783 PetscCall(DMPlexGetCone(dm, point, &cone)); 5784 if (dim == 2) eStart = cone[0]; 5785 else if (dim == 3) { 5786 const PetscInt *cone2; 5787 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5788 eStart = cone2[0]; 5789 } 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); 5790 } 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); 5791 5792 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5793 for (PetscInt d = 1; d <= dim; d++) { 5794 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5795 PetscInt *perm; 5796 5797 for (f = 0; f < Nf; ++f) { 5798 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5799 size += PetscPowInt(k + 1, d) * Nc; 5800 } 5801 PetscCall(PetscMalloc1(size, &perm)); 5802 for (f = 0; f < Nf; ++f) { 5803 switch (d) { 5804 case 1: 5805 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5806 /* 5807 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5808 We want [ vtx0; edge of length k-1; vtx1 ] 5809 */ 5810 if (continuous) { 5811 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5812 for (i = 0; i < k - 1; i++) 5813 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5814 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5815 foffset = offset; 5816 } else { 5817 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5818 foffset = offset = size; 5819 } 5820 break; 5821 case 2: 5822 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5823 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5824 /* The SEM order is 5825 5826 v_lb, {e_b}, v_rb, 5827 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5828 v_lt, reverse {e_t}, v_rt 5829 */ 5830 if (continuous) { 5831 const PetscInt of = 0; 5832 const PetscInt oeb = of + PetscSqr(k - 1); 5833 const PetscInt oer = oeb + (k - 1); 5834 const PetscInt oet = oer + (k - 1); 5835 const PetscInt oel = oet + (k - 1); 5836 const PetscInt ovlb = oel + (k - 1); 5837 const PetscInt ovrb = ovlb + 1; 5838 const PetscInt ovrt = ovrb + 1; 5839 const PetscInt ovlt = ovrt + 1; 5840 PetscInt o; 5841 5842 /* bottom */ 5843 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5844 for (o = oeb; o < oer; ++o) 5845 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5846 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5847 /* middle */ 5848 for (i = 0; i < k - 1; ++i) { 5849 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5850 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5851 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5852 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5853 } 5854 /* top */ 5855 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5856 for (o = oel - 1; o >= oet; --o) 5857 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5858 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5859 foffset = offset; 5860 } else { 5861 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5862 foffset = offset = size; 5863 } 5864 break; 5865 case 3: 5866 /* The original hex closure is 5867 5868 {c, 5869 f_b, f_t, f_f, f_b, f_r, f_l, 5870 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5871 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5872 */ 5873 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous)); 5874 /* The SEM order is 5875 Bottom Slice 5876 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5877 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5878 v_blb, {e_bb}, v_brb, 5879 5880 Middle Slice (j) 5881 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5882 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5883 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5884 5885 Top Slice 5886 v_tlf, {e_tf}, v_trf, 5887 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5888 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5889 */ 5890 if (continuous) { 5891 const PetscInt oc = 0; 5892 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5893 const PetscInt oft = ofb + PetscSqr(k - 1); 5894 const PetscInt off = oft + PetscSqr(k - 1); 5895 const PetscInt ofk = off + PetscSqr(k - 1); 5896 const PetscInt ofr = ofk + PetscSqr(k - 1); 5897 const PetscInt ofl = ofr + PetscSqr(k - 1); 5898 const PetscInt oebl = ofl + PetscSqr(k - 1); 5899 const PetscInt oebb = oebl + (k - 1); 5900 const PetscInt oebr = oebb + (k - 1); 5901 const PetscInt oebf = oebr + (k - 1); 5902 const PetscInt oetf = oebf + (k - 1); 5903 const PetscInt oetr = oetf + (k - 1); 5904 const PetscInt oetb = oetr + (k - 1); 5905 const PetscInt oetl = oetb + (k - 1); 5906 const PetscInt oerf = oetl + (k - 1); 5907 const PetscInt oelf = oerf + (k - 1); 5908 const PetscInt oelb = oelf + (k - 1); 5909 const PetscInt oerb = oelb + (k - 1); 5910 const PetscInt ovblf = oerb + (k - 1); 5911 const PetscInt ovblb = ovblf + 1; 5912 const PetscInt ovbrb = ovblb + 1; 5913 const PetscInt ovbrf = ovbrb + 1; 5914 const PetscInt ovtlf = ovbrf + 1; 5915 const PetscInt ovtrf = ovtlf + 1; 5916 const PetscInt ovtrb = ovtrf + 1; 5917 const PetscInt ovtlb = ovtrb + 1; 5918 PetscInt o, n; 5919 5920 /* Bottom Slice */ 5921 /* bottom */ 5922 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5923 for (o = oetf - 1; o >= oebf; --o) 5924 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5925 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5926 /* middle */ 5927 for (i = 0; i < k - 1; ++i) { 5928 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5929 for (n = 0; n < k - 1; ++n) { 5930 o = ofb + n * (k - 1) + i; 5931 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5932 } 5933 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5934 } 5935 /* top */ 5936 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5937 for (o = oebb; o < oebr; ++o) 5938 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5939 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5940 5941 /* Middle Slice */ 5942 for (j = 0; j < k - 1; ++j) { 5943 /* bottom */ 5944 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5945 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5946 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5947 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5948 /* middle */ 5949 for (i = 0; i < k - 1; ++i) { 5950 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5951 for (n = 0; n < k - 1; ++n) 5952 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5953 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5954 } 5955 /* top */ 5956 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5957 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5958 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5959 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5960 } 5961 5962 /* Top Slice */ 5963 /* bottom */ 5964 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5965 for (o = oetf; o < oetr; ++o) 5966 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5967 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5968 /* middle */ 5969 for (i = 0; i < k - 1; ++i) { 5970 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5971 for (n = 0; n < k - 1; ++n) 5972 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5973 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5974 } 5975 /* top */ 5976 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5977 for (o = oetl - 1; o >= oetb; --o) 5978 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5979 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5980 5981 foffset = offset; 5982 } else { 5983 for (i = offset; i < size; i++) perm[i] = i - offset + foffset; 5984 foffset = offset = size; 5985 } 5986 break; 5987 default: 5988 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5989 } 5990 } 5991 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5992 /* Check permutation */ 5993 { 5994 PetscInt *check; 5995 5996 PetscCall(PetscMalloc1(size, &check)); 5997 for (i = 0; i < size; ++i) { 5998 check[i] = -1; 5999 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6000 } 6001 for (i = 0; i < size; ++i) check[perm[i]] = i; 6002 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6003 PetscCall(PetscFree(check)); 6004 } 6005 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6006 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6007 PetscInt *loc_perm; 6008 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6009 for (PetscInt i = 0; i < size; i++) { 6010 loc_perm[i] = perm[i]; 6011 loc_perm[size + i] = size + perm[i]; 6012 } 6013 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6014 } 6015 } 6016 PetscFunctionReturn(PETSC_SUCCESS); 6017 } 6018 6019 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6020 { 6021 PetscDS prob; 6022 PetscInt depth, Nf, h; 6023 DMLabel label; 6024 6025 PetscFunctionBeginHot; 6026 PetscCall(DMGetDS(dm, &prob)); 6027 Nf = prob->Nf; 6028 label = dm->depthLabel; 6029 *dspace = NULL; 6030 if (field < Nf) { 6031 PetscObject disc = prob->disc[field]; 6032 6033 if (disc->classid == PETSCFE_CLASSID) { 6034 PetscDualSpace dsp; 6035 6036 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6037 PetscCall(DMLabelGetNumValues(label, &depth)); 6038 PetscCall(DMLabelGetValue(label, point, &h)); 6039 h = depth - 1 - h; 6040 if (h) { 6041 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6042 } else { 6043 *dspace = dsp; 6044 } 6045 } 6046 } 6047 PetscFunctionReturn(PETSC_SUCCESS); 6048 } 6049 6050 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6051 { 6052 PetscScalar *array; 6053 const PetscScalar *vArray; 6054 const PetscInt *cone, *coneO; 6055 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6056 6057 PetscFunctionBeginHot; 6058 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6059 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6060 PetscCall(DMPlexGetCone(dm, point, &cone)); 6061 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6062 if (!values || !*values) { 6063 if ((point >= pStart) && (point < pEnd)) { 6064 PetscInt dof; 6065 6066 PetscCall(PetscSectionGetDof(section, point, &dof)); 6067 size += dof; 6068 } 6069 for (p = 0; p < numPoints; ++p) { 6070 const PetscInt cp = cone[p]; 6071 PetscInt dof; 6072 6073 if ((cp < pStart) || (cp >= pEnd)) continue; 6074 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6075 size += dof; 6076 } 6077 if (!values) { 6078 if (csize) *csize = size; 6079 PetscFunctionReturn(PETSC_SUCCESS); 6080 } 6081 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6082 } else { 6083 array = *values; 6084 } 6085 size = 0; 6086 PetscCall(VecGetArrayRead(v, &vArray)); 6087 if ((point >= pStart) && (point < pEnd)) { 6088 PetscInt dof, off, d; 6089 const PetscScalar *varr; 6090 6091 PetscCall(PetscSectionGetDof(section, point, &dof)); 6092 PetscCall(PetscSectionGetOffset(section, point, &off)); 6093 varr = &vArray[off]; 6094 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6095 size += dof; 6096 } 6097 for (p = 0; p < numPoints; ++p) { 6098 const PetscInt cp = cone[p]; 6099 PetscInt o = coneO[p]; 6100 PetscInt dof, off, d; 6101 const PetscScalar *varr; 6102 6103 if ((cp < pStart) || (cp >= pEnd)) continue; 6104 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6105 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6106 varr = &vArray[off]; 6107 if (o >= 0) { 6108 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6109 } else { 6110 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6111 } 6112 size += dof; 6113 } 6114 PetscCall(VecRestoreArrayRead(v, &vArray)); 6115 if (!*values) { 6116 if (csize) *csize = size; 6117 *values = array; 6118 } else { 6119 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6120 *csize = size; 6121 } 6122 PetscFunctionReturn(PETSC_SUCCESS); 6123 } 6124 6125 /* Compress out points not in the section */ 6126 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6127 { 6128 const PetscInt np = *numPoints; 6129 PetscInt pStart, pEnd, p, q; 6130 6131 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6132 for (p = 0, q = 0; p < np; ++p) { 6133 const PetscInt r = points[p * 2]; 6134 if ((r >= pStart) && (r < pEnd)) { 6135 points[q * 2] = r; 6136 points[q * 2 + 1] = points[p * 2 + 1]; 6137 ++q; 6138 } 6139 } 6140 *numPoints = q; 6141 return PETSC_SUCCESS; 6142 } 6143 6144 /* Compressed closure does not apply closure permutation */ 6145 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6146 { 6147 const PetscInt *cla = NULL; 6148 PetscInt np, *pts = NULL; 6149 6150 PetscFunctionBeginHot; 6151 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6152 if (!ornt && *clPoints) { 6153 PetscInt dof, off; 6154 6155 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6156 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6157 PetscCall(ISGetIndices(*clPoints, &cla)); 6158 np = dof / 2; 6159 pts = (PetscInt *)&cla[off]; 6160 } else { 6161 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6162 PetscCall(CompressPoints_Private(section, &np, pts)); 6163 } 6164 *numPoints = np; 6165 *points = pts; 6166 *clp = cla; 6167 PetscFunctionReturn(PETSC_SUCCESS); 6168 } 6169 6170 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6171 { 6172 PetscFunctionBeginHot; 6173 if (!*clPoints) { 6174 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6175 } else { 6176 PetscCall(ISRestoreIndices(*clPoints, clp)); 6177 } 6178 *numPoints = 0; 6179 *points = NULL; 6180 *clSec = NULL; 6181 *clPoints = NULL; 6182 *clp = NULL; 6183 PetscFunctionReturn(PETSC_SUCCESS); 6184 } 6185 6186 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6187 { 6188 PetscInt offset = 0, p; 6189 const PetscInt **perms = NULL; 6190 const PetscScalar **flips = NULL; 6191 6192 PetscFunctionBeginHot; 6193 *size = 0; 6194 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6195 for (p = 0; p < numPoints; p++) { 6196 const PetscInt point = points[2 * p]; 6197 const PetscInt *perm = perms ? perms[p] : NULL; 6198 const PetscScalar *flip = flips ? flips[p] : NULL; 6199 PetscInt dof, off, d; 6200 const PetscScalar *varr; 6201 6202 PetscCall(PetscSectionGetDof(section, point, &dof)); 6203 PetscCall(PetscSectionGetOffset(section, point, &off)); 6204 varr = &vArray[off]; 6205 if (clperm) { 6206 if (perm) { 6207 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6208 } else { 6209 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6210 } 6211 if (flip) { 6212 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6213 } 6214 } else { 6215 if (perm) { 6216 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6217 } else { 6218 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6219 } 6220 if (flip) { 6221 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6222 } 6223 } 6224 offset += dof; 6225 } 6226 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6227 *size = offset; 6228 PetscFunctionReturn(PETSC_SUCCESS); 6229 } 6230 6231 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[]) 6232 { 6233 PetscInt offset = 0, f; 6234 6235 PetscFunctionBeginHot; 6236 *size = 0; 6237 for (f = 0; f < numFields; ++f) { 6238 PetscInt p; 6239 const PetscInt **perms = NULL; 6240 const PetscScalar **flips = NULL; 6241 6242 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6243 for (p = 0; p < numPoints; p++) { 6244 const PetscInt point = points[2 * p]; 6245 PetscInt fdof, foff, b; 6246 const PetscScalar *varr; 6247 const PetscInt *perm = perms ? perms[p] : NULL; 6248 const PetscScalar *flip = flips ? flips[p] : NULL; 6249 6250 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6251 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6252 varr = &vArray[foff]; 6253 if (clperm) { 6254 if (perm) { 6255 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6256 } else { 6257 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6258 } 6259 if (flip) { 6260 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6261 } 6262 } else { 6263 if (perm) { 6264 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6265 } else { 6266 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6267 } 6268 if (flip) { 6269 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6270 } 6271 } 6272 offset += fdof; 6273 } 6274 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6275 } 6276 *size = offset; 6277 PetscFunctionReturn(PETSC_SUCCESS); 6278 } 6279 6280 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6281 { 6282 PetscSection clSection; 6283 IS clPoints; 6284 PetscInt *points = NULL; 6285 const PetscInt *clp, *perm = NULL; 6286 PetscInt depth, numFields, numPoints, asize; 6287 6288 PetscFunctionBeginHot; 6289 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6290 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6291 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6292 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6293 PetscCall(DMPlexGetDepth(dm, &depth)); 6294 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6295 if (depth == 1 && numFields < 2) { 6296 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6297 PetscFunctionReturn(PETSC_SUCCESS); 6298 } 6299 /* Get points */ 6300 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6301 /* Get sizes */ 6302 asize = 0; 6303 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6304 PetscInt dof; 6305 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6306 asize += dof; 6307 } 6308 if (values) { 6309 const PetscScalar *vArray; 6310 PetscInt size; 6311 6312 if (*values) { 6313 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); 6314 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6315 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6316 PetscCall(VecGetArrayRead(v, &vArray)); 6317 /* Get values */ 6318 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6319 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6320 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6321 /* Cleanup array */ 6322 PetscCall(VecRestoreArrayRead(v, &vArray)); 6323 } 6324 if (csize) *csize = asize; 6325 /* Cleanup points */ 6326 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6327 PetscFunctionReturn(PETSC_SUCCESS); 6328 } 6329 6330 /*@C 6331 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6332 6333 Not collective 6334 6335 Input Parameters: 6336 + dm - The `DM` 6337 . section - The section describing the layout in `v`, or `NULL` to use the default section 6338 . v - The local vector 6339 - point - The point in the `DM` 6340 6341 Input/Output Parameters: 6342 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6343 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6344 if the user provided `NULL`, it is a borrowed array and should not be freed 6345 6346 Level: intermediate 6347 6348 Notes: 6349 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6350 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6351 assembly function, and a user may already have allocated storage for this operation. 6352 6353 A typical use could be 6354 .vb 6355 values = NULL; 6356 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6357 for (cl = 0; cl < clSize; ++cl) { 6358 <Compute on closure> 6359 } 6360 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6361 .ve 6362 or 6363 .vb 6364 PetscMalloc1(clMaxSize, &values); 6365 for (p = pStart; p < pEnd; ++p) { 6366 clSize = clMaxSize; 6367 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6368 for (cl = 0; cl < clSize; ++cl) { 6369 <Compute on closure> 6370 } 6371 } 6372 PetscFree(values); 6373 .ve 6374 6375 Fortran Notes: 6376 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6377 6378 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6379 @*/ 6380 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6381 { 6382 PetscFunctionBeginHot; 6383 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6384 PetscFunctionReturn(PETSC_SUCCESS); 6385 } 6386 6387 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6388 { 6389 DMLabel depthLabel; 6390 PetscSection clSection; 6391 IS clPoints; 6392 PetscScalar *array; 6393 const PetscScalar *vArray; 6394 PetscInt *points = NULL; 6395 const PetscInt *clp, *perm = NULL; 6396 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6397 6398 PetscFunctionBeginHot; 6399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6400 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6401 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6402 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6403 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6404 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6405 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6406 if (mdepth == 1 && numFields < 2) { 6407 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6408 PetscFunctionReturn(PETSC_SUCCESS); 6409 } 6410 /* Get points */ 6411 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6412 for (clsize = 0, p = 0; p < Np; p++) { 6413 PetscInt dof; 6414 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6415 clsize += dof; 6416 } 6417 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6418 /* Filter points */ 6419 for (p = 0; p < numPoints * 2; p += 2) { 6420 PetscInt dep; 6421 6422 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6423 if (dep != depth) continue; 6424 points[Np * 2 + 0] = points[p]; 6425 points[Np * 2 + 1] = points[p + 1]; 6426 ++Np; 6427 } 6428 /* Get array */ 6429 if (!values || !*values) { 6430 PetscInt asize = 0, dof; 6431 6432 for (p = 0; p < Np * 2; p += 2) { 6433 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6434 asize += dof; 6435 } 6436 if (!values) { 6437 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6438 if (csize) *csize = asize; 6439 PetscFunctionReturn(PETSC_SUCCESS); 6440 } 6441 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6442 } else { 6443 array = *values; 6444 } 6445 PetscCall(VecGetArrayRead(v, &vArray)); 6446 /* Get values */ 6447 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6448 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6449 /* Cleanup points */ 6450 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6451 /* Cleanup array */ 6452 PetscCall(VecRestoreArrayRead(v, &vArray)); 6453 if (!*values) { 6454 if (csize) *csize = size; 6455 *values = array; 6456 } else { 6457 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6458 *csize = size; 6459 } 6460 PetscFunctionReturn(PETSC_SUCCESS); 6461 } 6462 6463 /*@C 6464 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6465 6466 Not collective 6467 6468 Input Parameters: 6469 + dm - The `DM` 6470 . section - The section describing the layout in `v`, or `NULL` to use the default section 6471 . v - The local vector 6472 . point - The point in the `DM` 6473 . csize - The number of values in the closure, or `NULL` 6474 - values - The array of values, which is a borrowed array and should not be freed 6475 6476 Level: intermediate 6477 6478 Note: 6479 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6480 6481 Fortran Notes: 6482 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6483 6484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6485 @*/ 6486 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6487 { 6488 PetscInt size = 0; 6489 6490 PetscFunctionBegin; 6491 /* Should work without recalculating size */ 6492 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6493 *values = NULL; 6494 PetscFunctionReturn(PETSC_SUCCESS); 6495 } 6496 6497 static inline void add(PetscScalar *x, PetscScalar y) 6498 { 6499 *x += y; 6500 } 6501 static inline void insert(PetscScalar *x, PetscScalar y) 6502 { 6503 *x = y; 6504 } 6505 6506 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[]) 6507 { 6508 PetscInt cdof; /* The number of constraints on this point */ 6509 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6510 PetscScalar *a; 6511 PetscInt off, cind = 0, k; 6512 6513 PetscFunctionBegin; 6514 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6515 PetscCall(PetscSectionGetOffset(section, point, &off)); 6516 a = &array[off]; 6517 if (!cdof || setBC) { 6518 if (clperm) { 6519 if (perm) { 6520 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6521 } else { 6522 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6523 } 6524 } else { 6525 if (perm) { 6526 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6527 } else { 6528 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6529 } 6530 } 6531 } else { 6532 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6533 if (clperm) { 6534 if (perm) { 6535 for (k = 0; k < dof; ++k) { 6536 if ((cind < cdof) && (k == cdofs[cind])) { 6537 ++cind; 6538 continue; 6539 } 6540 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6541 } 6542 } else { 6543 for (k = 0; k < dof; ++k) { 6544 if ((cind < cdof) && (k == cdofs[cind])) { 6545 ++cind; 6546 continue; 6547 } 6548 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6549 } 6550 } 6551 } else { 6552 if (perm) { 6553 for (k = 0; k < dof; ++k) { 6554 if ((cind < cdof) && (k == cdofs[cind])) { 6555 ++cind; 6556 continue; 6557 } 6558 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6559 } 6560 } else { 6561 for (k = 0; k < dof; ++k) { 6562 if ((cind < cdof) && (k == cdofs[cind])) { 6563 ++cind; 6564 continue; 6565 } 6566 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6567 } 6568 } 6569 } 6570 } 6571 PetscFunctionReturn(PETSC_SUCCESS); 6572 } 6573 6574 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[]) 6575 { 6576 PetscInt cdof; /* The number of constraints on this point */ 6577 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6578 PetscScalar *a; 6579 PetscInt off, cind = 0, k; 6580 6581 PetscFunctionBegin; 6582 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6583 PetscCall(PetscSectionGetOffset(section, point, &off)); 6584 a = &array[off]; 6585 if (cdof) { 6586 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6587 if (clperm) { 6588 if (perm) { 6589 for (k = 0; k < dof; ++k) { 6590 if ((cind < cdof) && (k == cdofs[cind])) { 6591 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6592 cind++; 6593 } 6594 } 6595 } else { 6596 for (k = 0; k < dof; ++k) { 6597 if ((cind < cdof) && (k == cdofs[cind])) { 6598 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6599 cind++; 6600 } 6601 } 6602 } 6603 } else { 6604 if (perm) { 6605 for (k = 0; k < dof; ++k) { 6606 if ((cind < cdof) && (k == cdofs[cind])) { 6607 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6608 cind++; 6609 } 6610 } 6611 } else { 6612 for (k = 0; k < dof; ++k) { 6613 if ((cind < cdof) && (k == cdofs[cind])) { 6614 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6615 cind++; 6616 } 6617 } 6618 } 6619 } 6620 } 6621 PetscFunctionReturn(PETSC_SUCCESS); 6622 } 6623 6624 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[]) 6625 { 6626 PetscScalar *a; 6627 PetscInt fdof, foff, fcdof, foffset = *offset; 6628 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6629 PetscInt cind = 0, b; 6630 6631 PetscFunctionBegin; 6632 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6633 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6634 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6635 a = &array[foff]; 6636 if (!fcdof || setBC) { 6637 if (clperm) { 6638 if (perm) { 6639 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6640 } else { 6641 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6642 } 6643 } else { 6644 if (perm) { 6645 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6646 } else { 6647 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6648 } 6649 } 6650 } else { 6651 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6652 if (clperm) { 6653 if (perm) { 6654 for (b = 0; b < fdof; b++) { 6655 if ((cind < fcdof) && (b == fcdofs[cind])) { 6656 ++cind; 6657 continue; 6658 } 6659 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6660 } 6661 } else { 6662 for (b = 0; b < fdof; b++) { 6663 if ((cind < fcdof) && (b == fcdofs[cind])) { 6664 ++cind; 6665 continue; 6666 } 6667 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6668 } 6669 } 6670 } else { 6671 if (perm) { 6672 for (b = 0; b < fdof; b++) { 6673 if ((cind < fcdof) && (b == fcdofs[cind])) { 6674 ++cind; 6675 continue; 6676 } 6677 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6678 } 6679 } else { 6680 for (b = 0; b < fdof; b++) { 6681 if ((cind < fcdof) && (b == fcdofs[cind])) { 6682 ++cind; 6683 continue; 6684 } 6685 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6686 } 6687 } 6688 } 6689 } 6690 *offset += fdof; 6691 PetscFunctionReturn(PETSC_SUCCESS); 6692 } 6693 6694 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[]) 6695 { 6696 PetscScalar *a; 6697 PetscInt fdof, foff, fcdof, foffset = *offset; 6698 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6699 PetscInt Nc, cind = 0, ncind = 0, b; 6700 PetscBool ncSet, fcSet; 6701 6702 PetscFunctionBegin; 6703 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6704 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6705 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6706 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6707 a = &array[foff]; 6708 if (fcdof) { 6709 /* We just override fcdof and fcdofs with Ncc and comps */ 6710 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6711 if (clperm) { 6712 if (perm) { 6713 if (comps) { 6714 for (b = 0; b < fdof; b++) { 6715 ncSet = fcSet = PETSC_FALSE; 6716 if (b % Nc == comps[ncind]) { 6717 ncind = (ncind + 1) % Ncc; 6718 ncSet = PETSC_TRUE; 6719 } 6720 if ((cind < fcdof) && (b == fcdofs[cind])) { 6721 ++cind; 6722 fcSet = PETSC_TRUE; 6723 } 6724 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6725 } 6726 } else { 6727 for (b = 0; b < fdof; b++) { 6728 if ((cind < fcdof) && (b == fcdofs[cind])) { 6729 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6730 ++cind; 6731 } 6732 } 6733 } 6734 } else { 6735 if (comps) { 6736 for (b = 0; b < fdof; b++) { 6737 ncSet = fcSet = PETSC_FALSE; 6738 if (b % Nc == comps[ncind]) { 6739 ncind = (ncind + 1) % Ncc; 6740 ncSet = PETSC_TRUE; 6741 } 6742 if ((cind < fcdof) && (b == fcdofs[cind])) { 6743 ++cind; 6744 fcSet = PETSC_TRUE; 6745 } 6746 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6747 } 6748 } else { 6749 for (b = 0; b < fdof; b++) { 6750 if ((cind < fcdof) && (b == fcdofs[cind])) { 6751 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6752 ++cind; 6753 } 6754 } 6755 } 6756 } 6757 } else { 6758 if (perm) { 6759 if (comps) { 6760 for (b = 0; b < fdof; b++) { 6761 ncSet = fcSet = PETSC_FALSE; 6762 if (b % Nc == comps[ncind]) { 6763 ncind = (ncind + 1) % Ncc; 6764 ncSet = PETSC_TRUE; 6765 } 6766 if ((cind < fcdof) && (b == fcdofs[cind])) { 6767 ++cind; 6768 fcSet = PETSC_TRUE; 6769 } 6770 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6771 } 6772 } else { 6773 for (b = 0; b < fdof; b++) { 6774 if ((cind < fcdof) && (b == fcdofs[cind])) { 6775 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6776 ++cind; 6777 } 6778 } 6779 } 6780 } else { 6781 if (comps) { 6782 for (b = 0; b < fdof; b++) { 6783 ncSet = fcSet = PETSC_FALSE; 6784 if (b % Nc == comps[ncind]) { 6785 ncind = (ncind + 1) % Ncc; 6786 ncSet = PETSC_TRUE; 6787 } 6788 if ((cind < fcdof) && (b == fcdofs[cind])) { 6789 ++cind; 6790 fcSet = PETSC_TRUE; 6791 } 6792 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6793 } 6794 } else { 6795 for (b = 0; b < fdof; b++) { 6796 if ((cind < fcdof) && (b == fcdofs[cind])) { 6797 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6798 ++cind; 6799 } 6800 } 6801 } 6802 } 6803 } 6804 } 6805 *offset += fdof; 6806 PetscFunctionReturn(PETSC_SUCCESS); 6807 } 6808 6809 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6810 { 6811 PetscScalar *array; 6812 const PetscInt *cone, *coneO; 6813 PetscInt pStart, pEnd, p, numPoints, off, dof; 6814 6815 PetscFunctionBeginHot; 6816 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6817 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6818 PetscCall(DMPlexGetCone(dm, point, &cone)); 6819 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6820 PetscCall(VecGetArray(v, &array)); 6821 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6822 const PetscInt cp = !p ? point : cone[p - 1]; 6823 const PetscInt o = !p ? 0 : coneO[p - 1]; 6824 6825 if ((cp < pStart) || (cp >= pEnd)) { 6826 dof = 0; 6827 continue; 6828 } 6829 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6830 /* ADD_VALUES */ 6831 { 6832 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6833 PetscScalar *a; 6834 PetscInt cdof, coff, cind = 0, k; 6835 6836 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6837 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6838 a = &array[coff]; 6839 if (!cdof) { 6840 if (o >= 0) { 6841 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6842 } else { 6843 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6844 } 6845 } else { 6846 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6847 if (o >= 0) { 6848 for (k = 0; k < dof; ++k) { 6849 if ((cind < cdof) && (k == cdofs[cind])) { 6850 ++cind; 6851 continue; 6852 } 6853 a[k] += values[off + k]; 6854 } 6855 } else { 6856 for (k = 0; k < dof; ++k) { 6857 if ((cind < cdof) && (k == cdofs[cind])) { 6858 ++cind; 6859 continue; 6860 } 6861 a[k] += values[off + dof - k - 1]; 6862 } 6863 } 6864 } 6865 } 6866 } 6867 PetscCall(VecRestoreArray(v, &array)); 6868 PetscFunctionReturn(PETSC_SUCCESS); 6869 } 6870 6871 /*@C 6872 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6873 6874 Not collective 6875 6876 Input Parameters: 6877 + dm - The `DM` 6878 . section - The section describing the layout in `v`, or `NULL` to use the default section 6879 . v - The local vector 6880 . point - The point in the `DM` 6881 . values - The array of values 6882 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6883 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6884 6885 Level: intermediate 6886 6887 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6888 @*/ 6889 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6890 { 6891 PetscSection clSection; 6892 IS clPoints; 6893 PetscScalar *array; 6894 PetscInt *points = NULL; 6895 const PetscInt *clp, *clperm = NULL; 6896 PetscInt depth, numFields, numPoints, p, clsize; 6897 6898 PetscFunctionBeginHot; 6899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6900 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6901 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6902 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6903 PetscCall(DMPlexGetDepth(dm, &depth)); 6904 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6905 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6906 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6907 PetscFunctionReturn(PETSC_SUCCESS); 6908 } 6909 /* Get points */ 6910 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6911 for (clsize = 0, p = 0; p < numPoints; p++) { 6912 PetscInt dof; 6913 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6914 clsize += dof; 6915 } 6916 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6917 /* Get array */ 6918 PetscCall(VecGetArray(v, &array)); 6919 /* Get values */ 6920 if (numFields > 0) { 6921 PetscInt offset = 0, f; 6922 for (f = 0; f < numFields; ++f) { 6923 const PetscInt **perms = NULL; 6924 const PetscScalar **flips = NULL; 6925 6926 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6927 switch (mode) { 6928 case INSERT_VALUES: 6929 for (p = 0; p < numPoints; p++) { 6930 const PetscInt point = points[2 * p]; 6931 const PetscInt *perm = perms ? perms[p] : NULL; 6932 const PetscScalar *flip = flips ? flips[p] : NULL; 6933 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6934 } 6935 break; 6936 case INSERT_ALL_VALUES: 6937 for (p = 0; p < numPoints; p++) { 6938 const PetscInt point = points[2 * p]; 6939 const PetscInt *perm = perms ? perms[p] : NULL; 6940 const PetscScalar *flip = flips ? flips[p] : NULL; 6941 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6942 } 6943 break; 6944 case INSERT_BC_VALUES: 6945 for (p = 0; p < numPoints; p++) { 6946 const PetscInt point = points[2 * p]; 6947 const PetscInt *perm = perms ? perms[p] : NULL; 6948 const PetscScalar *flip = flips ? flips[p] : NULL; 6949 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6950 } 6951 break; 6952 case ADD_VALUES: 6953 for (p = 0; p < numPoints; p++) { 6954 const PetscInt point = points[2 * p]; 6955 const PetscInt *perm = perms ? perms[p] : NULL; 6956 const PetscScalar *flip = flips ? flips[p] : NULL; 6957 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6958 } 6959 break; 6960 case ADD_ALL_VALUES: 6961 for (p = 0; p < numPoints; p++) { 6962 const PetscInt point = points[2 * p]; 6963 const PetscInt *perm = perms ? perms[p] : NULL; 6964 const PetscScalar *flip = flips ? flips[p] : NULL; 6965 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6966 } 6967 break; 6968 case ADD_BC_VALUES: 6969 for (p = 0; p < numPoints; p++) { 6970 const PetscInt point = points[2 * p]; 6971 const PetscInt *perm = perms ? perms[p] : NULL; 6972 const PetscScalar *flip = flips ? flips[p] : NULL; 6973 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6974 } 6975 break; 6976 default: 6977 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6978 } 6979 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6980 } 6981 } else { 6982 PetscInt dof, off; 6983 const PetscInt **perms = NULL; 6984 const PetscScalar **flips = NULL; 6985 6986 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6987 switch (mode) { 6988 case INSERT_VALUES: 6989 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6990 const PetscInt point = points[2 * p]; 6991 const PetscInt *perm = perms ? perms[p] : NULL; 6992 const PetscScalar *flip = flips ? flips[p] : NULL; 6993 PetscCall(PetscSectionGetDof(section, point, &dof)); 6994 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6995 } 6996 break; 6997 case INSERT_ALL_VALUES: 6998 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6999 const PetscInt point = points[2 * p]; 7000 const PetscInt *perm = perms ? perms[p] : NULL; 7001 const PetscScalar *flip = flips ? flips[p] : NULL; 7002 PetscCall(PetscSectionGetDof(section, point, &dof)); 7003 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7004 } 7005 break; 7006 case INSERT_BC_VALUES: 7007 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7008 const PetscInt point = points[2 * p]; 7009 const PetscInt *perm = perms ? perms[p] : NULL; 7010 const PetscScalar *flip = flips ? flips[p] : NULL; 7011 PetscCall(PetscSectionGetDof(section, point, &dof)); 7012 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7013 } 7014 break; 7015 case ADD_VALUES: 7016 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7017 const PetscInt point = points[2 * p]; 7018 const PetscInt *perm = perms ? perms[p] : NULL; 7019 const PetscScalar *flip = flips ? flips[p] : NULL; 7020 PetscCall(PetscSectionGetDof(section, point, &dof)); 7021 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7022 } 7023 break; 7024 case ADD_ALL_VALUES: 7025 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7026 const PetscInt point = points[2 * p]; 7027 const PetscInt *perm = perms ? perms[p] : NULL; 7028 const PetscScalar *flip = flips ? flips[p] : NULL; 7029 PetscCall(PetscSectionGetDof(section, point, &dof)); 7030 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7031 } 7032 break; 7033 case ADD_BC_VALUES: 7034 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7035 const PetscInt point = points[2 * p]; 7036 const PetscInt *perm = perms ? perms[p] : NULL; 7037 const PetscScalar *flip = flips ? flips[p] : NULL; 7038 PetscCall(PetscSectionGetDof(section, point, &dof)); 7039 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7040 } 7041 break; 7042 default: 7043 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7044 } 7045 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7046 } 7047 /* Cleanup points */ 7048 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7049 /* Cleanup array */ 7050 PetscCall(VecRestoreArray(v, &array)); 7051 PetscFunctionReturn(PETSC_SUCCESS); 7052 } 7053 7054 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7055 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7056 { 7057 PetscFunctionBegin; 7058 *contains = PETSC_TRUE; 7059 if (label) { 7060 PetscInt fdof; 7061 7062 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7063 if (!*contains) { 7064 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7065 *offset += fdof; 7066 PetscFunctionReturn(PETSC_SUCCESS); 7067 } 7068 } 7069 PetscFunctionReturn(PETSC_SUCCESS); 7070 } 7071 7072 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7073 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) 7074 { 7075 PetscSection clSection; 7076 IS clPoints; 7077 PetscScalar *array; 7078 PetscInt *points = NULL; 7079 const PetscInt *clp; 7080 PetscInt numFields, numPoints, p; 7081 PetscInt offset = 0, f; 7082 7083 PetscFunctionBeginHot; 7084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7085 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7086 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7087 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7088 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7089 /* Get points */ 7090 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7091 /* Get array */ 7092 PetscCall(VecGetArray(v, &array)); 7093 /* Get values */ 7094 for (f = 0; f < numFields; ++f) { 7095 const PetscInt **perms = NULL; 7096 const PetscScalar **flips = NULL; 7097 PetscBool contains; 7098 7099 if (!fieldActive[f]) { 7100 for (p = 0; p < numPoints * 2; p += 2) { 7101 PetscInt fdof; 7102 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7103 offset += fdof; 7104 } 7105 continue; 7106 } 7107 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7108 switch (mode) { 7109 case INSERT_VALUES: 7110 for (p = 0; p < numPoints; p++) { 7111 const PetscInt point = points[2 * p]; 7112 const PetscInt *perm = perms ? perms[p] : NULL; 7113 const PetscScalar *flip = flips ? flips[p] : NULL; 7114 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7115 if (!contains) continue; 7116 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7117 } 7118 break; 7119 case INSERT_ALL_VALUES: 7120 for (p = 0; p < numPoints; p++) { 7121 const PetscInt point = points[2 * p]; 7122 const PetscInt *perm = perms ? perms[p] : NULL; 7123 const PetscScalar *flip = flips ? flips[p] : NULL; 7124 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7125 if (!contains) continue; 7126 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7127 } 7128 break; 7129 case INSERT_BC_VALUES: 7130 for (p = 0; p < numPoints; p++) { 7131 const PetscInt point = points[2 * p]; 7132 const PetscInt *perm = perms ? perms[p] : NULL; 7133 const PetscScalar *flip = flips ? flips[p] : NULL; 7134 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7135 if (!contains) continue; 7136 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7137 } 7138 break; 7139 case ADD_VALUES: 7140 for (p = 0; p < numPoints; p++) { 7141 const PetscInt point = points[2 * p]; 7142 const PetscInt *perm = perms ? perms[p] : NULL; 7143 const PetscScalar *flip = flips ? flips[p] : NULL; 7144 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7145 if (!contains) continue; 7146 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7147 } 7148 break; 7149 case ADD_ALL_VALUES: 7150 for (p = 0; p < numPoints; p++) { 7151 const PetscInt point = points[2 * p]; 7152 const PetscInt *perm = perms ? perms[p] : NULL; 7153 const PetscScalar *flip = flips ? flips[p] : NULL; 7154 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7155 if (!contains) continue; 7156 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7157 } 7158 break; 7159 default: 7160 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7161 } 7162 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7163 } 7164 /* Cleanup points */ 7165 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7166 /* Cleanup array */ 7167 PetscCall(VecRestoreArray(v, &array)); 7168 PetscFunctionReturn(PETSC_SUCCESS); 7169 } 7170 7171 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7172 { 7173 PetscMPIInt rank; 7174 PetscInt i, j; 7175 7176 PetscFunctionBegin; 7177 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7178 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7179 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7180 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7181 numCIndices = numCIndices ? numCIndices : numRIndices; 7182 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7183 for (i = 0; i < numRIndices; i++) { 7184 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7185 for (j = 0; j < numCIndices; j++) { 7186 #if defined(PETSC_USE_COMPLEX) 7187 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7188 #else 7189 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7190 #endif 7191 } 7192 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7193 } 7194 PetscFunctionReturn(PETSC_SUCCESS); 7195 } 7196 7197 /* 7198 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7199 7200 Input Parameters: 7201 + section - The section for this data layout 7202 . islocal - Is the section (and thus indices being requested) local or global? 7203 . point - The point contributing dofs with these indices 7204 . off - The global offset of this point 7205 . loff - The local offset of each field 7206 . setBC - The flag determining whether to include indices of boundary values 7207 . perm - A permutation of the dofs on this point, or NULL 7208 - indperm - A permutation of the entire indices array, or NULL 7209 7210 Output Parameter: 7211 . indices - Indices for dofs on this point 7212 7213 Level: developer 7214 7215 Note: The indices could be local or global, depending on the value of 'off'. 7216 */ 7217 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7218 { 7219 PetscInt dof; /* The number of unknowns on this point */ 7220 PetscInt cdof; /* The number of constraints on this point */ 7221 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7222 PetscInt cind = 0, k; 7223 7224 PetscFunctionBegin; 7225 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7226 PetscCall(PetscSectionGetDof(section, point, &dof)); 7227 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7228 if (!cdof || setBC) { 7229 for (k = 0; k < dof; ++k) { 7230 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7231 const PetscInt ind = indperm ? indperm[preind] : preind; 7232 7233 indices[ind] = off + k; 7234 } 7235 } else { 7236 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7237 for (k = 0; k < dof; ++k) { 7238 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7239 const PetscInt ind = indperm ? indperm[preind] : preind; 7240 7241 if ((cind < cdof) && (k == cdofs[cind])) { 7242 /* Insert check for returning constrained indices */ 7243 indices[ind] = -(off + k + 1); 7244 ++cind; 7245 } else { 7246 indices[ind] = off + k - (islocal ? 0 : cind); 7247 } 7248 } 7249 } 7250 *loff += dof; 7251 PetscFunctionReturn(PETSC_SUCCESS); 7252 } 7253 7254 /* 7255 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7256 7257 Input Parameters: 7258 + section - a section (global or local) 7259 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7260 . point - point within section 7261 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7262 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7263 . setBC - identify constrained (boundary condition) points via involution. 7264 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7265 . permsoff - offset 7266 - indperm - index permutation 7267 7268 Output Parameter: 7269 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7270 . indices - array to hold indices (as defined by section) of each dof associated with point 7271 7272 Notes: 7273 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7274 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7275 in the local vector. 7276 7277 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7278 significant). It is invalid to call with a global section and setBC=true. 7279 7280 Developer Note: 7281 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7282 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7283 offset could be obtained from the section instead of passing it explicitly as we do now. 7284 7285 Example: 7286 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7287 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7288 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7289 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. 7290 7291 Level: developer 7292 */ 7293 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[]) 7294 { 7295 PetscInt numFields, foff, f; 7296 7297 PetscFunctionBegin; 7298 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7299 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7300 for (f = 0, foff = 0; f < numFields; ++f) { 7301 PetscInt fdof, cfdof; 7302 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7303 PetscInt cind = 0, b; 7304 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7305 7306 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7307 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7308 if (!cfdof || setBC) { 7309 for (b = 0; b < fdof; ++b) { 7310 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7311 const PetscInt ind = indperm ? indperm[preind] : preind; 7312 7313 indices[ind] = off + foff + b; 7314 } 7315 } else { 7316 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7317 for (b = 0; b < fdof; ++b) { 7318 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7319 const PetscInt ind = indperm ? indperm[preind] : preind; 7320 7321 if ((cind < cfdof) && (b == fcdofs[cind])) { 7322 indices[ind] = -(off + foff + b + 1); 7323 ++cind; 7324 } else { 7325 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7326 } 7327 } 7328 } 7329 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7330 foffs[f] += fdof; 7331 } 7332 PetscFunctionReturn(PETSC_SUCCESS); 7333 } 7334 7335 /* 7336 This version believes the globalSection offsets for each field, rather than just the point offset 7337 7338 . foffs - The offset into 'indices' for each field, since it is segregated by field 7339 7340 Notes: 7341 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7342 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7343 */ 7344 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7345 { 7346 PetscInt numFields, foff, f; 7347 7348 PetscFunctionBegin; 7349 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7350 for (f = 0; f < numFields; ++f) { 7351 PetscInt fdof, cfdof; 7352 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7353 PetscInt cind = 0, b; 7354 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7355 7356 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7357 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7358 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7359 if (!cfdof) { 7360 for (b = 0; b < fdof; ++b) { 7361 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7362 const PetscInt ind = indperm ? indperm[preind] : preind; 7363 7364 indices[ind] = foff + b; 7365 } 7366 } else { 7367 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7368 for (b = 0; b < fdof; ++b) { 7369 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7370 const PetscInt ind = indperm ? indperm[preind] : preind; 7371 7372 if ((cind < cfdof) && (b == fcdofs[cind])) { 7373 indices[ind] = -(foff + b + 1); 7374 ++cind; 7375 } else { 7376 indices[ind] = foff + b - cind; 7377 } 7378 } 7379 } 7380 foffs[f] += fdof; 7381 } 7382 PetscFunctionReturn(PETSC_SUCCESS); 7383 } 7384 7385 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) 7386 { 7387 Mat cMat; 7388 PetscSection aSec, cSec; 7389 IS aIS; 7390 PetscInt aStart = -1, aEnd = -1; 7391 const PetscInt *anchors; 7392 PetscInt numFields, f, p, q, newP = 0; 7393 PetscInt newNumPoints = 0, newNumIndices = 0; 7394 PetscInt *newPoints, *indices, *newIndices; 7395 PetscInt maxAnchor, maxDof; 7396 PetscInt newOffsets[32]; 7397 PetscInt *pointMatOffsets[32]; 7398 PetscInt *newPointOffsets[32]; 7399 PetscScalar *pointMat[32]; 7400 PetscScalar *newValues = NULL, *tmpValues; 7401 PetscBool anyConstrained = PETSC_FALSE; 7402 7403 PetscFunctionBegin; 7404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7405 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7406 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7407 7408 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7409 /* if there are point-to-point constraints */ 7410 if (aSec) { 7411 PetscCall(PetscArrayzero(newOffsets, 32)); 7412 PetscCall(ISGetIndices(aIS, &anchors)); 7413 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7414 /* figure out how many points are going to be in the new element matrix 7415 * (we allow double counting, because it's all just going to be summed 7416 * into the global matrix anyway) */ 7417 for (p = 0; p < 2 * numPoints; p += 2) { 7418 PetscInt b = points[p]; 7419 PetscInt bDof = 0, bSecDof; 7420 7421 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7422 if (!bSecDof) continue; 7423 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7424 if (bDof) { 7425 /* this point is constrained */ 7426 /* it is going to be replaced by its anchors */ 7427 PetscInt bOff, q; 7428 7429 anyConstrained = PETSC_TRUE; 7430 newNumPoints += bDof; 7431 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7432 for (q = 0; q < bDof; q++) { 7433 PetscInt a = anchors[bOff + q]; 7434 PetscInt aDof; 7435 7436 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7437 newNumIndices += aDof; 7438 for (f = 0; f < numFields; ++f) { 7439 PetscInt fDof; 7440 7441 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7442 newOffsets[f + 1] += fDof; 7443 } 7444 } 7445 } else { 7446 /* this point is not constrained */ 7447 newNumPoints++; 7448 newNumIndices += bSecDof; 7449 for (f = 0; f < numFields; ++f) { 7450 PetscInt fDof; 7451 7452 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7453 newOffsets[f + 1] += fDof; 7454 } 7455 } 7456 } 7457 } 7458 if (!anyConstrained) { 7459 if (outNumPoints) *outNumPoints = 0; 7460 if (outNumIndices) *outNumIndices = 0; 7461 if (outPoints) *outPoints = NULL; 7462 if (outValues) *outValues = NULL; 7463 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7464 PetscFunctionReturn(PETSC_SUCCESS); 7465 } 7466 7467 if (outNumPoints) *outNumPoints = newNumPoints; 7468 if (outNumIndices) *outNumIndices = newNumIndices; 7469 7470 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7471 7472 if (!outPoints && !outValues) { 7473 if (offsets) { 7474 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7475 } 7476 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7477 PetscFunctionReturn(PETSC_SUCCESS); 7478 } 7479 7480 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7481 7482 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7483 7484 /* workspaces */ 7485 if (numFields) { 7486 for (f = 0; f < numFields; f++) { 7487 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7488 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7489 } 7490 } else { 7491 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7492 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7493 } 7494 7495 /* get workspaces for the point-to-point matrices */ 7496 if (numFields) { 7497 PetscInt totalOffset, totalMatOffset; 7498 7499 for (p = 0; p < numPoints; p++) { 7500 PetscInt b = points[2 * p]; 7501 PetscInt bDof = 0, bSecDof; 7502 7503 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7504 if (!bSecDof) { 7505 for (f = 0; f < numFields; f++) { 7506 newPointOffsets[f][p + 1] = 0; 7507 pointMatOffsets[f][p + 1] = 0; 7508 } 7509 continue; 7510 } 7511 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7512 if (bDof) { 7513 for (f = 0; f < numFields; f++) { 7514 PetscInt fDof, q, bOff, allFDof = 0; 7515 7516 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7517 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7518 for (q = 0; q < bDof; q++) { 7519 PetscInt a = anchors[bOff + q]; 7520 PetscInt aFDof; 7521 7522 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7523 allFDof += aFDof; 7524 } 7525 newPointOffsets[f][p + 1] = allFDof; 7526 pointMatOffsets[f][p + 1] = fDof * allFDof; 7527 } 7528 } else { 7529 for (f = 0; f < numFields; f++) { 7530 PetscInt fDof; 7531 7532 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7533 newPointOffsets[f][p + 1] = fDof; 7534 pointMatOffsets[f][p + 1] = 0; 7535 } 7536 } 7537 } 7538 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7539 newPointOffsets[f][0] = totalOffset; 7540 pointMatOffsets[f][0] = totalMatOffset; 7541 for (p = 0; p < numPoints; p++) { 7542 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7543 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7544 } 7545 totalOffset = newPointOffsets[f][numPoints]; 7546 totalMatOffset = pointMatOffsets[f][numPoints]; 7547 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7548 } 7549 } else { 7550 for (p = 0; p < numPoints; p++) { 7551 PetscInt b = points[2 * p]; 7552 PetscInt bDof = 0, bSecDof; 7553 7554 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7555 if (!bSecDof) { 7556 newPointOffsets[0][p + 1] = 0; 7557 pointMatOffsets[0][p + 1] = 0; 7558 continue; 7559 } 7560 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7561 if (bDof) { 7562 PetscInt bOff, q, allDof = 0; 7563 7564 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7565 for (q = 0; q < bDof; q++) { 7566 PetscInt a = anchors[bOff + q], aDof; 7567 7568 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7569 allDof += aDof; 7570 } 7571 newPointOffsets[0][p + 1] = allDof; 7572 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7573 } else { 7574 newPointOffsets[0][p + 1] = bSecDof; 7575 pointMatOffsets[0][p + 1] = 0; 7576 } 7577 } 7578 newPointOffsets[0][0] = 0; 7579 pointMatOffsets[0][0] = 0; 7580 for (p = 0; p < numPoints; p++) { 7581 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7582 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7583 } 7584 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7585 } 7586 7587 /* output arrays */ 7588 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7589 7590 /* get the point-to-point matrices; construct newPoints */ 7591 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7592 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7593 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7594 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7595 if (numFields) { 7596 for (p = 0, newP = 0; p < numPoints; p++) { 7597 PetscInt b = points[2 * p]; 7598 PetscInt o = points[2 * p + 1]; 7599 PetscInt bDof = 0, bSecDof; 7600 7601 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7602 if (!bSecDof) continue; 7603 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7604 if (bDof) { 7605 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7606 7607 fStart[0] = 0; 7608 fEnd[0] = 0; 7609 for (f = 0; f < numFields; f++) { 7610 PetscInt fDof; 7611 7612 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7613 fStart[f + 1] = fStart[f] + fDof; 7614 fEnd[f + 1] = fStart[f + 1]; 7615 } 7616 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7617 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7618 7619 fAnchorStart[0] = 0; 7620 fAnchorEnd[0] = 0; 7621 for (f = 0; f < numFields; f++) { 7622 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7623 7624 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7625 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7626 } 7627 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7628 for (q = 0; q < bDof; q++) { 7629 PetscInt a = anchors[bOff + q], aOff; 7630 7631 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7632 newPoints[2 * (newP + q)] = a; 7633 newPoints[2 * (newP + q) + 1] = 0; 7634 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7635 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7636 } 7637 newP += bDof; 7638 7639 if (outValues) { 7640 /* get the point-to-point submatrix */ 7641 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7642 } 7643 } else { 7644 newPoints[2 * newP] = b; 7645 newPoints[2 * newP + 1] = o; 7646 newP++; 7647 } 7648 } 7649 } else { 7650 for (p = 0; p < numPoints; p++) { 7651 PetscInt b = points[2 * p]; 7652 PetscInt o = points[2 * p + 1]; 7653 PetscInt bDof = 0, bSecDof; 7654 7655 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7656 if (!bSecDof) continue; 7657 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7658 if (bDof) { 7659 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7660 7661 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7662 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7663 7664 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7665 for (q = 0; q < bDof; q++) { 7666 PetscInt a = anchors[bOff + q], aOff; 7667 7668 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7669 7670 newPoints[2 * (newP + q)] = a; 7671 newPoints[2 * (newP + q) + 1] = 0; 7672 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7673 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7674 } 7675 newP += bDof; 7676 7677 /* get the point-to-point submatrix */ 7678 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7679 } else { 7680 newPoints[2 * newP] = b; 7681 newPoints[2 * newP + 1] = o; 7682 newP++; 7683 } 7684 } 7685 } 7686 7687 if (outValues) { 7688 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7689 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7690 /* multiply constraints on the right */ 7691 if (numFields) { 7692 for (f = 0; f < numFields; f++) { 7693 PetscInt oldOff = offsets[f]; 7694 7695 for (p = 0; p < numPoints; p++) { 7696 PetscInt cStart = newPointOffsets[f][p]; 7697 PetscInt b = points[2 * p]; 7698 PetscInt c, r, k; 7699 PetscInt dof; 7700 7701 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7702 if (!dof) continue; 7703 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7704 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7705 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7706 7707 for (r = 0; r < numIndices; r++) { 7708 for (c = 0; c < nCols; c++) { 7709 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7710 } 7711 } 7712 } else { 7713 /* copy this column as is */ 7714 for (r = 0; r < numIndices; r++) { 7715 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7716 } 7717 } 7718 oldOff += dof; 7719 } 7720 } 7721 } else { 7722 PetscInt oldOff = 0; 7723 for (p = 0; p < numPoints; p++) { 7724 PetscInt cStart = newPointOffsets[0][p]; 7725 PetscInt b = points[2 * p]; 7726 PetscInt c, r, k; 7727 PetscInt dof; 7728 7729 PetscCall(PetscSectionGetDof(section, b, &dof)); 7730 if (!dof) continue; 7731 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7732 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7733 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7734 7735 for (r = 0; r < numIndices; r++) { 7736 for (c = 0; c < nCols; c++) { 7737 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7738 } 7739 } 7740 } else { 7741 /* copy this column as is */ 7742 for (r = 0; r < numIndices; r++) { 7743 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7744 } 7745 } 7746 oldOff += dof; 7747 } 7748 } 7749 7750 if (multiplyLeft) { 7751 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7752 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7753 /* multiply constraints transpose on the left */ 7754 if (numFields) { 7755 for (f = 0; f < numFields; f++) { 7756 PetscInt oldOff = offsets[f]; 7757 7758 for (p = 0; p < numPoints; p++) { 7759 PetscInt rStart = newPointOffsets[f][p]; 7760 PetscInt b = points[2 * p]; 7761 PetscInt c, r, k; 7762 PetscInt dof; 7763 7764 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7765 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7766 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7767 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7768 7769 for (r = 0; r < nRows; r++) { 7770 for (c = 0; c < newNumIndices; c++) { 7771 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7772 } 7773 } 7774 } else { 7775 /* copy this row as is */ 7776 for (r = 0; r < dof; r++) { 7777 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7778 } 7779 } 7780 oldOff += dof; 7781 } 7782 } 7783 } else { 7784 PetscInt oldOff = 0; 7785 7786 for (p = 0; p < numPoints; p++) { 7787 PetscInt rStart = newPointOffsets[0][p]; 7788 PetscInt b = points[2 * p]; 7789 PetscInt c, r, k; 7790 PetscInt dof; 7791 7792 PetscCall(PetscSectionGetDof(section, b, &dof)); 7793 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7794 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7795 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7796 7797 for (r = 0; r < nRows; r++) { 7798 for (c = 0; c < newNumIndices; c++) { 7799 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7800 } 7801 } 7802 } else { 7803 /* copy this row as is */ 7804 for (r = 0; r < dof; r++) { 7805 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7806 } 7807 } 7808 oldOff += dof; 7809 } 7810 } 7811 7812 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7813 } else { 7814 newValues = tmpValues; 7815 } 7816 } 7817 7818 /* clean up */ 7819 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7820 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7821 7822 if (numFields) { 7823 for (f = 0; f < numFields; f++) { 7824 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7825 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7826 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7827 } 7828 } else { 7829 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7830 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7831 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7832 } 7833 PetscCall(ISRestoreIndices(aIS, &anchors)); 7834 7835 /* output */ 7836 if (outPoints) { 7837 *outPoints = newPoints; 7838 } else { 7839 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7840 } 7841 if (outValues) *outValues = newValues; 7842 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7843 PetscFunctionReturn(PETSC_SUCCESS); 7844 } 7845 7846 /*@C 7847 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7848 7849 Not collective 7850 7851 Input Parameters: 7852 + dm - The `DM` 7853 . section - The `PetscSection` describing the points (a local section) 7854 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7855 . point - The point defining the closure 7856 - useClPerm - Use the closure point permutation if available 7857 7858 Output Parameters: 7859 + numIndices - The number of dof indices in the closure of point with the input sections 7860 . indices - The dof indices 7861 . outOffsets - Array to write the field offsets into, or `NULL` 7862 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7863 7864 Level: advanced 7865 7866 Notes: 7867 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7868 7869 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7870 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7871 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7872 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7873 indices (with the above semantics) are implied. 7874 7875 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7876 `PetscSection`, `DMGetGlobalSection()` 7877 @*/ 7878 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7879 { 7880 /* Closure ordering */ 7881 PetscSection clSection; 7882 IS clPoints; 7883 const PetscInt *clp; 7884 PetscInt *points; 7885 const PetscInt *clperm = NULL; 7886 /* Dof permutation and sign flips */ 7887 const PetscInt **perms[32] = {NULL}; 7888 const PetscScalar **flips[32] = {NULL}; 7889 PetscScalar *valCopy = NULL; 7890 /* Hanging node constraints */ 7891 PetscInt *pointsC = NULL; 7892 PetscScalar *valuesC = NULL; 7893 PetscInt NclC, NiC; 7894 7895 PetscInt *idx; 7896 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7897 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7898 7899 PetscFunctionBeginHot; 7900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7901 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7902 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7903 if (numIndices) PetscAssertPointer(numIndices, 6); 7904 if (indices) PetscAssertPointer(indices, 7); 7905 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7906 if (values) PetscAssertPointer(values, 9); 7907 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7908 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7909 PetscCall(PetscArrayzero(offsets, 32)); 7910 /* 1) Get points in closure */ 7911 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7912 if (useClPerm) { 7913 PetscInt depth, clsize; 7914 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7915 for (clsize = 0, p = 0; p < Ncl; p++) { 7916 PetscInt dof; 7917 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7918 clsize += dof; 7919 } 7920 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7921 } 7922 /* 2) Get number of indices on these points and field offsets from section */ 7923 for (p = 0; p < Ncl * 2; p += 2) { 7924 PetscInt dof, fdof; 7925 7926 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7927 for (f = 0; f < Nf; ++f) { 7928 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7929 offsets[f + 1] += fdof; 7930 } 7931 Ni += dof; 7932 } 7933 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7934 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7935 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7936 for (f = 0; f < PetscMax(1, Nf); ++f) { 7937 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7938 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7939 /* may need to apply sign changes to the element matrix */ 7940 if (values && flips[f]) { 7941 PetscInt foffset = offsets[f]; 7942 7943 for (p = 0; p < Ncl; ++p) { 7944 PetscInt pnt = points[2 * p], fdof; 7945 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7946 7947 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7948 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7949 if (flip) { 7950 PetscInt i, j, k; 7951 7952 if (!valCopy) { 7953 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7954 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7955 *values = valCopy; 7956 } 7957 for (i = 0; i < fdof; ++i) { 7958 PetscScalar fval = flip[i]; 7959 7960 for (k = 0; k < Ni; ++k) { 7961 valCopy[Ni * (foffset + i) + k] *= fval; 7962 valCopy[Ni * k + (foffset + i)] *= fval; 7963 } 7964 } 7965 } 7966 foffset += fdof; 7967 } 7968 } 7969 } 7970 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7971 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7972 if (NclC) { 7973 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7974 for (f = 0; f < PetscMax(1, Nf); ++f) { 7975 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7976 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7977 } 7978 for (f = 0; f < PetscMax(1, Nf); ++f) { 7979 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7980 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7981 } 7982 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7983 Ncl = NclC; 7984 Ni = NiC; 7985 points = pointsC; 7986 if (values) *values = valuesC; 7987 } 7988 /* 5) Calculate indices */ 7989 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7990 if (Nf) { 7991 PetscInt idxOff; 7992 PetscBool useFieldOffsets; 7993 7994 if (outOffsets) { 7995 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7996 } 7997 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7998 if (useFieldOffsets) { 7999 for (p = 0; p < Ncl; ++p) { 8000 const PetscInt pnt = points[p * 2]; 8001 8002 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8003 } 8004 } else { 8005 for (p = 0; p < Ncl; ++p) { 8006 const PetscInt pnt = points[p * 2]; 8007 8008 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8009 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8010 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8011 * global section. */ 8012 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8013 } 8014 } 8015 } else { 8016 PetscInt off = 0, idxOff; 8017 8018 for (p = 0; p < Ncl; ++p) { 8019 const PetscInt pnt = points[p * 2]; 8020 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8021 8022 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8023 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8024 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8025 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8026 } 8027 } 8028 /* 6) Cleanup */ 8029 for (f = 0; f < PetscMax(1, Nf); ++f) { 8030 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8031 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8032 } 8033 if (NclC) { 8034 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8035 } else { 8036 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8037 } 8038 8039 if (numIndices) *numIndices = Ni; 8040 if (indices) *indices = idx; 8041 PetscFunctionReturn(PETSC_SUCCESS); 8042 } 8043 8044 /*@C 8045 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8046 8047 Not collective 8048 8049 Input Parameters: 8050 + dm - The `DM` 8051 . section - The `PetscSection` describing the points (a local section) 8052 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8053 . point - The point defining the closure 8054 - useClPerm - Use the closure point permutation if available 8055 8056 Output Parameters: 8057 + numIndices - The number of dof indices in the closure of point with the input sections 8058 . indices - The dof indices 8059 . outOffsets - Array to write the field offsets into, or `NULL` 8060 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8061 8062 Level: advanced 8063 8064 Notes: 8065 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8066 8067 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8068 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8069 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8070 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8071 indices (with the above semantics) are implied. 8072 8073 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8074 @*/ 8075 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8076 { 8077 PetscFunctionBegin; 8078 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8079 PetscAssertPointer(indices, 7); 8080 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8081 PetscFunctionReturn(PETSC_SUCCESS); 8082 } 8083 8084 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8085 { 8086 DM_Plex *mesh = (DM_Plex *)dm->data; 8087 PetscInt *indices; 8088 PetscInt numIndices; 8089 const PetscScalar *valuesOrig = values; 8090 PetscErrorCode ierr; 8091 8092 PetscFunctionBegin; 8093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8094 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8095 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8096 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8097 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8098 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8099 8100 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8101 8102 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8103 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8104 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8105 if (ierr) { 8106 PetscMPIInt rank; 8107 8108 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8109 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8110 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8111 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8112 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8113 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8114 } 8115 if (mesh->printFEM > 1) { 8116 PetscInt i; 8117 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8118 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8119 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8120 } 8121 8122 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8123 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8124 PetscFunctionReturn(PETSC_SUCCESS); 8125 } 8126 8127 /*@C 8128 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8129 8130 Not collective 8131 8132 Input Parameters: 8133 + dm - The `DM` 8134 . section - The section describing the layout in `v`, or `NULL` to use the default section 8135 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8136 . A - The matrix 8137 . point - The point in the `DM` 8138 . values - The array of values 8139 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8140 8141 Level: intermediate 8142 8143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8144 @*/ 8145 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8146 { 8147 PetscFunctionBegin; 8148 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8149 PetscFunctionReturn(PETSC_SUCCESS); 8150 } 8151 8152 /*@C 8153 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8154 8155 Not collective 8156 8157 Input Parameters: 8158 + dmRow - The `DM` for the row fields 8159 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8160 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8161 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8162 . dmCol - The `DM` for the column fields 8163 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8164 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8165 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8166 . A - The matrix 8167 . point - The point in the `DM` 8168 . values - The array of values 8169 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8170 8171 Level: intermediate 8172 8173 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8174 @*/ 8175 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) 8176 { 8177 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8178 PetscInt *indicesRow, *indicesCol; 8179 PetscInt numIndicesRow, numIndicesCol; 8180 const PetscScalar *valuesOrig = values; 8181 PetscErrorCode ierr; 8182 8183 PetscFunctionBegin; 8184 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8185 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8186 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8187 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8188 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8189 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8190 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8191 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8192 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8193 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8194 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8195 8196 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8197 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8198 8199 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8200 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8201 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8202 if (ierr) { 8203 PetscMPIInt rank; 8204 8205 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8206 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8207 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8208 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8209 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8210 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8211 } 8212 8213 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8214 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8215 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8216 PetscFunctionReturn(PETSC_SUCCESS); 8217 } 8218 8219 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8220 { 8221 DM_Plex *mesh = (DM_Plex *)dmf->data; 8222 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8223 PetscInt *cpoints = NULL; 8224 PetscInt *findices, *cindices; 8225 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8226 PetscInt foffsets[32], coffsets[32]; 8227 DMPolytopeType ct; 8228 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8229 PetscErrorCode ierr; 8230 8231 PetscFunctionBegin; 8232 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8233 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8234 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8235 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8236 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8237 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8238 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8239 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8240 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8241 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8242 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8243 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8244 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8245 PetscCall(PetscArrayzero(foffsets, 32)); 8246 PetscCall(PetscArrayzero(coffsets, 32)); 8247 /* Column indices */ 8248 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8249 maxFPoints = numCPoints; 8250 /* Compress out points not in the section */ 8251 /* TODO: Squeeze out points with 0 dof as well */ 8252 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8253 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8254 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8255 cpoints[q * 2] = cpoints[p]; 8256 cpoints[q * 2 + 1] = cpoints[p + 1]; 8257 ++q; 8258 } 8259 } 8260 numCPoints = q; 8261 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8262 PetscInt fdof; 8263 8264 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8265 if (!dof) continue; 8266 for (f = 0; f < numFields; ++f) { 8267 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8268 coffsets[f + 1] += fdof; 8269 } 8270 numCIndices += dof; 8271 } 8272 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8273 /* Row indices */ 8274 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8275 { 8276 DMPlexTransform tr; 8277 DMPolytopeType *rct; 8278 PetscInt *rsize, *rcone, *rornt, Nt; 8279 8280 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8281 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8282 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8283 numSubcells = rsize[Nt - 1]; 8284 PetscCall(DMPlexTransformDestroy(&tr)); 8285 } 8286 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8287 for (r = 0, q = 0; r < numSubcells; ++r) { 8288 /* TODO Map from coarse to fine cells */ 8289 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8290 /* Compress out points not in the section */ 8291 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8292 for (p = 0; p < numFPoints * 2; p += 2) { 8293 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8294 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8295 if (!dof) continue; 8296 for (s = 0; s < q; ++s) 8297 if (fpoints[p] == ftotpoints[s * 2]) break; 8298 if (s < q) continue; 8299 ftotpoints[q * 2] = fpoints[p]; 8300 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8301 ++q; 8302 } 8303 } 8304 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8305 } 8306 numFPoints = q; 8307 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8308 PetscInt fdof; 8309 8310 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8311 if (!dof) continue; 8312 for (f = 0; f < numFields; ++f) { 8313 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8314 foffsets[f + 1] += fdof; 8315 } 8316 numFIndices += dof; 8317 } 8318 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8319 8320 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8321 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8322 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8323 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8324 if (numFields) { 8325 const PetscInt **permsF[32] = {NULL}; 8326 const PetscInt **permsC[32] = {NULL}; 8327 8328 for (f = 0; f < numFields; f++) { 8329 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8330 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8331 } 8332 for (p = 0; p < numFPoints; p++) { 8333 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8334 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8335 } 8336 for (p = 0; p < numCPoints; p++) { 8337 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8338 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8339 } 8340 for (f = 0; f < numFields; f++) { 8341 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8342 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8343 } 8344 } else { 8345 const PetscInt **permsF = NULL; 8346 const PetscInt **permsC = NULL; 8347 8348 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8349 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8350 for (p = 0, off = 0; p < numFPoints; p++) { 8351 const PetscInt *perm = permsF ? permsF[p] : NULL; 8352 8353 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8354 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8355 } 8356 for (p = 0, off = 0; p < numCPoints; p++) { 8357 const PetscInt *perm = permsC ? permsC[p] : NULL; 8358 8359 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8360 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8361 } 8362 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8363 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8364 } 8365 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8366 /* TODO: flips */ 8367 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8368 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8369 if (ierr) { 8370 PetscMPIInt rank; 8371 8372 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8373 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8374 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8375 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8376 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8377 } 8378 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8379 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8380 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8381 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8382 PetscFunctionReturn(PETSC_SUCCESS); 8383 } 8384 8385 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8386 { 8387 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8388 PetscInt *cpoints = NULL; 8389 PetscInt foffsets[32], coffsets[32]; 8390 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8391 DMPolytopeType ct; 8392 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8393 8394 PetscFunctionBegin; 8395 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8396 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8397 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8398 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8399 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8400 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8401 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8402 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8403 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8404 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8405 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8406 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8407 PetscCall(PetscArrayzero(foffsets, 32)); 8408 PetscCall(PetscArrayzero(coffsets, 32)); 8409 /* Column indices */ 8410 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8411 maxFPoints = numCPoints; 8412 /* Compress out points not in the section */ 8413 /* TODO: Squeeze out points with 0 dof as well */ 8414 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8415 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8416 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8417 cpoints[q * 2] = cpoints[p]; 8418 cpoints[q * 2 + 1] = cpoints[p + 1]; 8419 ++q; 8420 } 8421 } 8422 numCPoints = q; 8423 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8424 PetscInt fdof; 8425 8426 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8427 if (!dof) continue; 8428 for (f = 0; f < numFields; ++f) { 8429 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8430 coffsets[f + 1] += fdof; 8431 } 8432 numCIndices += dof; 8433 } 8434 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8435 /* Row indices */ 8436 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8437 { 8438 DMPlexTransform tr; 8439 DMPolytopeType *rct; 8440 PetscInt *rsize, *rcone, *rornt, Nt; 8441 8442 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8443 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8444 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8445 numSubcells = rsize[Nt - 1]; 8446 PetscCall(DMPlexTransformDestroy(&tr)); 8447 } 8448 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8449 for (r = 0, q = 0; r < numSubcells; ++r) { 8450 /* TODO Map from coarse to fine cells */ 8451 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8452 /* Compress out points not in the section */ 8453 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8454 for (p = 0; p < numFPoints * 2; p += 2) { 8455 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8456 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8457 if (!dof) continue; 8458 for (s = 0; s < q; ++s) 8459 if (fpoints[p] == ftotpoints[s * 2]) break; 8460 if (s < q) continue; 8461 ftotpoints[q * 2] = fpoints[p]; 8462 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8463 ++q; 8464 } 8465 } 8466 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8467 } 8468 numFPoints = q; 8469 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8470 PetscInt fdof; 8471 8472 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8473 if (!dof) continue; 8474 for (f = 0; f < numFields; ++f) { 8475 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8476 foffsets[f + 1] += fdof; 8477 } 8478 numFIndices += dof; 8479 } 8480 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8481 8482 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8483 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8484 if (numFields) { 8485 const PetscInt **permsF[32] = {NULL}; 8486 const PetscInt **permsC[32] = {NULL}; 8487 8488 for (f = 0; f < numFields; f++) { 8489 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8490 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8491 } 8492 for (p = 0; p < numFPoints; p++) { 8493 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8494 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8495 } 8496 for (p = 0; p < numCPoints; p++) { 8497 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8498 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8499 } 8500 for (f = 0; f < numFields; f++) { 8501 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8502 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8503 } 8504 } else { 8505 const PetscInt **permsF = NULL; 8506 const PetscInt **permsC = NULL; 8507 8508 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8509 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8510 for (p = 0, off = 0; p < numFPoints; p++) { 8511 const PetscInt *perm = permsF ? permsF[p] : NULL; 8512 8513 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8514 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8515 } 8516 for (p = 0, off = 0; p < numCPoints; p++) { 8517 const PetscInt *perm = permsC ? permsC[p] : NULL; 8518 8519 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8520 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8521 } 8522 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8523 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8524 } 8525 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8526 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8527 PetscFunctionReturn(PETSC_SUCCESS); 8528 } 8529 8530 /*@C 8531 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8532 8533 Input Parameter: 8534 . dm - The `DMPLEX` object 8535 8536 Output Parameter: 8537 . cellHeight - The height of a cell 8538 8539 Level: developer 8540 8541 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8542 @*/ 8543 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8544 { 8545 DM_Plex *mesh = (DM_Plex *)dm->data; 8546 8547 PetscFunctionBegin; 8548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8549 PetscAssertPointer(cellHeight, 2); 8550 *cellHeight = mesh->vtkCellHeight; 8551 PetscFunctionReturn(PETSC_SUCCESS); 8552 } 8553 8554 /*@C 8555 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8556 8557 Input Parameters: 8558 + dm - The `DMPLEX` object 8559 - cellHeight - The height of a cell 8560 8561 Level: developer 8562 8563 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8564 @*/ 8565 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8566 { 8567 DM_Plex *mesh = (DM_Plex *)dm->data; 8568 8569 PetscFunctionBegin; 8570 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8571 mesh->vtkCellHeight = cellHeight; 8572 PetscFunctionReturn(PETSC_SUCCESS); 8573 } 8574 8575 /*@ 8576 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8577 8578 Input Parameters: 8579 + dm - The `DMPLEX` object 8580 - ct - The `DMPolytopeType` of the cell 8581 8582 Output Parameters: 8583 + start - The first cell of this type, or `NULL` 8584 - end - The upper bound on this celltype, or `NULL` 8585 8586 Level: advanced 8587 8588 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8589 @*/ 8590 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8591 { 8592 DM_Plex *mesh = (DM_Plex *)dm->data; 8593 DMLabel label; 8594 PetscInt pStart, pEnd; 8595 8596 PetscFunctionBegin; 8597 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8598 if (start) { 8599 PetscAssertPointer(start, 3); 8600 *start = 0; 8601 } 8602 if (end) { 8603 PetscAssertPointer(end, 4); 8604 *end = 0; 8605 } 8606 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8607 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8608 if (mesh->tr) { 8609 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8610 } else { 8611 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8612 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8613 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8614 } 8615 PetscFunctionReturn(PETSC_SUCCESS); 8616 } 8617 8618 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8619 { 8620 PetscSection section, globalSection; 8621 PetscInt *numbers, p; 8622 8623 PetscFunctionBegin; 8624 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8625 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8626 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8627 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8628 PetscCall(PetscSectionSetUp(section)); 8629 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8630 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8631 for (p = pStart; p < pEnd; ++p) { 8632 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8633 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8634 else numbers[p - pStart] += shift; 8635 } 8636 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8637 if (globalSize) { 8638 PetscLayout layout; 8639 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8640 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8641 PetscCall(PetscLayoutDestroy(&layout)); 8642 } 8643 PetscCall(PetscSectionDestroy(§ion)); 8644 PetscCall(PetscSectionDestroy(&globalSection)); 8645 PetscFunctionReturn(PETSC_SUCCESS); 8646 } 8647 8648 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8649 { 8650 PetscInt cellHeight, cStart, cEnd; 8651 8652 PetscFunctionBegin; 8653 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8654 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8655 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8656 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8657 PetscFunctionReturn(PETSC_SUCCESS); 8658 } 8659 8660 /*@ 8661 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8662 8663 Input Parameter: 8664 . dm - The `DMPLEX` object 8665 8666 Output Parameter: 8667 . globalCellNumbers - Global cell numbers for all cells on this process 8668 8669 Level: developer 8670 8671 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8672 @*/ 8673 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8674 { 8675 DM_Plex *mesh = (DM_Plex *)dm->data; 8676 8677 PetscFunctionBegin; 8678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8679 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8680 *globalCellNumbers = mesh->globalCellNumbers; 8681 PetscFunctionReturn(PETSC_SUCCESS); 8682 } 8683 8684 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8685 { 8686 PetscInt vStart, vEnd; 8687 8688 PetscFunctionBegin; 8689 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8690 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8691 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8692 PetscFunctionReturn(PETSC_SUCCESS); 8693 } 8694 8695 /*@ 8696 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8697 8698 Input Parameter: 8699 . dm - The `DMPLEX` object 8700 8701 Output Parameter: 8702 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8703 8704 Level: developer 8705 8706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8707 @*/ 8708 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8709 { 8710 DM_Plex *mesh = (DM_Plex *)dm->data; 8711 8712 PetscFunctionBegin; 8713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8714 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8715 *globalVertexNumbers = mesh->globalVertexNumbers; 8716 PetscFunctionReturn(PETSC_SUCCESS); 8717 } 8718 8719 /*@ 8720 DMPlexCreatePointNumbering - Create a global numbering for all points. 8721 8722 Collective 8723 8724 Input Parameter: 8725 . dm - The `DMPLEX` object 8726 8727 Output Parameter: 8728 . globalPointNumbers - Global numbers for all points on this process 8729 8730 Level: developer 8731 8732 Notes: 8733 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8734 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8735 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8736 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8737 8738 The partitioned mesh is 8739 ``` 8740 (2)--0--(3)--1--(4) (1)--0--(2) 8741 ``` 8742 and its global numbering is 8743 ``` 8744 (3)--0--(4)--1--(5)--2--(6) 8745 ``` 8746 Then the global numbering is provided as 8747 ``` 8748 [0] Number of indices in set 5 8749 [0] 0 0 8750 [0] 1 1 8751 [0] 2 3 8752 [0] 3 4 8753 [0] 4 -6 8754 [1] Number of indices in set 3 8755 [1] 0 2 8756 [1] 1 5 8757 [1] 2 6 8758 ``` 8759 8760 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8761 @*/ 8762 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8763 { 8764 IS nums[4]; 8765 PetscInt depths[4], gdepths[4], starts[4]; 8766 PetscInt depth, d, shift = 0; 8767 PetscBool empty = PETSC_FALSE; 8768 8769 PetscFunctionBegin; 8770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8771 PetscCall(DMPlexGetDepth(dm, &depth)); 8772 // For unstratified meshes use dim instead of depth 8773 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8774 // If any stratum is empty, we must mark all empty 8775 for (d = 0; d <= depth; ++d) { 8776 PetscInt end; 8777 8778 depths[d] = depth - d; 8779 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8780 if (!(starts[d] - end)) empty = PETSC_TRUE; 8781 } 8782 if (empty) 8783 for (d = 0; d <= depth; ++d) { 8784 depths[d] = -1; 8785 starts[d] = -1; 8786 } 8787 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8788 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8789 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]); 8790 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8791 for (d = 0; d <= depth; ++d) { 8792 PetscInt pStart, pEnd, gsize; 8793 8794 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8795 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8796 shift += gsize; 8797 } 8798 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8799 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8800 PetscFunctionReturn(PETSC_SUCCESS); 8801 } 8802 8803 /*@ 8804 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8805 8806 Input Parameter: 8807 . dm - The `DMPLEX` object 8808 8809 Output Parameter: 8810 . ranks - The rank field 8811 8812 Options Database Key: 8813 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8814 8815 Level: intermediate 8816 8817 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8818 @*/ 8819 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8820 { 8821 DM rdm; 8822 PetscFE fe; 8823 PetscScalar *r; 8824 PetscMPIInt rank; 8825 DMPolytopeType ct; 8826 PetscInt dim, cStart, cEnd, c; 8827 PetscBool simplex; 8828 8829 PetscFunctionBeginUser; 8830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8831 PetscAssertPointer(ranks, 2); 8832 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8833 PetscCall(DMClone(dm, &rdm)); 8834 PetscCall(DMGetDimension(rdm, &dim)); 8835 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8836 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8837 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8838 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8839 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8840 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8841 PetscCall(PetscFEDestroy(&fe)); 8842 PetscCall(DMCreateDS(rdm)); 8843 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8844 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8845 PetscCall(VecGetArray(*ranks, &r)); 8846 for (c = cStart; c < cEnd; ++c) { 8847 PetscScalar *lr; 8848 8849 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8850 if (lr) *lr = rank; 8851 } 8852 PetscCall(VecRestoreArray(*ranks, &r)); 8853 PetscCall(DMDestroy(&rdm)); 8854 PetscFunctionReturn(PETSC_SUCCESS); 8855 } 8856 8857 /*@ 8858 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8859 8860 Input Parameters: 8861 + dm - The `DMPLEX` 8862 - label - The `DMLabel` 8863 8864 Output Parameter: 8865 . val - The label value field 8866 8867 Options Database Key: 8868 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8869 8870 Level: intermediate 8871 8872 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8873 @*/ 8874 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8875 { 8876 DM rdm; 8877 PetscFE fe; 8878 PetscScalar *v; 8879 PetscInt dim, cStart, cEnd, c; 8880 8881 PetscFunctionBeginUser; 8882 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8883 PetscAssertPointer(label, 2); 8884 PetscAssertPointer(val, 3); 8885 PetscCall(DMClone(dm, &rdm)); 8886 PetscCall(DMGetDimension(rdm, &dim)); 8887 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8888 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8889 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8890 PetscCall(PetscFEDestroy(&fe)); 8891 PetscCall(DMCreateDS(rdm)); 8892 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8893 PetscCall(DMCreateGlobalVector(rdm, val)); 8894 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8895 PetscCall(VecGetArray(*val, &v)); 8896 for (c = cStart; c < cEnd; ++c) { 8897 PetscScalar *lv; 8898 PetscInt cval; 8899 8900 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8901 PetscCall(DMLabelGetValue(label, c, &cval)); 8902 *lv = cval; 8903 } 8904 PetscCall(VecRestoreArray(*val, &v)); 8905 PetscCall(DMDestroy(&rdm)); 8906 PetscFunctionReturn(PETSC_SUCCESS); 8907 } 8908 8909 /*@ 8910 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8911 8912 Input Parameter: 8913 . dm - The `DMPLEX` object 8914 8915 Level: developer 8916 8917 Notes: 8918 This is a useful diagnostic when creating meshes programmatically. 8919 8920 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8921 8922 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8923 @*/ 8924 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8925 { 8926 PetscSection coneSection, supportSection; 8927 const PetscInt *cone, *support; 8928 PetscInt coneSize, c, supportSize, s; 8929 PetscInt pStart, pEnd, p, pp, csize, ssize; 8930 PetscBool storagecheck = PETSC_TRUE; 8931 8932 PetscFunctionBegin; 8933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8934 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8935 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8936 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8937 /* Check that point p is found in the support of its cone points, and vice versa */ 8938 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8939 for (p = pStart; p < pEnd; ++p) { 8940 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8941 PetscCall(DMPlexGetCone(dm, p, &cone)); 8942 for (c = 0; c < coneSize; ++c) { 8943 PetscBool dup = PETSC_FALSE; 8944 PetscInt d; 8945 for (d = c - 1; d >= 0; --d) { 8946 if (cone[c] == cone[d]) { 8947 dup = PETSC_TRUE; 8948 break; 8949 } 8950 } 8951 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8952 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8953 for (s = 0; s < supportSize; ++s) { 8954 if (support[s] == p) break; 8955 } 8956 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8957 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8958 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8959 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8960 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8961 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8962 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8963 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]); 8964 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8965 } 8966 } 8967 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8968 if (p != pp) { 8969 storagecheck = PETSC_FALSE; 8970 continue; 8971 } 8972 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8973 PetscCall(DMPlexGetSupport(dm, p, &support)); 8974 for (s = 0; s < supportSize; ++s) { 8975 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8976 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8977 for (c = 0; c < coneSize; ++c) { 8978 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8979 if (cone[c] != pp) { 8980 c = 0; 8981 break; 8982 } 8983 if (cone[c] == p) break; 8984 } 8985 if (c >= coneSize) { 8986 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8987 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8988 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8989 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8990 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8991 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8992 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8993 } 8994 } 8995 } 8996 if (storagecheck) { 8997 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8998 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8999 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9000 } 9001 PetscFunctionReturn(PETSC_SUCCESS); 9002 } 9003 9004 /* 9005 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. 9006 */ 9007 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9008 { 9009 DMPolytopeType cct; 9010 PetscInt ptpoints[4]; 9011 const PetscInt *cone, *ccone, *ptcone; 9012 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9013 9014 PetscFunctionBegin; 9015 *unsplit = 0; 9016 switch (ct) { 9017 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9018 ptpoints[npt++] = c; 9019 break; 9020 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9021 PetscCall(DMPlexGetCone(dm, c, &cone)); 9022 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9023 for (cp = 0; cp < coneSize; ++cp) { 9024 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9025 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9026 } 9027 break; 9028 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9029 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9030 PetscCall(DMPlexGetCone(dm, c, &cone)); 9031 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9032 for (cp = 0; cp < coneSize; ++cp) { 9033 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9034 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9035 for (ccp = 0; ccp < cconeSize; ++ccp) { 9036 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9037 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9038 PetscInt p; 9039 for (p = 0; p < npt; ++p) 9040 if (ptpoints[p] == ccone[ccp]) break; 9041 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9042 } 9043 } 9044 } 9045 break; 9046 default: 9047 break; 9048 } 9049 for (pt = 0; pt < npt; ++pt) { 9050 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9051 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9052 } 9053 PetscFunctionReturn(PETSC_SUCCESS); 9054 } 9055 9056 /*@ 9057 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9058 9059 Input Parameters: 9060 + dm - The `DMPLEX` object 9061 - cellHeight - Normally 0 9062 9063 Level: developer 9064 9065 Notes: 9066 This is a useful diagnostic when creating meshes programmatically. 9067 Currently applicable only to homogeneous simplex or tensor meshes. 9068 9069 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9070 9071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9072 @*/ 9073 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9074 { 9075 DMPlexInterpolatedFlag interp; 9076 DMPolytopeType ct; 9077 PetscInt vStart, vEnd, cStart, cEnd, c; 9078 9079 PetscFunctionBegin; 9080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9081 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9082 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9083 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9084 for (c = cStart; c < cEnd; ++c) { 9085 PetscInt *closure = NULL; 9086 PetscInt coneSize, closureSize, cl, Nv = 0; 9087 9088 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9089 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9090 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9091 if (interp == DMPLEX_INTERPOLATED_FULL) { 9092 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9093 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)); 9094 } 9095 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9096 for (cl = 0; cl < closureSize * 2; cl += 2) { 9097 const PetscInt p = closure[cl]; 9098 if ((p >= vStart) && (p < vEnd)) ++Nv; 9099 } 9100 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9101 /* Special Case: Tensor faces with identified vertices */ 9102 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9103 PetscInt unsplit; 9104 9105 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9106 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9107 } 9108 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)); 9109 } 9110 PetscFunctionReturn(PETSC_SUCCESS); 9111 } 9112 9113 /*@ 9114 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9115 9116 Collective 9117 9118 Input Parameters: 9119 + dm - The `DMPLEX` object 9120 - cellHeight - Normally 0 9121 9122 Level: developer 9123 9124 Notes: 9125 This is a useful diagnostic when creating meshes programmatically. 9126 This routine is only relevant for meshes that are fully interpolated across all ranks. 9127 It will error out if a partially interpolated mesh is given on some rank. 9128 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9129 9130 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9131 9132 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9133 @*/ 9134 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9135 { 9136 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9137 DMPlexInterpolatedFlag interpEnum; 9138 9139 PetscFunctionBegin; 9140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9141 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9142 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9143 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9144 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9145 PetscFunctionReturn(PETSC_SUCCESS); 9146 } 9147 9148 PetscCall(DMGetDimension(dm, &dim)); 9149 PetscCall(DMPlexGetDepth(dm, &depth)); 9150 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9151 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9152 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9153 for (c = cStart; c < cEnd; ++c) { 9154 const PetscInt *cone, *ornt, *faceSizes, *faces; 9155 const DMPolytopeType *faceTypes; 9156 DMPolytopeType ct; 9157 PetscInt numFaces, coneSize, f; 9158 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9159 9160 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9161 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9162 if (unsplit) continue; 9163 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9164 PetscCall(DMPlexGetCone(dm, c, &cone)); 9165 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9166 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9167 for (cl = 0; cl < closureSize * 2; cl += 2) { 9168 const PetscInt p = closure[cl]; 9169 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9170 } 9171 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9172 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); 9173 for (f = 0; f < numFaces; ++f) { 9174 DMPolytopeType fct; 9175 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9176 9177 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9178 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9179 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9180 const PetscInt p = fclosure[cl]; 9181 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9182 } 9183 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]); 9184 for (v = 0; v < fnumCorners; ++v) { 9185 if (fclosure[v] != faces[fOff + v]) { 9186 PetscInt v1; 9187 9188 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9189 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9190 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9191 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9192 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9193 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]); 9194 } 9195 } 9196 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9197 fOff += faceSizes[f]; 9198 } 9199 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9200 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9201 } 9202 } 9203 PetscFunctionReturn(PETSC_SUCCESS); 9204 } 9205 9206 /*@ 9207 DMPlexCheckGeometry - Check the geometry of mesh cells 9208 9209 Input Parameter: 9210 . dm - The `DMPLEX` object 9211 9212 Level: developer 9213 9214 Notes: 9215 This is a useful diagnostic when creating meshes programmatically. 9216 9217 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9218 9219 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9220 @*/ 9221 PetscErrorCode DMPlexCheckGeometry(DM dm) 9222 { 9223 Vec coordinates; 9224 PetscReal detJ, J[9], refVol = 1.0; 9225 PetscReal vol; 9226 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9227 9228 PetscFunctionBegin; 9229 PetscCall(DMGetDimension(dm, &dim)); 9230 PetscCall(DMGetCoordinateDim(dm, &dE)); 9231 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9232 PetscCall(DMPlexGetDepth(dm, &depth)); 9233 for (d = 0; d < dim; ++d) refVol *= 2.0; 9234 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9235 /* Make sure local coordinates are created, because that step is collective */ 9236 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9237 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9238 for (c = cStart; c < cEnd; ++c) { 9239 DMPolytopeType ct; 9240 PetscInt unsplit; 9241 PetscBool ignoreZeroVol = PETSC_FALSE; 9242 9243 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9244 switch (ct) { 9245 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9246 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9247 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9248 ignoreZeroVol = PETSC_TRUE; 9249 break; 9250 default: 9251 break; 9252 } 9253 switch (ct) { 9254 case DM_POLYTOPE_TRI_PRISM: 9255 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9256 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9257 case DM_POLYTOPE_PYRAMID: 9258 continue; 9259 default: 9260 break; 9261 } 9262 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9263 if (unsplit) continue; 9264 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9265 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); 9266 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9267 /* This should work with periodicity since DG coordinates should be used */ 9268 if (depth > 1) { 9269 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9270 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); 9271 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9272 } 9273 } 9274 PetscFunctionReturn(PETSC_SUCCESS); 9275 } 9276 9277 /*@ 9278 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9279 9280 Collective 9281 9282 Input Parameters: 9283 + dm - The `DMPLEX` object 9284 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9285 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9286 9287 Level: developer 9288 9289 Notes: 9290 This is mainly intended for debugging/testing purposes. 9291 9292 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9293 9294 Extra roots can come from periodic cuts, where additional points appear on the boundary 9295 9296 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9297 @*/ 9298 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9299 { 9300 PetscInt l, nleaves, nroots, overlap; 9301 const PetscInt *locals; 9302 const PetscSFNode *remotes; 9303 PetscBool distributed; 9304 MPI_Comm comm; 9305 PetscMPIInt rank; 9306 9307 PetscFunctionBegin; 9308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9309 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9310 else pointSF = dm->sf; 9311 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9312 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9313 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9314 { 9315 PetscMPIInt mpiFlag; 9316 9317 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9318 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9319 } 9320 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9321 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9322 if (!distributed) { 9323 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); 9324 PetscFunctionReturn(PETSC_SUCCESS); 9325 } 9326 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); 9327 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9328 9329 /* Check SF graph is compatible with DMPlex chart */ 9330 { 9331 PetscInt pStart, pEnd, maxLeaf; 9332 9333 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9334 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9335 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9336 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9337 } 9338 9339 /* Check Point SF has no local points referenced */ 9340 for (l = 0; l < nleaves; l++) { 9341 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); 9342 } 9343 9344 /* Check there are no cells in interface */ 9345 if (!overlap) { 9346 PetscInt cellHeight, cStart, cEnd; 9347 9348 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9349 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9350 for (l = 0; l < nleaves; ++l) { 9351 const PetscInt point = locals ? locals[l] : l; 9352 9353 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9354 } 9355 } 9356 9357 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9358 { 9359 const PetscInt *rootdegree; 9360 9361 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9362 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9363 for (l = 0; l < nleaves; ++l) { 9364 const PetscInt point = locals ? locals[l] : l; 9365 const PetscInt *cone; 9366 PetscInt coneSize, c, idx; 9367 9368 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9369 PetscCall(DMPlexGetCone(dm, point, &cone)); 9370 for (c = 0; c < coneSize; ++c) { 9371 if (!rootdegree[cone[c]]) { 9372 if (locals) { 9373 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9374 } else { 9375 idx = (cone[c] < nleaves) ? cone[c] : -1; 9376 } 9377 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9378 } 9379 } 9380 } 9381 } 9382 PetscFunctionReturn(PETSC_SUCCESS); 9383 } 9384 9385 /*@ 9386 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9387 9388 Input Parameter: 9389 . dm - The `DMPLEX` object 9390 9391 Level: developer 9392 9393 Notes: 9394 This is a useful diagnostic when creating meshes programmatically. 9395 9396 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9397 9398 Currently does not include `DMPlexCheckCellShape()`. 9399 9400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9401 @*/ 9402 PetscErrorCode DMPlexCheck(DM dm) 9403 { 9404 PetscInt cellHeight; 9405 9406 PetscFunctionBegin; 9407 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9408 PetscCall(DMPlexCheckSymmetry(dm)); 9409 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9410 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9411 PetscCall(DMPlexCheckGeometry(dm)); 9412 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9413 PetscCall(DMPlexCheckInterfaceCones(dm)); 9414 PetscFunctionReturn(PETSC_SUCCESS); 9415 } 9416 9417 typedef struct cell_stats { 9418 PetscReal min, max, sum, squaresum; 9419 PetscInt count; 9420 } cell_stats_t; 9421 9422 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9423 { 9424 PetscInt i, N = *len; 9425 9426 for (i = 0; i < N; i++) { 9427 cell_stats_t *A = (cell_stats_t *)a; 9428 cell_stats_t *B = (cell_stats_t *)b; 9429 9430 B->min = PetscMin(A->min, B->min); 9431 B->max = PetscMax(A->max, B->max); 9432 B->sum += A->sum; 9433 B->squaresum += A->squaresum; 9434 B->count += A->count; 9435 } 9436 } 9437 9438 /*@ 9439 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9440 9441 Collective 9442 9443 Input Parameters: 9444 + dm - The `DMPLEX` object 9445 . output - If true, statistics will be displayed on `stdout` 9446 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9447 9448 Level: developer 9449 9450 Notes: 9451 This is mainly intended for debugging/testing purposes. 9452 9453 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9454 9455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9456 @*/ 9457 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9458 { 9459 DM dmCoarse; 9460 cell_stats_t stats, globalStats; 9461 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9462 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9463 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9464 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9465 PetscMPIInt rank, size; 9466 9467 PetscFunctionBegin; 9468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9469 stats.min = PETSC_MAX_REAL; 9470 stats.max = PETSC_MIN_REAL; 9471 stats.sum = stats.squaresum = 0.; 9472 stats.count = 0; 9473 9474 PetscCallMPI(MPI_Comm_size(comm, &size)); 9475 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9476 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9477 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9478 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9479 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9480 for (c = cStart; c < cEnd; c++) { 9481 PetscInt i; 9482 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9483 9484 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9485 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9486 for (i = 0; i < PetscSqr(cdim); ++i) { 9487 frobJ += J[i] * J[i]; 9488 frobInvJ += invJ[i] * invJ[i]; 9489 } 9490 cond2 = frobJ * frobInvJ; 9491 cond = PetscSqrtReal(cond2); 9492 9493 stats.min = PetscMin(stats.min, cond); 9494 stats.max = PetscMax(stats.max, cond); 9495 stats.sum += cond; 9496 stats.squaresum += cond2; 9497 stats.count++; 9498 if (output && cond > limit) { 9499 PetscSection coordSection; 9500 Vec coordsLocal; 9501 PetscScalar *coords = NULL; 9502 PetscInt Nv, d, clSize, cl, *closure = NULL; 9503 9504 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9505 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9506 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9507 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9508 for (i = 0; i < Nv / cdim; ++i) { 9509 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9510 for (d = 0; d < cdim; ++d) { 9511 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9512 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9513 } 9514 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9515 } 9516 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9517 for (cl = 0; cl < clSize * 2; cl += 2) { 9518 const PetscInt edge = closure[cl]; 9519 9520 if ((edge >= eStart) && (edge < eEnd)) { 9521 PetscReal len; 9522 9523 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9524 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9525 } 9526 } 9527 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9528 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9529 } 9530 } 9531 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9532 9533 if (size > 1) { 9534 PetscMPIInt blockLengths[2] = {4, 1}; 9535 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9536 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9537 MPI_Op statReduce; 9538 9539 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9540 PetscCallMPI(MPI_Type_commit(&statType)); 9541 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9542 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9543 PetscCallMPI(MPI_Op_free(&statReduce)); 9544 PetscCallMPI(MPI_Type_free(&statType)); 9545 } else { 9546 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9547 } 9548 if (rank == 0) { 9549 count = globalStats.count; 9550 min = globalStats.min; 9551 max = globalStats.max; 9552 mean = globalStats.sum / globalStats.count; 9553 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9554 } 9555 9556 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)); 9557 PetscCall(PetscFree2(J, invJ)); 9558 9559 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9560 if (dmCoarse) { 9561 PetscBool isplex; 9562 9563 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9564 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9565 } 9566 PetscFunctionReturn(PETSC_SUCCESS); 9567 } 9568 9569 /*@ 9570 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9571 orthogonal quality below given tolerance. 9572 9573 Collective 9574 9575 Input Parameters: 9576 + dm - The `DMPLEX` object 9577 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9578 - atol - [0, 1] Absolute tolerance for tagging cells. 9579 9580 Output Parameters: 9581 + OrthQual - `Vec` containing orthogonal quality per cell 9582 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9583 9584 Options Database Keys: 9585 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9586 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9587 9588 Level: intermediate 9589 9590 Notes: 9591 Orthogonal quality is given by the following formula\: 9592 9593 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9594 9595 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 9596 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9597 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9598 calculating the cosine of the angle between these vectors. 9599 9600 Orthogonal quality ranges from 1 (best) to 0 (worst). 9601 9602 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9603 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9604 9605 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9606 9607 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9608 @*/ 9609 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9610 { 9611 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9612 PetscInt *idx; 9613 PetscScalar *oqVals; 9614 const PetscScalar *cellGeomArr, *faceGeomArr; 9615 PetscReal *ci, *fi, *Ai; 9616 MPI_Comm comm; 9617 Vec cellgeom, facegeom; 9618 DM dmFace, dmCell; 9619 IS glob; 9620 ISLocalToGlobalMapping ltog; 9621 PetscViewer vwr; 9622 9623 PetscFunctionBegin; 9624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9625 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9626 PetscAssertPointer(OrthQual, 4); 9627 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9628 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9629 PetscCall(DMGetDimension(dm, &nc)); 9630 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9631 { 9632 DMPlexInterpolatedFlag interpFlag; 9633 9634 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9635 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9636 PetscMPIInt rank; 9637 9638 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9639 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9640 } 9641 } 9642 if (OrthQualLabel) { 9643 PetscAssertPointer(OrthQualLabel, 5); 9644 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9645 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9646 } else { 9647 *OrthQualLabel = NULL; 9648 } 9649 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9650 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9651 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9652 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9653 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9654 PetscCall(VecCreate(comm, OrthQual)); 9655 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9656 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9657 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9658 PetscCall(VecSetUp(*OrthQual)); 9659 PetscCall(ISDestroy(&glob)); 9660 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9661 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9662 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9663 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9664 PetscCall(VecGetDM(cellgeom, &dmCell)); 9665 PetscCall(VecGetDM(facegeom, &dmFace)); 9666 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9667 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9668 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9669 PetscInt cellarr[2], *adj = NULL; 9670 PetscScalar *cArr, *fArr; 9671 PetscReal minvalc = 1.0, minvalf = 1.0; 9672 PetscFVCellGeom *cg; 9673 9674 idx[cellIter] = cell - cStart; 9675 cellarr[0] = cell; 9676 /* Make indexing into cellGeom easier */ 9677 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9678 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9679 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9680 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9681 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9682 PetscInt i; 9683 const PetscInt neigh = adj[cellneigh]; 9684 PetscReal normci = 0, normfi = 0, normai = 0; 9685 PetscFVCellGeom *cgneigh; 9686 PetscFVFaceGeom *fg; 9687 9688 /* Don't count ourselves in the neighbor list */ 9689 if (neigh == cell) continue; 9690 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9691 cellarr[1] = neigh; 9692 { 9693 PetscInt numcovpts; 9694 const PetscInt *covpts; 9695 9696 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9697 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9698 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9699 } 9700 9701 /* Compute c_i, f_i and their norms */ 9702 for (i = 0; i < nc; i++) { 9703 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9704 fi[i] = fg->centroid[i] - cg->centroid[i]; 9705 Ai[i] = fg->normal[i]; 9706 normci += PetscPowReal(ci[i], 2); 9707 normfi += PetscPowReal(fi[i], 2); 9708 normai += PetscPowReal(Ai[i], 2); 9709 } 9710 normci = PetscSqrtReal(normci); 9711 normfi = PetscSqrtReal(normfi); 9712 normai = PetscSqrtReal(normai); 9713 9714 /* Normalize and compute for each face-cell-normal pair */ 9715 for (i = 0; i < nc; i++) { 9716 ci[i] = ci[i] / normci; 9717 fi[i] = fi[i] / normfi; 9718 Ai[i] = Ai[i] / normai; 9719 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9720 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9721 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9722 } 9723 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9724 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9725 } 9726 PetscCall(PetscFree(adj)); 9727 PetscCall(PetscFree2(cArr, fArr)); 9728 /* Defer to cell if they're equal */ 9729 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9730 if (OrthQualLabel) { 9731 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9732 } 9733 } 9734 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9735 PetscCall(VecAssemblyBegin(*OrthQual)); 9736 PetscCall(VecAssemblyEnd(*OrthQual)); 9737 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9738 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9739 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9740 if (OrthQualLabel) { 9741 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9742 } 9743 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9744 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9745 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9746 PetscFunctionReturn(PETSC_SUCCESS); 9747 } 9748 9749 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9750 * interpolator construction */ 9751 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9752 { 9753 PetscSection section, newSection, gsection; 9754 PetscSF sf; 9755 PetscBool hasConstraints, ghasConstraints; 9756 9757 PetscFunctionBegin; 9758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9759 PetscAssertPointer(odm, 2); 9760 PetscCall(DMGetLocalSection(dm, §ion)); 9761 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9762 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9763 if (!ghasConstraints) { 9764 PetscCall(PetscObjectReference((PetscObject)dm)); 9765 *odm = dm; 9766 PetscFunctionReturn(PETSC_SUCCESS); 9767 } 9768 PetscCall(DMClone(dm, odm)); 9769 PetscCall(DMCopyFields(dm, *odm)); 9770 PetscCall(DMGetLocalSection(*odm, &newSection)); 9771 PetscCall(DMGetPointSF(*odm, &sf)); 9772 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9773 PetscCall(DMSetGlobalSection(*odm, gsection)); 9774 PetscCall(PetscSectionDestroy(&gsection)); 9775 PetscFunctionReturn(PETSC_SUCCESS); 9776 } 9777 9778 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9779 { 9780 DM dmco, dmfo; 9781 Mat interpo; 9782 Vec rscale; 9783 Vec cglobalo, clocal; 9784 Vec fglobal, fglobalo, flocal; 9785 PetscBool regular; 9786 9787 PetscFunctionBegin; 9788 PetscCall(DMGetFullDM(dmc, &dmco)); 9789 PetscCall(DMGetFullDM(dmf, &dmfo)); 9790 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9791 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9792 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9793 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9794 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9795 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9796 PetscCall(VecSet(cglobalo, 0.)); 9797 PetscCall(VecSet(clocal, 0.)); 9798 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9799 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9800 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9801 PetscCall(VecSet(fglobal, 0.)); 9802 PetscCall(VecSet(fglobalo, 0.)); 9803 PetscCall(VecSet(flocal, 0.)); 9804 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9805 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9806 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9807 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9808 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9809 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9810 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9811 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9812 *shift = fglobal; 9813 PetscCall(VecDestroy(&flocal)); 9814 PetscCall(VecDestroy(&fglobalo)); 9815 PetscCall(VecDestroy(&clocal)); 9816 PetscCall(VecDestroy(&cglobalo)); 9817 PetscCall(VecDestroy(&rscale)); 9818 PetscCall(MatDestroy(&interpo)); 9819 PetscCall(DMDestroy(&dmfo)); 9820 PetscCall(DMDestroy(&dmco)); 9821 PetscFunctionReturn(PETSC_SUCCESS); 9822 } 9823 9824 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9825 { 9826 PetscObject shifto; 9827 Vec shift; 9828 9829 PetscFunctionBegin; 9830 if (!interp) { 9831 Vec rscale; 9832 9833 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9834 PetscCall(VecDestroy(&rscale)); 9835 } else { 9836 PetscCall(PetscObjectReference((PetscObject)interp)); 9837 } 9838 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9839 if (!shifto) { 9840 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9841 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9842 shifto = (PetscObject)shift; 9843 PetscCall(VecDestroy(&shift)); 9844 } 9845 shift = (Vec)shifto; 9846 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9847 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9848 PetscCall(MatDestroy(&interp)); 9849 PetscFunctionReturn(PETSC_SUCCESS); 9850 } 9851 9852 /* Pointwise interpolation 9853 Just code FEM for now 9854 u^f = I u^c 9855 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9856 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9857 I_{ij} = psi^f_i phi^c_j 9858 */ 9859 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9860 { 9861 PetscSection gsc, gsf; 9862 PetscInt m, n; 9863 void *ctx; 9864 DM cdm; 9865 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9866 9867 PetscFunctionBegin; 9868 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9869 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9870 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9871 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9872 9873 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9874 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9875 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9876 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9877 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9878 9879 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9880 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9881 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9882 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9883 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9884 if (scaling) { 9885 /* Use naive scaling */ 9886 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9887 } 9888 PetscFunctionReturn(PETSC_SUCCESS); 9889 } 9890 9891 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9892 { 9893 VecScatter ctx; 9894 9895 PetscFunctionBegin; 9896 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9897 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9898 PetscCall(VecScatterDestroy(&ctx)); 9899 PetscFunctionReturn(PETSC_SUCCESS); 9900 } 9901 9902 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[]) 9903 { 9904 const PetscInt Nc = uOff[1] - uOff[0]; 9905 PetscInt c; 9906 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9907 } 9908 9909 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9910 { 9911 DM dmc; 9912 PetscDS ds; 9913 Vec ones, locmass; 9914 IS cellIS; 9915 PetscFormKey key; 9916 PetscInt depth; 9917 9918 PetscFunctionBegin; 9919 PetscCall(DMClone(dm, &dmc)); 9920 PetscCall(DMCopyDisc(dm, dmc)); 9921 PetscCall(DMGetDS(dmc, &ds)); 9922 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9923 PetscCall(DMCreateGlobalVector(dmc, mass)); 9924 PetscCall(DMGetLocalVector(dmc, &ones)); 9925 PetscCall(DMGetLocalVector(dmc, &locmass)); 9926 PetscCall(DMPlexGetDepth(dmc, &depth)); 9927 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9928 PetscCall(VecSet(locmass, 0.0)); 9929 PetscCall(VecSet(ones, 1.0)); 9930 key.label = NULL; 9931 key.value = 0; 9932 key.field = 0; 9933 key.part = 0; 9934 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9935 PetscCall(ISDestroy(&cellIS)); 9936 PetscCall(VecSet(*mass, 0.0)); 9937 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9938 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9939 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9940 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9941 PetscCall(DMDestroy(&dmc)); 9942 PetscFunctionReturn(PETSC_SUCCESS); 9943 } 9944 9945 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9946 { 9947 PetscSection gsc, gsf; 9948 PetscInt m, n; 9949 void *ctx; 9950 DM cdm; 9951 PetscBool regular; 9952 9953 PetscFunctionBegin; 9954 if (dmFine == dmCoarse) { 9955 DM dmc; 9956 PetscDS ds; 9957 PetscWeakForm wf; 9958 Vec u; 9959 IS cellIS; 9960 PetscFormKey key; 9961 PetscInt depth; 9962 9963 PetscCall(DMClone(dmFine, &dmc)); 9964 PetscCall(DMCopyDisc(dmFine, dmc)); 9965 PetscCall(DMGetDS(dmc, &ds)); 9966 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9967 PetscCall(PetscWeakFormClear(wf)); 9968 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9969 PetscCall(DMCreateMatrix(dmc, mass)); 9970 PetscCall(DMGetLocalVector(dmc, &u)); 9971 PetscCall(DMPlexGetDepth(dmc, &depth)); 9972 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9973 PetscCall(MatZeroEntries(*mass)); 9974 key.label = NULL; 9975 key.value = 0; 9976 key.field = 0; 9977 key.part = 0; 9978 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9979 PetscCall(ISDestroy(&cellIS)); 9980 PetscCall(DMRestoreLocalVector(dmc, &u)); 9981 PetscCall(DMDestroy(&dmc)); 9982 } else { 9983 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9984 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9985 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9986 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9987 9988 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9989 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9990 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9991 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9992 9993 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9994 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9995 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9996 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9997 } 9998 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9999 PetscFunctionReturn(PETSC_SUCCESS); 10000 } 10001 10002 /*@ 10003 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10004 10005 Input Parameter: 10006 . dm - The `DMPLEX` object 10007 10008 Output Parameter: 10009 . regular - The flag 10010 10011 Level: intermediate 10012 10013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10014 @*/ 10015 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10016 { 10017 PetscFunctionBegin; 10018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10019 PetscAssertPointer(regular, 2); 10020 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10021 PetscFunctionReturn(PETSC_SUCCESS); 10022 } 10023 10024 /*@ 10025 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10026 10027 Input Parameters: 10028 + dm - The `DMPLEX` object 10029 - regular - The flag 10030 10031 Level: intermediate 10032 10033 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10034 @*/ 10035 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10036 { 10037 PetscFunctionBegin; 10038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10039 ((DM_Plex *)dm->data)->regularRefinement = regular; 10040 PetscFunctionReturn(PETSC_SUCCESS); 10041 } 10042 10043 /*@ 10044 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10045 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10046 10047 Not Collective 10048 10049 Input Parameter: 10050 . dm - The `DMPLEX` object 10051 10052 Output Parameters: 10053 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10054 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10055 10056 Level: intermediate 10057 10058 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10059 @*/ 10060 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10061 { 10062 DM_Plex *plex = (DM_Plex *)dm->data; 10063 10064 PetscFunctionBegin; 10065 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10066 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10067 if (anchorSection) *anchorSection = plex->anchorSection; 10068 if (anchorIS) *anchorIS = plex->anchorIS; 10069 PetscFunctionReturn(PETSC_SUCCESS); 10070 } 10071 10072 /*@ 10073 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10074 10075 Collective 10076 10077 Input Parameters: 10078 + dm - The `DMPLEX` object 10079 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10080 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10081 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10082 10083 Level: intermediate 10084 10085 Notes: 10086 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10087 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10088 combination of other points' degrees of freedom. 10089 10090 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10091 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10092 10093 The reference counts of `anchorSection` and `anchorIS` are incremented. 10094 10095 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10096 @*/ 10097 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10098 { 10099 DM_Plex *plex = (DM_Plex *)dm->data; 10100 PetscMPIInt result; 10101 10102 PetscFunctionBegin; 10103 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10104 if (anchorSection) { 10105 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10106 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10107 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10108 } 10109 if (anchorIS) { 10110 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10111 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10112 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10113 } 10114 10115 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10116 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10117 plex->anchorSection = anchorSection; 10118 10119 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10120 PetscCall(ISDestroy(&plex->anchorIS)); 10121 plex->anchorIS = anchorIS; 10122 10123 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10124 PetscInt size, a, pStart, pEnd; 10125 const PetscInt *anchors; 10126 10127 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10128 PetscCall(ISGetLocalSize(anchorIS, &size)); 10129 PetscCall(ISGetIndices(anchorIS, &anchors)); 10130 for (a = 0; a < size; a++) { 10131 PetscInt p; 10132 10133 p = anchors[a]; 10134 if (p >= pStart && p < pEnd) { 10135 PetscInt dof; 10136 10137 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10138 if (dof) { 10139 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10140 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10141 } 10142 } 10143 } 10144 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10145 } 10146 /* reset the generic constraints */ 10147 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10148 PetscFunctionReturn(PETSC_SUCCESS); 10149 } 10150 10151 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10152 { 10153 PetscSection anchorSection; 10154 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10155 10156 PetscFunctionBegin; 10157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10158 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10159 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10160 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10161 if (numFields) { 10162 PetscInt f; 10163 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10164 10165 for (f = 0; f < numFields; f++) { 10166 PetscInt numComp; 10167 10168 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10169 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10170 } 10171 } 10172 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10173 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10174 pStart = PetscMax(pStart, sStart); 10175 pEnd = PetscMin(pEnd, sEnd); 10176 pEnd = PetscMax(pStart, pEnd); 10177 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10178 for (p = pStart; p < pEnd; p++) { 10179 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10180 if (dof) { 10181 PetscCall(PetscSectionGetDof(section, p, &dof)); 10182 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10183 for (f = 0; f < numFields; f++) { 10184 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10185 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10186 } 10187 } 10188 } 10189 PetscCall(PetscSectionSetUp(*cSec)); 10190 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10191 PetscFunctionReturn(PETSC_SUCCESS); 10192 } 10193 10194 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10195 { 10196 PetscSection aSec; 10197 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10198 const PetscInt *anchors; 10199 PetscInt numFields, f; 10200 IS aIS; 10201 MatType mtype; 10202 PetscBool iscuda, iskokkos; 10203 10204 PetscFunctionBegin; 10205 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10206 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10207 PetscCall(PetscSectionGetStorageSize(section, &n)); 10208 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10209 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10210 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10211 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10212 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10213 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10214 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10215 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10216 else mtype = MATSEQAIJ; 10217 PetscCall(MatSetType(*cMat, mtype)); 10218 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10219 PetscCall(ISGetIndices(aIS, &anchors)); 10220 /* cSec will be a subset of aSec and section */ 10221 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10222 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10223 PetscCall(PetscMalloc1(m + 1, &i)); 10224 i[0] = 0; 10225 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10226 for (p = pStart; p < pEnd; p++) { 10227 PetscInt rDof, rOff, r; 10228 10229 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10230 if (!rDof) continue; 10231 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10232 if (numFields) { 10233 for (f = 0; f < numFields; f++) { 10234 annz = 0; 10235 for (r = 0; r < rDof; r++) { 10236 a = anchors[rOff + r]; 10237 if (a < sStart || a >= sEnd) continue; 10238 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10239 annz += aDof; 10240 } 10241 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10242 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10243 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10244 } 10245 } else { 10246 annz = 0; 10247 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10248 for (q = 0; q < dof; q++) { 10249 a = anchors[rOff + q]; 10250 if (a < sStart || a >= sEnd) continue; 10251 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10252 annz += aDof; 10253 } 10254 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10255 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10256 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10257 } 10258 } 10259 nnz = i[m]; 10260 PetscCall(PetscMalloc1(nnz, &j)); 10261 offset = 0; 10262 for (p = pStart; p < pEnd; p++) { 10263 if (numFields) { 10264 for (f = 0; f < numFields; f++) { 10265 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10266 for (q = 0; q < dof; q++) { 10267 PetscInt rDof, rOff, r; 10268 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10269 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10270 for (r = 0; r < rDof; r++) { 10271 PetscInt s; 10272 10273 a = anchors[rOff + r]; 10274 if (a < sStart || a >= sEnd) continue; 10275 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10276 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10277 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10278 } 10279 } 10280 } 10281 } else { 10282 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10283 for (q = 0; q < dof; q++) { 10284 PetscInt rDof, rOff, r; 10285 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10286 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10287 for (r = 0; r < rDof; r++) { 10288 PetscInt s; 10289 10290 a = anchors[rOff + r]; 10291 if (a < sStart || a >= sEnd) continue; 10292 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10293 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10294 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10295 } 10296 } 10297 } 10298 } 10299 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10300 PetscCall(PetscFree(i)); 10301 PetscCall(PetscFree(j)); 10302 PetscCall(ISRestoreIndices(aIS, &anchors)); 10303 PetscFunctionReturn(PETSC_SUCCESS); 10304 } 10305 10306 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10307 { 10308 DM_Plex *plex = (DM_Plex *)dm->data; 10309 PetscSection anchorSection, section, cSec; 10310 Mat cMat; 10311 10312 PetscFunctionBegin; 10313 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10314 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10315 if (anchorSection) { 10316 PetscInt Nf; 10317 10318 PetscCall(DMGetLocalSection(dm, §ion)); 10319 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10320 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10321 PetscCall(DMGetNumFields(dm, &Nf)); 10322 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10323 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10324 PetscCall(PetscSectionDestroy(&cSec)); 10325 PetscCall(MatDestroy(&cMat)); 10326 } 10327 PetscFunctionReturn(PETSC_SUCCESS); 10328 } 10329 10330 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10331 { 10332 IS subis; 10333 PetscSection section, subsection; 10334 10335 PetscFunctionBegin; 10336 PetscCall(DMGetLocalSection(dm, §ion)); 10337 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10338 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10339 /* Create subdomain */ 10340 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10341 /* Create submodel */ 10342 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10343 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10344 PetscCall(DMSetLocalSection(*subdm, subsection)); 10345 PetscCall(PetscSectionDestroy(&subsection)); 10346 PetscCall(DMCopyDisc(dm, *subdm)); 10347 /* Create map from submodel to global model */ 10348 if (is) { 10349 PetscSection sectionGlobal, subsectionGlobal; 10350 IS spIS; 10351 const PetscInt *spmap; 10352 PetscInt *subIndices; 10353 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10354 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10355 10356 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10357 PetscCall(ISGetIndices(spIS, &spmap)); 10358 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10359 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10360 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10361 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10362 for (p = pStart; p < pEnd; ++p) { 10363 PetscInt gdof, pSubSize = 0; 10364 10365 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10366 if (gdof > 0) { 10367 for (f = 0; f < Nf; ++f) { 10368 PetscInt fdof, fcdof; 10369 10370 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10371 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10372 pSubSize += fdof - fcdof; 10373 } 10374 subSize += pSubSize; 10375 if (pSubSize) { 10376 if (bs < 0) { 10377 bs = pSubSize; 10378 } else if (bs != pSubSize) { 10379 /* Layout does not admit a pointwise block size */ 10380 bs = 1; 10381 } 10382 } 10383 } 10384 } 10385 /* Must have same blocksize on all procs (some might have no points) */ 10386 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10387 bsLocal[1] = bs; 10388 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10389 if (bsMinMax[0] != bsMinMax[1]) { 10390 bs = 1; 10391 } else { 10392 bs = bsMinMax[0]; 10393 } 10394 PetscCall(PetscMalloc1(subSize, &subIndices)); 10395 for (p = pStart; p < pEnd; ++p) { 10396 PetscInt gdof, goff; 10397 10398 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10399 if (gdof > 0) { 10400 const PetscInt point = spmap[p]; 10401 10402 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10403 for (f = 0; f < Nf; ++f) { 10404 PetscInt fdof, fcdof, fc, f2, poff = 0; 10405 10406 /* Can get rid of this loop by storing field information in the global section */ 10407 for (f2 = 0; f2 < f; ++f2) { 10408 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10409 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10410 poff += fdof - fcdof; 10411 } 10412 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10413 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10414 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10415 } 10416 } 10417 } 10418 PetscCall(ISRestoreIndices(spIS, &spmap)); 10419 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10420 if (bs > 1) { 10421 /* We need to check that the block size does not come from non-contiguous fields */ 10422 PetscInt i, j, set = 1; 10423 for (i = 0; i < subSize; i += bs) { 10424 for (j = 0; j < bs; ++j) { 10425 if (subIndices[i + j] != subIndices[i] + j) { 10426 set = 0; 10427 break; 10428 } 10429 } 10430 } 10431 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10432 } 10433 /* Attach nullspace */ 10434 for (f = 0; f < Nf; ++f) { 10435 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10436 if ((*subdm)->nullspaceConstructors[f]) break; 10437 } 10438 if (f < Nf) { 10439 MatNullSpace nullSpace; 10440 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10441 10442 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10443 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10444 } 10445 } 10446 PetscFunctionReturn(PETSC_SUCCESS); 10447 } 10448 10449 /*@ 10450 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10451 10452 Input Parameters: 10453 + dm - The `DM` 10454 - dummy - unused argument 10455 10456 Options Database Key: 10457 . -dm_plex_monitor_throughput - Activate the monitor 10458 10459 Level: developer 10460 10461 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10462 @*/ 10463 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10464 { 10465 PetscLogHandler default_handler; 10466 10467 PetscFunctionBegin; 10468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10469 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10470 if (default_handler) { 10471 PetscLogEvent event; 10472 PetscEventPerfInfo eventInfo; 10473 PetscReal cellRate, flopRate; 10474 PetscInt cStart, cEnd, Nf, N; 10475 const char *name; 10476 10477 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10478 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10479 PetscCall(DMGetNumFields(dm, &Nf)); 10480 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10481 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10482 N = (cEnd - cStart) * Nf * eventInfo.count; 10483 flopRate = eventInfo.flops / eventInfo.time; 10484 cellRate = N / eventInfo.time; 10485 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))); 10486 } else { 10487 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."); 10488 } 10489 PetscFunctionReturn(PETSC_SUCCESS); 10490 } 10491