1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 89 90 PetscFunctionBegin; 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 93 PetscCall(ISGetLocalSize(valueIS, &Nct)); 94 PetscCall(ISGetIndices(valueIS, &ctypes)); 95 if (!Nct) cS = cE = 0; 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 } 114 PetscCall(ISDestroy(&valueIS)); 115 // Reset label for fast lookup 116 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 117 if (cStart) *cStart = cS; 118 if (cEnd) *cEnd = cE; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 123 { 124 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 125 PetscInt *sStart, *sEnd; 126 PetscViewerVTKFieldType *ft; 127 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 128 DMLabel depthLabel, ctLabel; 129 130 PetscFunctionBegin; 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 } 162 163 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 164 *types = 0; 165 166 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 167 if (globalvcdof[c]) ++(*types); 168 } 169 170 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 171 t = 0; 172 if (globalvcdof[DM_NUM_POLYTOPES]) { 173 sStart[t] = vStart; 174 sEnd[t] = vEnd; 175 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 176 ++t; 177 } 178 179 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 180 if (globalvcdof[c]) { 181 const DMPolytopeType ict = (DMPolytopeType)c; 182 183 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 184 sStart[t] = cStart; 185 sEnd[t] = cEnd; 186 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 187 ++t; 188 } 189 } 190 191 if (!*types) { 192 if (field >= 0) { 193 const char *fieldname; 194 195 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 196 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 197 } else { 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 199 } 200 } 201 202 *ssStart = sStart; 203 *ssEnd = sEnd; 204 *sft = ft; 205 PetscFunctionReturn(PETSC_SUCCESS); 206 } 207 208 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 209 { 210 PetscFunctionBegin; 211 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 216 { 217 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 218 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 219 220 PetscFunctionBegin; 221 *ft = PETSC_VTK_INVALID; 222 PetscCall(DMGetCoordinateDim(dm, &cdim)); 223 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 224 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 225 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 226 if (field >= 0) { 227 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 228 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 229 } else { 230 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 231 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 232 } 233 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 234 if (globalvcdof[0]) { 235 *sStart = vStart; 236 *sEnd = vEnd; 237 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 238 else *ft = PETSC_VTK_POINT_FIELD; 239 } else if (globalvcdof[1]) { 240 *sStart = cStart; 241 *sEnd = cEnd; 242 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 243 else *ft = PETSC_VTK_CELL_FIELD; 244 } else { 245 if (field >= 0) { 246 const char *fieldname; 247 248 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 249 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 250 } else { 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 252 } 253 } 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 DMPlexVecView1D - Plot many 1D solutions on the same line graph 259 260 Collective 261 262 Input Parameters: 263 + dm - The `DMPLEX` object 264 . n - The number of vectors 265 . u - The array of local vectors 266 - viewer - The `PetscViewer` 267 268 Level: advanced 269 270 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 271 @*/ 272 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 273 { 274 PetscDS ds; 275 PetscDraw draw = NULL; 276 PetscDrawLG lg; 277 Vec coordinates; 278 const PetscScalar *coords, **sol; 279 PetscReal *vals; 280 PetscInt *Nc; 281 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 282 char **names; 283 284 PetscFunctionBegin; 285 PetscCall(DMGetDS(dm, &ds)); 286 PetscCall(PetscDSGetNumFields(ds, &Nf)); 287 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 288 PetscCall(PetscDSGetComponents(ds, &Nc)); 289 290 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 291 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 292 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 293 294 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 295 for (i = 0, l = 0; i < n; ++i) { 296 const char *vname; 297 298 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 299 for (f = 0; f < Nf; ++f) { 300 PetscObject disc; 301 const char *fname; 302 char tmpname[PETSC_MAX_PATH_LEN]; 303 304 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 305 /* TODO Create names for components */ 306 for (c = 0; c < Nc[f]; ++c, ++l) { 307 PetscCall(PetscObjectGetName(disc, &fname)); 308 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 309 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 311 PetscCall(PetscStrallocpy(tmpname, &names[l])); 312 } 313 } 314 } 315 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 316 /* Just add P_1 support for now */ 317 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 318 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 319 PetscCall(VecGetArrayRead(coordinates, &coords)); 320 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 321 for (v = vStart; v < vEnd; ++v) { 322 PetscScalar *x, *svals; 323 324 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 325 for (i = 0; i < n; ++i) { 326 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 327 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 328 } 329 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 330 } 331 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 332 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 333 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 334 PetscCall(PetscFree3(sol, names, vals)); 335 336 PetscCall(PetscDrawLGDraw(lg)); 337 PetscCall(PetscDrawLGDestroy(&lg)); 338 PetscFunctionReturn(PETSC_SUCCESS); 339 } 340 341 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 342 { 343 DM dm; 344 345 PetscFunctionBegin; 346 PetscCall(VecGetDM(u, &dm)); 347 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 352 { 353 DM dm; 354 PetscSection s; 355 PetscDraw draw, popup; 356 DM cdm; 357 PetscSection coordSection; 358 Vec coordinates; 359 const PetscScalar *array; 360 PetscReal lbound[3], ubound[3]; 361 PetscReal vbound[2], time; 362 PetscBool flg; 363 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 364 const char *name; 365 char title[PETSC_MAX_PATH_LEN]; 366 367 PetscFunctionBegin; 368 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 369 PetscCall(VecGetDM(v, &dm)); 370 PetscCall(DMGetCoordinateDim(dm, &dim)); 371 PetscCall(DMGetLocalSection(dm, &s)); 372 PetscCall(PetscSectionGetNumFields(s, &Nf)); 373 PetscCall(DMGetCoarsenLevel(dm, &level)); 374 PetscCall(DMGetCoordinateDM(dm, &cdm)); 375 PetscCall(DMGetLocalSection(cdm, &coordSection)); 376 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 377 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 378 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 379 380 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 381 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 382 383 PetscCall(VecGetLocalSize(coordinates, &N)); 384 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 385 PetscCall(PetscDrawClear(draw)); 386 387 /* Could implement something like DMDASelectFields() */ 388 for (f = 0; f < Nf; ++f) { 389 DM fdm = dm; 390 Vec fv = v; 391 IS fis; 392 char prefix[PETSC_MAX_PATH_LEN]; 393 const char *fname; 394 395 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 396 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 397 398 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 399 else prefix[0] = '\0'; 400 if (Nf > 1) { 401 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 402 PetscCall(VecGetSubVector(v, fis, &fv)); 403 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 404 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 405 } 406 for (comp = 0; comp < Nc; ++comp, ++w) { 407 PetscInt nmax = 2; 408 409 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 410 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 411 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 412 PetscCall(PetscDrawSetTitle(draw, title)); 413 414 /* TODO Get max and min only for this component */ 415 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 416 if (!flg) { 417 PetscCall(VecMin(fv, NULL, &vbound[0])); 418 PetscCall(VecMax(fv, NULL, &vbound[1])); 419 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 420 } 421 422 PetscCall(PetscDrawGetPopup(draw, &popup)); 423 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 424 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 425 PetscCall(VecGetArrayRead(fv, &array)); 426 for (c = cStart; c < cEnd; ++c) { 427 PetscScalar *coords = NULL, *a = NULL; 428 const PetscScalar *coords_arr; 429 PetscBool isDG; 430 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 431 432 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 433 if (a) { 434 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 435 color[1] = color[2] = color[3] = color[0]; 436 } else { 437 PetscScalar *vals = NULL; 438 PetscInt numVals, va; 439 440 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 441 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); 442 switch (numVals / Nc) { 443 case 3: /* P1 Triangle */ 444 case 4: /* P1 Quadrangle */ 445 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 446 break; 447 case 6: /* P2 Triangle */ 448 case 8: /* P2 Quadrangle */ 449 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 450 break; 451 default: 452 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 453 } 454 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 455 } 456 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 457 switch (numCoords) { 458 case 6: 459 case 12: /* Localized triangle */ 460 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])); 461 break; 462 case 8: 463 case 16: /* Localized quadrilateral */ 464 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])); 465 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])); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 469 } 470 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 471 } 472 PetscCall(VecRestoreArrayRead(fv, &array)); 473 PetscCall(PetscDrawFlush(draw)); 474 PetscCall(PetscDrawPause(draw)); 475 PetscCall(PetscDrawSave(draw)); 476 } 477 if (Nf > 1) { 478 PetscCall(VecRestoreSubVector(v, fis, &fv)); 479 PetscCall(ISDestroy(&fis)); 480 PetscCall(DMDestroy(&fdm)); 481 } 482 } 483 PetscFunctionReturn(PETSC_SUCCESS); 484 } 485 486 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 487 { 488 DM dm; 489 PetscDraw draw; 490 PetscInt dim; 491 PetscBool isnull; 492 493 PetscFunctionBegin; 494 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 495 PetscCall(PetscDrawIsNull(draw, &isnull)); 496 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 497 498 PetscCall(VecGetDM(v, &dm)); 499 PetscCall(DMGetCoordinateDim(dm, &dim)); 500 switch (dim) { 501 case 1: 502 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 503 break; 504 case 2: 505 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 506 break; 507 default: 508 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 509 } 510 PetscFunctionReturn(PETSC_SUCCESS); 511 } 512 513 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 514 { 515 DM dm; 516 Vec locv; 517 const char *name; 518 PetscSection section; 519 PetscInt pStart, pEnd; 520 PetscInt numFields; 521 PetscViewerVTKFieldType ft; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 526 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 527 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 528 PetscCall(VecCopy(v, locv)); 529 PetscCall(DMGetLocalSection(dm, §ion)); 530 PetscCall(PetscSectionGetNumFields(section, &numFields)); 531 if (!numFields) { 532 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 533 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 534 } else { 535 PetscInt f; 536 537 for (f = 0; f < numFields; f++) { 538 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 539 if (ft == PETSC_VTK_INVALID) continue; 540 PetscCall(PetscObjectReference((PetscObject)locv)); 541 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 542 } 543 PetscCall(VecDestroy(&locv)); 544 } 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 549 { 550 DM dm; 551 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 552 553 PetscFunctionBegin; 554 PetscCall(VecGetDM(v, &dm)); 555 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 561 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 562 PetscInt i, numFields; 563 PetscObject fe; 564 PetscBool fem = PETSC_FALSE; 565 Vec locv = v; 566 const char *name; 567 PetscInt step; 568 PetscReal time; 569 570 PetscCall(DMGetNumFields(dm, &numFields)); 571 for (i = 0; i < numFields; i++) { 572 PetscCall(DMGetField(dm, i, NULL, &fe)); 573 if (fe->classid == PETSCFE_CLASSID) { 574 fem = PETSC_TRUE; 575 break; 576 } 577 } 578 if (fem) { 579 PetscObject isZero; 580 581 PetscCall(DMGetLocalVector(dm, &locv)); 582 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 583 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 584 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 585 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 586 PetscCall(VecCopy(v, locv)); 587 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 588 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 589 } 590 if (isvtk) { 591 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 592 } else if (ishdf5) { 593 #if defined(PETSC_HAVE_HDF5) 594 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 595 #else 596 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 597 #endif 598 } else if (isdraw) { 599 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 600 } else if (isglvis) { 601 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 602 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 603 PetscCall(VecView_GLVis(locv, viewer)); 604 } else if (iscgns) { 605 #if defined(PETSC_HAVE_CGNS) 606 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 607 #else 608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 609 #endif 610 } 611 if (fem) { 612 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 613 PetscCall(DMRestoreLocalVector(dm, &locv)); 614 } 615 } else { 616 PetscBool isseq; 617 618 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 619 if (isseq) PetscCall(VecView_Seq(v, viewer)); 620 else PetscCall(VecView_MPI(v, viewer)); 621 } 622 PetscFunctionReturn(PETSC_SUCCESS); 623 } 624 625 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 626 { 627 DM dm; 628 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 629 630 PetscFunctionBegin; 631 PetscCall(VecGetDM(v, &dm)); 632 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 639 if (isvtk || isdraw || isglvis || iscgns) { 640 Vec locv; 641 PetscObject isZero; 642 const char *name; 643 644 PetscCall(DMGetLocalVector(dm, &locv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 647 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 648 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 649 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 650 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 651 PetscCall(VecView_Plex_Local(locv, viewer)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 653 PetscCall(DMRestoreLocalVector(dm, &locv)); 654 } else if (ishdf5) { 655 #if defined(PETSC_HAVE_HDF5) 656 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 657 #else 658 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 659 #endif 660 } else if (isexodusii) { 661 #if defined(PETSC_HAVE_EXODUSII) 662 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 665 #endif 666 } else { 667 PetscBool isseq; 668 669 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 670 if (isseq) PetscCall(VecView_Seq(v, viewer)); 671 else PetscCall(VecView_MPI(v, viewer)); 672 } 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 MPI_Comm comm; 680 PetscViewerFormat format; 681 Vec v; 682 PetscBool isvtk, ishdf5; 683 684 PetscFunctionBegin; 685 PetscCall(VecGetDM(originalv, &dm)); 686 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 687 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 691 if (format == PETSC_VIEWER_NATIVE) { 692 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 693 /* this need a better fix */ 694 if (dm->useNatural) { 695 if (dm->sfNatural) { 696 const char *vecname; 697 PetscInt n, nroots; 698 699 PetscCall(VecGetLocalSize(originalv, &n)); 700 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 701 if (n == nroots) { 702 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 703 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 704 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 705 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 706 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 707 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 709 } else v = originalv; 710 } else v = originalv; 711 712 if (ishdf5) { 713 #if defined(PETSC_HAVE_HDF5) 714 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 715 #else 716 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 717 #endif 718 } else if (isvtk) { 719 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 720 } else { 721 PetscBool isseq; 722 723 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 724 if (isseq) PetscCall(VecView_Seq(v, viewer)); 725 else PetscCall(VecView_MPI(v, viewer)); 726 } 727 if (v != originalv) PetscCall(VecDestroy(&v)); 728 PetscFunctionReturn(PETSC_SUCCESS); 729 } 730 731 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 732 { 733 DM dm; 734 PetscBool ishdf5; 735 736 PetscFunctionBegin; 737 PetscCall(VecGetDM(v, &dm)); 738 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 739 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 740 if (ishdf5) { 741 DM dmBC; 742 Vec gv; 743 const char *name; 744 745 PetscCall(DMGetOutputDM(dm, &dmBC)); 746 PetscCall(DMGetGlobalVector(dmBC, &gv)); 747 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 748 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 749 PetscCall(VecLoad_Default(gv, viewer)); 750 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 751 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 753 } else PetscCall(VecLoad_Default(v, viewer)); 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 758 { 759 DM dm; 760 PetscBool ishdf5, isexodusii; 761 762 PetscFunctionBegin; 763 PetscCall(VecGetDM(v, &dm)); 764 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 765 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 767 if (ishdf5) { 768 #if defined(PETSC_HAVE_HDF5) 769 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 770 #else 771 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 772 #endif 773 } else if (isexodusii) { 774 #if defined(PETSC_HAVE_EXODUSII) 775 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 776 #else 777 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 778 #endif 779 } else PetscCall(VecLoad_Default(v, viewer)); 780 PetscFunctionReturn(PETSC_SUCCESS); 781 } 782 783 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 784 { 785 DM dm; 786 PetscViewerFormat format; 787 PetscBool ishdf5; 788 789 PetscFunctionBegin; 790 PetscCall(VecGetDM(originalv, &dm)); 791 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 792 PetscCall(PetscViewerGetFormat(viewer, &format)); 793 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 794 if (format == PETSC_VIEWER_NATIVE) { 795 if (dm->useNatural) { 796 if (dm->sfNatural) { 797 if (ishdf5) { 798 #if defined(PETSC_HAVE_HDF5) 799 Vec v; 800 const char *vecname; 801 802 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 803 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 804 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 805 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 806 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 807 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 808 PetscCall(VecDestroy(&v)); 809 #else 810 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 811 #endif 812 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 813 } 814 } else PetscCall(VecLoad_Default(originalv, viewer)); 815 } 816 PetscFunctionReturn(PETSC_SUCCESS); 817 } 818 819 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 820 { 821 PetscSection coordSection; 822 Vec coordinates; 823 DMLabel depthLabel, celltypeLabel; 824 const char *name[4]; 825 const PetscScalar *a; 826 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 827 828 PetscFunctionBegin; 829 PetscCall(DMGetDimension(dm, &dim)); 830 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 833 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 834 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 835 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 836 PetscCall(VecGetArrayRead(coordinates, &a)); 837 name[0] = "vertex"; 838 name[1] = "edge"; 839 name[dim - 1] = "face"; 840 name[dim] = "cell"; 841 for (c = cStart; c < cEnd; ++c) { 842 PetscInt *closure = NULL; 843 PetscInt closureSize, cl, ct; 844 845 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 847 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 848 PetscCall(PetscViewerASCIIPushTab(viewer)); 849 for (cl = 0; cl < closureSize * 2; cl += 2) { 850 PetscInt point = closure[cl], depth, dof, off, d, p; 851 852 if ((point < pStart) || (point >= pEnd)) continue; 853 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 854 if (!dof) continue; 855 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 856 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 858 for (p = 0; p < dof / dim; ++p) { 859 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 860 for (d = 0; d < dim; ++d) { 861 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 863 } 864 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 865 } 866 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 867 } 868 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 869 PetscCall(PetscViewerASCIIPopTab(viewer)); 870 } 871 PetscCall(VecRestoreArrayRead(coordinates, &a)); 872 PetscFunctionReturn(PETSC_SUCCESS); 873 } 874 875 typedef enum { 876 CS_CARTESIAN, 877 CS_POLAR, 878 CS_CYLINDRICAL, 879 CS_SPHERICAL 880 } CoordSystem; 881 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 882 883 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 884 { 885 PetscInt i; 886 887 PetscFunctionBegin; 888 if (dim > 3) { 889 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 890 } else { 891 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 892 893 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 894 switch (cs) { 895 case CS_CARTESIAN: 896 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 897 break; 898 case CS_POLAR: 899 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 900 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 901 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 902 break; 903 case CS_CYLINDRICAL: 904 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 905 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 906 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 907 trcoords[2] = coords[2]; 908 break; 909 case CS_SPHERICAL: 910 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 911 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 912 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 913 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 914 break; 915 } 916 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 917 } 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 922 { 923 DM_Plex *mesh = (DM_Plex *)dm->data; 924 DM cdm, cdmCell; 925 PetscSection coordSection, coordSectionCell; 926 Vec coordinates, coordinatesCell; 927 PetscViewerFormat format; 928 929 PetscFunctionBegin; 930 PetscCall(PetscViewerGetFormat(viewer, &format)); 931 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 932 const char *name; 933 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 934 PetscInt pStart, pEnd, p, numLabels, l; 935 PetscMPIInt rank, size; 936 937 PetscCall(DMGetCoordinateDM(dm, &cdm)); 938 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 939 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 940 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 941 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 942 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 943 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 944 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 945 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 946 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 947 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 948 PetscCall(DMGetDimension(dm, &dim)); 949 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 950 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 951 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 952 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 953 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 954 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 955 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 956 for (p = pStart; p < pEnd; ++p) { 957 PetscInt dof, off, s; 958 959 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 960 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 961 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 962 } 963 PetscCall(PetscViewerFlush(viewer)); 964 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 965 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 966 for (p = pStart; p < pEnd; ++p) { 967 PetscInt dof, off, c; 968 969 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 970 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 971 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])); 972 } 973 PetscCall(PetscViewerFlush(viewer)); 974 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 975 if (coordSection && coordinates) { 976 CoordSystem cs = CS_CARTESIAN; 977 const PetscScalar *array, *arrayCell = NULL; 978 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 979 PetscMPIInt rank; 980 const char *name; 981 982 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 983 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 984 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 985 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 986 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 987 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 988 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 989 pStart = PetscMin(pvStart, pcStart); 990 pEnd = PetscMax(pvEnd, pcEnd); 991 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 992 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 994 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 995 996 PetscCall(VecGetArrayRead(coordinates, &array)); 997 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 998 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 999 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1000 for (p = pStart; p < pEnd; ++p) { 1001 PetscInt dof, off; 1002 1003 if (p >= pvStart && p < pvEnd) { 1004 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1005 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1006 if (dof) { 1007 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1008 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1009 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1010 } 1011 } 1012 if (cdmCell && p >= pcStart && p < pcEnd) { 1013 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1014 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1015 if (dof) { 1016 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1017 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1018 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1019 } 1020 } 1021 } 1022 PetscCall(PetscViewerFlush(viewer)); 1023 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1024 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1025 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1026 } 1027 PetscCall(DMGetNumLabels(dm, &numLabels)); 1028 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1029 for (l = 0; l < numLabels; ++l) { 1030 DMLabel label; 1031 PetscBool isdepth; 1032 const char *name; 1033 1034 PetscCall(DMGetLabelName(dm, l, &name)); 1035 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1036 if (isdepth) continue; 1037 PetscCall(DMGetLabel(dm, name, &label)); 1038 PetscCall(DMLabelView(label, viewer)); 1039 } 1040 if (size > 1) { 1041 PetscSF sf; 1042 1043 PetscCall(DMGetPointSF(dm, &sf)); 1044 PetscCall(PetscSFView(sf, viewer)); 1045 } 1046 if (mesh->periodic.face_sfs) 1047 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], 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 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 if (lflg) { 1115 DMLabel lbl; 1116 1117 PetscCall(DMGetLabel(dm, lname, &lbl)); 1118 if (lbl) { 1119 PetscInt val, defval; 1120 1121 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1122 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1123 for (c = pStart; c < pEnd; c++) { 1124 PetscInt *closure = NULL; 1125 PetscInt closureSize; 1126 1127 PetscCall(DMLabelGetValue(lbl, c, &val)); 1128 if (val == defval) continue; 1129 1130 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1131 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1132 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1133 } 1134 } 1135 } 1136 1137 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1138 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1139 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1140 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1141 \\documentclass[tikz]{standalone}\n\n\ 1142 \\usepackage{pgflibraryshapes}\n\ 1143 \\usetikzlibrary{backgrounds}\n\ 1144 \\usetikzlibrary{arrows}\n\ 1145 \\begin{document}\n")); 1146 if (size > 1) { 1147 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1148 for (p = 0; p < size; ++p) { 1149 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1151 } 1152 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1153 } 1154 if (drawHasse) { 1155 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1156 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1169 } 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1171 1172 /* Plot vertices */ 1173 PetscCall(VecGetArray(coordinates, &coords)); 1174 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1175 for (v = vStart; v < vEnd; ++v) { 1176 PetscInt off, dof, d; 1177 PetscBool isLabeled = PETSC_FALSE; 1178 1179 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1180 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1181 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1183 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1184 for (d = 0; d < dof; ++d) { 1185 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1186 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1187 } 1188 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1189 if (dim == 3) { 1190 PetscReal tmp = tcoords[1]; 1191 tcoords[1] = tcoords[2]; 1192 tcoords[2] = -tmp; 1193 } 1194 for (d = 0; d < dof; ++d) { 1195 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1197 } 1198 if (drawHasse) color = colors[0 % numColors]; 1199 else color = colors[rank % numColors]; 1200 for (l = 0; l < numLabels; ++l) { 1201 PetscInt val; 1202 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1203 if (val >= 0) { 1204 color = lcolors[l % numLColors]; 1205 isLabeled = PETSC_TRUE; 1206 break; 1207 } 1208 } 1209 if (drawNumbers[0]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1211 } else if (drawColors[0]) { 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1213 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1214 } 1215 PetscCall(VecRestoreArray(coordinates, &coords)); 1216 PetscCall(PetscViewerFlush(viewer)); 1217 /* Plot edges */ 1218 if (plotEdges) { 1219 PetscCall(VecGetArray(coordinates, &coords)); 1220 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1221 for (e = eStart; e < eEnd; ++e) { 1222 const PetscInt *cone; 1223 PetscInt coneSize, offA, offB, dof, d; 1224 1225 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1226 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1227 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1228 PetscCall(DMPlexGetCone(dm, e, &cone)); 1229 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1231 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1232 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1233 for (d = 0; d < dof; ++d) { 1234 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1235 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1236 } 1237 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1238 if (dim == 3) { 1239 PetscReal tmp = tcoords[1]; 1240 tcoords[1] = tcoords[2]; 1241 tcoords[2] = -tmp; 1242 } 1243 for (d = 0; d < dof; ++d) { 1244 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1245 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1246 } 1247 if (drawHasse) color = colors[1 % numColors]; 1248 else color = colors[rank % numColors]; 1249 for (l = 0; l < numLabels; ++l) { 1250 PetscInt val; 1251 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1252 if (val >= 0) { 1253 color = lcolors[l % numLColors]; 1254 break; 1255 } 1256 } 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1258 } 1259 PetscCall(VecRestoreArray(coordinates, &coords)); 1260 PetscCall(PetscViewerFlush(viewer)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1262 } 1263 /* Plot cells */ 1264 if (dim == 3 || !drawNumbers[1]) { 1265 for (e = eStart; e < eEnd; ++e) { 1266 const PetscInt *cone; 1267 1268 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1269 color = colors[rank % numColors]; 1270 for (l = 0; l < numLabels; ++l) { 1271 PetscInt val; 1272 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1273 if (val >= 0) { 1274 color = lcolors[l % numLColors]; 1275 break; 1276 } 1277 } 1278 PetscCall(DMPlexGetCone(dm, e, &cone)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1280 } 1281 } else { 1282 DMPolytopeType ct; 1283 1284 /* Drawing a 2D polygon */ 1285 for (c = cStart; c < cEnd; ++c) { 1286 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1287 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1288 if (DMPolytopeTypeIsHybrid(ct)) { 1289 const PetscInt *cone; 1290 PetscInt coneSize, e; 1291 1292 PetscCall(DMPlexGetCone(dm, c, &cone)); 1293 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1294 for (e = 0; e < coneSize; ++e) { 1295 const PetscInt *econe; 1296 1297 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1298 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)); 1299 } 1300 } else { 1301 PetscInt *closure = NULL; 1302 PetscInt closureSize, Nv = 0, v; 1303 1304 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1305 for (p = 0; p < closureSize * 2; p += 2) { 1306 const PetscInt point = closure[p]; 1307 1308 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1309 } 1310 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1311 for (v = 0; v <= Nv; ++v) { 1312 const PetscInt vertex = closure[v % Nv]; 1313 1314 if (v > 0) { 1315 if (plotEdges) { 1316 const PetscInt *edge; 1317 PetscInt endpoints[2], ne; 1318 1319 endpoints[0] = closure[v - 1]; 1320 endpoints[1] = vertex; 1321 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1322 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1323 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1324 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1325 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1326 } 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1328 } 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1330 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1331 } 1332 } 1333 } 1334 for (c = cStart; c < cEnd; ++c) { 1335 double ccoords[3] = {0.0, 0.0, 0.0}; 1336 PetscBool isLabeled = PETSC_FALSE; 1337 PetscScalar *cellCoords = NULL; 1338 const PetscScalar *array; 1339 PetscInt numCoords, cdim, d; 1340 PetscBool isDG; 1341 1342 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1343 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1344 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1345 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1346 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1347 for (p = 0; p < numCoords / cdim; ++p) { 1348 for (d = 0; d < cdim; ++d) { 1349 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1350 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1351 } 1352 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1353 if (cdim == 3) { 1354 PetscReal tmp = tcoords[1]; 1355 tcoords[1] = tcoords[2]; 1356 tcoords[2] = -tmp; 1357 } 1358 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1359 } 1360 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1361 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1362 for (d = 0; d < cdim; ++d) { 1363 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1364 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1365 } 1366 if (drawHasse) color = colors[depth % numColors]; 1367 else color = colors[rank % numColors]; 1368 for (l = 0; l < numLabels; ++l) { 1369 PetscInt val; 1370 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1371 if (val >= 0) { 1372 color = lcolors[l % numLColors]; 1373 isLabeled = PETSC_TRUE; 1374 break; 1375 } 1376 } 1377 if (drawNumbers[dim]) { 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1379 } else if (drawColors[dim]) { 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1381 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1382 } 1383 if (drawHasse) { 1384 color = colors[depth % numColors]; 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1389 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1390 1391 color = colors[1 % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 color = colors[0 % numColors]; 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1404 1405 for (p = pStart; p < pEnd; ++p) { 1406 const PetscInt *cone; 1407 PetscInt coneSize, cp; 1408 1409 PetscCall(DMPlexGetCone(dm, p, &cone)); 1410 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1411 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1412 } 1413 } 1414 PetscCall(PetscViewerFlush(viewer)); 1415 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1418 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1419 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1420 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1421 PetscCall(PetscFree3(names, colors, lcolors)); 1422 PetscCall(PetscBTDestroy(&wp)); 1423 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1424 Vec cown, acown; 1425 VecScatter sct; 1426 ISLocalToGlobalMapping g2l; 1427 IS gid, acis; 1428 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1429 MPI_Group ggroup, ngroup; 1430 PetscScalar *array, nid; 1431 const PetscInt *idxs; 1432 PetscInt *idxs2, *start, *adjacency, *work; 1433 PetscInt64 lm[3], gm[3]; 1434 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1435 PetscMPIInt d1, d2, rank; 1436 1437 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1438 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1439 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1440 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1441 #endif 1442 if (ncomm != MPI_COMM_NULL) { 1443 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1444 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1445 d1 = 0; 1446 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1447 nid = d2; 1448 PetscCallMPI(MPI_Group_free(&ggroup)); 1449 PetscCallMPI(MPI_Group_free(&ngroup)); 1450 PetscCallMPI(MPI_Comm_free(&ncomm)); 1451 } else nid = 0.0; 1452 1453 /* Get connectivity */ 1454 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1455 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1456 1457 /* filter overlapped local cells */ 1458 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1459 PetscCall(ISGetIndices(gid, &idxs)); 1460 PetscCall(ISGetLocalSize(gid, &cum)); 1461 PetscCall(PetscMalloc1(cum, &idxs2)); 1462 for (c = cStart, cum = 0; c < cEnd; c++) { 1463 if (idxs[c - cStart] < 0) continue; 1464 idxs2[cum++] = idxs[c - cStart]; 1465 } 1466 PetscCall(ISRestoreIndices(gid, &idxs)); 1467 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1468 PetscCall(ISDestroy(&gid)); 1469 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1470 1471 /* support for node-aware cell locality */ 1472 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1473 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1474 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1475 PetscCall(VecGetArray(cown, &array)); 1476 for (c = 0; c < numVertices; c++) array[c] = nid; 1477 PetscCall(VecRestoreArray(cown, &array)); 1478 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1479 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1481 PetscCall(ISDestroy(&acis)); 1482 PetscCall(VecScatterDestroy(&sct)); 1483 PetscCall(VecDestroy(&cown)); 1484 1485 /* compute edgeCut */ 1486 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1487 PetscCall(PetscMalloc1(cum, &work)); 1488 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1489 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1490 PetscCall(ISDestroy(&gid)); 1491 PetscCall(VecGetArray(acown, &array)); 1492 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1493 PetscInt totl; 1494 1495 totl = start[c + 1] - start[c]; 1496 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1497 for (i = 0; i < totl; i++) { 1498 if (work[i] < 0) { 1499 ect += 1; 1500 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1501 } 1502 } 1503 } 1504 PetscCall(PetscFree(work)); 1505 PetscCall(VecRestoreArray(acown, &array)); 1506 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1507 lm[1] = -numVertices; 1508 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1510 lm[0] = ect; /* edgeCut */ 1511 lm[1] = ectn; /* node-aware edgeCut */ 1512 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1513 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1514 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1515 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1517 #else 1518 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1519 #endif 1520 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1521 PetscCall(PetscFree(start)); 1522 PetscCall(PetscFree(adjacency)); 1523 PetscCall(VecDestroy(&acown)); 1524 } else { 1525 const char *name; 1526 PetscInt *sizes, *hybsizes, *ghostsizes; 1527 PetscInt locDepth, depth, cellHeight, dim, d; 1528 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1529 PetscInt numLabels, l, maxSize = 17; 1530 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1531 MPI_Comm comm; 1532 PetscMPIInt size, rank; 1533 1534 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1535 PetscCallMPI(MPI_Comm_size(comm, &size)); 1536 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1537 PetscCall(DMGetDimension(dm, &dim)); 1538 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1539 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1540 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1541 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1542 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1543 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1544 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1545 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1546 gcNum = gcEnd - gcStart; 1547 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1548 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1549 for (d = 0; d <= depth; d++) { 1550 PetscInt Nc[2] = {0, 0}, ict; 1551 1552 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1553 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1554 ict = ct0; 1555 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1556 ct0 = (DMPolytopeType)ict; 1557 for (p = pStart; p < pEnd; ++p) { 1558 DMPolytopeType ct; 1559 1560 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1561 if (ct == ct0) ++Nc[0]; 1562 else ++Nc[1]; 1563 } 1564 if (size < maxSize) { 1565 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1566 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1567 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1568 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1569 for (p = 0; p < size; ++p) { 1570 if (rank == 0) { 1571 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1572 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1573 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1574 } 1575 } 1576 } else { 1577 PetscInt locMinMax[2]; 1578 1579 locMinMax[0] = Nc[0] + Nc[1]; 1580 locMinMax[1] = Nc[0] + Nc[1]; 1581 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1582 locMinMax[0] = Nc[1]; 1583 locMinMax[1] = Nc[1]; 1584 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1585 if (d == depth) { 1586 locMinMax[0] = gcNum; 1587 locMinMax[1] = gcNum; 1588 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1589 } 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1591 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1592 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1593 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1594 } 1595 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1596 } 1597 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1598 { 1599 const PetscReal *maxCell; 1600 const PetscReal *L; 1601 PetscBool localized; 1602 1603 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1604 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1605 if (L || localized) { 1606 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1607 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1608 if (L) { 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1610 for (d = 0; d < dim; ++d) { 1611 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1612 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1613 } 1614 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1615 } 1616 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1617 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1618 } 1619 } 1620 PetscCall(DMGetNumLabels(dm, &numLabels)); 1621 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1622 for (l = 0; l < numLabels; ++l) { 1623 DMLabel label; 1624 const char *name; 1625 IS valueIS; 1626 const PetscInt *values; 1627 PetscInt numValues, v; 1628 1629 PetscCall(DMGetLabelName(dm, l, &name)); 1630 PetscCall(DMGetLabel(dm, name, &label)); 1631 PetscCall(DMLabelGetNumValues(label, &numValues)); 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1633 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1634 PetscCall(ISGetIndices(valueIS, &values)); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1636 for (v = 0; v < numValues; ++v) { 1637 PetscInt size; 1638 1639 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1640 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1641 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1642 } 1643 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1644 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1645 PetscCall(ISRestoreIndices(valueIS, &values)); 1646 PetscCall(ISDestroy(&valueIS)); 1647 } 1648 { 1649 char **labelNames; 1650 PetscInt Nl = numLabels; 1651 PetscBool flg; 1652 1653 PetscCall(PetscMalloc1(Nl, &labelNames)); 1654 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1655 for (l = 0; l < Nl; ++l) { 1656 DMLabel label; 1657 1658 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1659 if (flg) { 1660 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1661 PetscCall(DMLabelView(label, viewer)); 1662 } 1663 PetscCall(PetscFree(labelNames[l])); 1664 } 1665 PetscCall(PetscFree(labelNames)); 1666 } 1667 /* If no fields are specified, people do not want to see adjacency */ 1668 if (dm->Nf) { 1669 PetscInt f; 1670 1671 for (f = 0; f < dm->Nf; ++f) { 1672 const char *name; 1673 1674 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1675 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1676 PetscCall(PetscViewerASCIIPushTab(viewer)); 1677 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1678 if (dm->fields[f].adjacency[0]) { 1679 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1680 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1681 } else { 1682 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1683 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1684 } 1685 PetscCall(PetscViewerASCIIPopTab(viewer)); 1686 } 1687 } 1688 PetscCall(DMGetCoarseDM(dm, &cdm)); 1689 if (cdm) { 1690 PetscCall(PetscViewerASCIIPushTab(viewer)); 1691 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1692 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1693 PetscCall(PetscViewerASCIIPopTab(viewer)); 1694 } 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1700 { 1701 DMPolytopeType ct; 1702 PetscMPIInt rank; 1703 PetscInt cdim; 1704 1705 PetscFunctionBegin; 1706 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1707 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1708 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1709 switch (ct) { 1710 case DM_POLYTOPE_SEGMENT: 1711 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1712 switch (cdim) { 1713 case 1: { 1714 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1715 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1716 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1719 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1720 } break; 1721 case 2: { 1722 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1723 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1724 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1725 1726 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1727 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)); 1728 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)); 1729 } break; 1730 default: 1731 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1732 } 1733 break; 1734 case DM_POLYTOPE_TRIANGLE: 1735 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)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1738 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1739 break; 1740 case DM_POLYTOPE_QUADRILATERAL: 1741 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)); 1742 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)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1747 break; 1748 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1749 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)); 1750 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)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_FV_GHOST: 1757 break; 1758 default: 1759 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1760 } 1761 PetscFunctionReturn(PETSC_SUCCESS); 1762 } 1763 1764 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1765 { 1766 PetscReal centroid[2] = {0., 0.}; 1767 PetscMPIInt rank; 1768 PetscInt fillColor; 1769 1770 PetscFunctionBegin; 1771 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1772 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1773 for (PetscInt v = 0; v < Nv; ++v) { 1774 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1775 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1776 } 1777 for (PetscInt e = 0; e < Nv; ++e) { 1778 refCoords[0] = refVertices[e * 2 + 0]; 1779 refCoords[1] = refVertices[e * 2 + 1]; 1780 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1781 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1782 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1783 } 1784 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1785 for (PetscInt d = 0; d < edgeDiv; ++d) { 1786 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)); 1787 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1788 } 1789 } 1790 PetscFunctionReturn(PETSC_SUCCESS); 1791 } 1792 1793 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1794 { 1795 DMPolytopeType ct; 1796 1797 PetscFunctionBegin; 1798 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1799 switch (ct) { 1800 case DM_POLYTOPE_TRIANGLE: { 1801 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1802 1803 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1804 } break; 1805 case DM_POLYTOPE_QUADRILATERAL: { 1806 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1807 1808 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1809 } break; 1810 default: 1811 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1812 } 1813 PetscFunctionReturn(PETSC_SUCCESS); 1814 } 1815 1816 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1817 { 1818 PetscDraw draw; 1819 DM cdm; 1820 PetscSection coordSection; 1821 Vec coordinates; 1822 PetscReal xyl[3], xyr[3]; 1823 PetscReal *refCoords, *edgeCoords; 1824 PetscBool isnull, drawAffine; 1825 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1826 1827 PetscFunctionBegin; 1828 PetscCall(DMGetCoordinateDim(dm, &dim)); 1829 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1830 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1831 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1832 edgeDiv = cDegree + 1; 1833 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1834 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1835 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1836 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1837 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1838 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1839 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1840 1841 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1842 PetscCall(PetscDrawIsNull(draw, &isnull)); 1843 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1844 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1845 1846 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1847 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1848 PetscCall(PetscDrawClear(draw)); 1849 1850 for (c = cStart; c < cEnd; ++c) { 1851 PetscScalar *coords = NULL; 1852 const PetscScalar *coords_arr; 1853 PetscInt numCoords; 1854 PetscBool isDG; 1855 1856 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1857 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1858 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1859 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1860 } 1861 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1862 PetscCall(PetscDrawFlush(draw)); 1863 PetscCall(PetscDrawPause(draw)); 1864 PetscCall(PetscDrawSave(draw)); 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1869 { 1870 DM odm = dm, rdm = dm, cdm; 1871 PetscFE fe; 1872 PetscSpace sp; 1873 PetscClassId id; 1874 PetscInt degree; 1875 PetscBool hoView = PETSC_TRUE; 1876 1877 PetscFunctionBegin; 1878 PetscObjectOptionsBegin((PetscObject)dm); 1879 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1880 PetscOptionsEnd(); 1881 PetscCall(PetscObjectReference((PetscObject)dm)); 1882 *hdm = dm; 1883 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1884 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1885 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1886 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1887 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1888 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1889 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1890 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1891 DM cdm, rcdm; 1892 Mat In; 1893 Vec cl, rcl; 1894 1895 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1896 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1897 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1898 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1899 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1900 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1901 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1902 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1903 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1904 PetscCall(MatMult(In, cl, rcl)); 1905 PetscCall(MatDestroy(&In)); 1906 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1907 PetscCall(DMDestroy(&odm)); 1908 odm = rdm; 1909 } 1910 *hdm = rdm; 1911 PetscFunctionReturn(PETSC_SUCCESS); 1912 } 1913 1914 #if defined(PETSC_HAVE_EXODUSII) 1915 #include <exodusII.h> 1916 #include <petscviewerexodusii.h> 1917 #endif 1918 1919 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1920 { 1921 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1922 char name[PETSC_MAX_PATH_LEN]; 1923 1924 PetscFunctionBegin; 1925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1926 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1927 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1928 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1931 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1932 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1933 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1934 if (iascii) { 1935 PetscViewerFormat format; 1936 PetscCall(PetscViewerGetFormat(viewer, &format)); 1937 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1938 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1939 } else if (ishdf5) { 1940 #if defined(PETSC_HAVE_HDF5) 1941 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1942 #else 1943 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1944 #endif 1945 } else if (isvtk) { 1946 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1947 } else if (isdraw) { 1948 DM hdm; 1949 1950 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1951 PetscCall(DMPlexView_Draw(hdm, viewer)); 1952 PetscCall(DMDestroy(&hdm)); 1953 } else if (isglvis) { 1954 PetscCall(DMPlexView_GLVis(dm, viewer)); 1955 #if defined(PETSC_HAVE_EXODUSII) 1956 } else if (isexodus) { 1957 /* 1958 exodusII requires that all sets be part of exactly one cell set. 1959 If the dm does not have a "Cell Sets" label defined, we create one 1960 with ID 1, containing all cells. 1961 Note that if the Cell Sets label is defined but does not cover all cells, 1962 we may still have a problem. This should probably be checked here or in the viewer; 1963 */ 1964 PetscInt numCS; 1965 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1966 if (!numCS) { 1967 PetscInt cStart, cEnd, c; 1968 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1969 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1970 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1971 } 1972 PetscCall(DMView_PlexExodusII(dm, viewer)); 1973 #endif 1974 #if defined(PETSC_HAVE_CGNS) 1975 } else if (iscgns) { 1976 PetscCall(DMView_PlexCGNS(dm, viewer)); 1977 #endif 1978 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1979 /* Optionally view the partition */ 1980 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1981 if (flg) { 1982 Vec ranks; 1983 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1984 PetscCall(VecView(ranks, viewer)); 1985 PetscCall(VecDestroy(&ranks)); 1986 } 1987 /* Optionally view a label */ 1988 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1989 if (flg) { 1990 DMLabel label; 1991 Vec val; 1992 1993 PetscCall(DMGetLabel(dm, name, &label)); 1994 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1995 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1996 PetscCall(VecView(val, viewer)); 1997 PetscCall(VecDestroy(&val)); 1998 } 1999 PetscFunctionReturn(PETSC_SUCCESS); 2000 } 2001 2002 /*@ 2003 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2004 2005 Collective 2006 2007 Input Parameters: 2008 + dm - The `DM` whose topology is to be saved 2009 - viewer - The `PetscViewer` to save it in 2010 2011 Level: advanced 2012 2013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2014 @*/ 2015 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2016 { 2017 PetscBool ishdf5; 2018 2019 PetscFunctionBegin; 2020 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2021 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2022 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2023 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2024 if (ishdf5) { 2025 #if defined(PETSC_HAVE_HDF5) 2026 PetscViewerFormat format; 2027 PetscCall(PetscViewerGetFormat(viewer, &format)); 2028 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2029 IS globalPointNumbering; 2030 2031 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2032 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2033 PetscCall(ISDestroy(&globalPointNumbering)); 2034 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2035 #else 2036 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2037 #endif 2038 } 2039 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2040 PetscFunctionReturn(PETSC_SUCCESS); 2041 } 2042 2043 /*@ 2044 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2045 2046 Collective 2047 2048 Input Parameters: 2049 + dm - The `DM` whose coordinates are to be saved 2050 - viewer - The `PetscViewer` for saving 2051 2052 Level: advanced 2053 2054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2055 @*/ 2056 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2057 { 2058 PetscBool ishdf5; 2059 2060 PetscFunctionBegin; 2061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2062 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2064 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2065 if (ishdf5) { 2066 #if defined(PETSC_HAVE_HDF5) 2067 PetscViewerFormat format; 2068 PetscCall(PetscViewerGetFormat(viewer, &format)); 2069 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2070 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2071 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2072 #else 2073 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2074 #endif 2075 } 2076 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2077 PetscFunctionReturn(PETSC_SUCCESS); 2078 } 2079 2080 /*@ 2081 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2082 2083 Collective 2084 2085 Input Parameters: 2086 + dm - The `DM` whose labels are to be saved 2087 - viewer - The `PetscViewer` for saving 2088 2089 Level: advanced 2090 2091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2092 @*/ 2093 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2094 { 2095 PetscBool ishdf5; 2096 2097 PetscFunctionBegin; 2098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2099 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2100 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2101 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2102 if (ishdf5) { 2103 #if defined(PETSC_HAVE_HDF5) 2104 IS globalPointNumbering; 2105 PetscViewerFormat format; 2106 2107 PetscCall(PetscViewerGetFormat(viewer, &format)); 2108 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2109 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2110 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2111 PetscCall(ISDestroy(&globalPointNumbering)); 2112 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2113 #else 2114 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2115 #endif 2116 } 2117 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2118 PetscFunctionReturn(PETSC_SUCCESS); 2119 } 2120 2121 /*@ 2122 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2123 2124 Collective 2125 2126 Input Parameters: 2127 + dm - The `DM` that contains the topology on which the section to be saved is defined 2128 . viewer - The `PetscViewer` for saving 2129 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2130 2131 Level: advanced 2132 2133 Notes: 2134 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. 2135 2136 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2137 2138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2139 @*/ 2140 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2141 { 2142 PetscBool ishdf5; 2143 2144 PetscFunctionBegin; 2145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2146 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2147 if (!sectiondm) sectiondm = dm; 2148 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2149 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2150 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2151 if (ishdf5) { 2152 #if defined(PETSC_HAVE_HDF5) 2153 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2154 #else 2155 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2156 #endif 2157 } 2158 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2159 PetscFunctionReturn(PETSC_SUCCESS); 2160 } 2161 2162 /*@ 2163 DMPlexGlobalVectorView - Saves a global vector 2164 2165 Collective 2166 2167 Input Parameters: 2168 + dm - The `DM` that represents the topology 2169 . viewer - The `PetscViewer` to save data with 2170 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2171 - vec - The global vector to be saved 2172 2173 Level: advanced 2174 2175 Notes: 2176 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2177 2178 Calling sequence: 2179 .vb 2180 DMCreate(PETSC_COMM_WORLD, &dm); 2181 DMSetType(dm, DMPLEX); 2182 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2183 DMClone(dm, §iondm); 2184 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2185 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2186 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2187 PetscSectionSetChart(section, pStart, pEnd); 2188 PetscSectionSetUp(section); 2189 DMSetLocalSection(sectiondm, section); 2190 PetscSectionDestroy(§ion); 2191 DMGetGlobalVector(sectiondm, &vec); 2192 PetscObjectSetName((PetscObject)vec, "vec_name"); 2193 DMPlexTopologyView(dm, viewer); 2194 DMPlexSectionView(dm, viewer, sectiondm); 2195 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2196 DMRestoreGlobalVector(sectiondm, &vec); 2197 DMDestroy(§iondm); 2198 DMDestroy(&dm); 2199 .ve 2200 2201 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2202 @*/ 2203 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2204 { 2205 PetscBool ishdf5; 2206 2207 PetscFunctionBegin; 2208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2209 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2210 if (!sectiondm) sectiondm = dm; 2211 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2212 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2213 /* Check consistency */ 2214 { 2215 PetscSection section; 2216 PetscBool includesConstraints; 2217 PetscInt m, m1; 2218 2219 PetscCall(VecGetLocalSize(vec, &m1)); 2220 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2221 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2222 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2223 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2224 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2225 } 2226 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2227 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2228 if (ishdf5) { 2229 #if defined(PETSC_HAVE_HDF5) 2230 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2231 #else 2232 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2233 #endif 2234 } 2235 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2236 PetscFunctionReturn(PETSC_SUCCESS); 2237 } 2238 2239 /*@ 2240 DMPlexLocalVectorView - Saves a local vector 2241 2242 Collective 2243 2244 Input Parameters: 2245 + dm - The `DM` that represents the topology 2246 . viewer - The `PetscViewer` to save data with 2247 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2248 - vec - The local vector to be saved 2249 2250 Level: advanced 2251 2252 Note: 2253 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2254 2255 Calling sequence: 2256 .vb 2257 DMCreate(PETSC_COMM_WORLD, &dm); 2258 DMSetType(dm, DMPLEX); 2259 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2260 DMClone(dm, §iondm); 2261 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2262 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2263 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2264 PetscSectionSetChart(section, pStart, pEnd); 2265 PetscSectionSetUp(section); 2266 DMSetLocalSection(sectiondm, section); 2267 DMGetLocalVector(sectiondm, &vec); 2268 PetscObjectSetName((PetscObject)vec, "vec_name"); 2269 DMPlexTopologyView(dm, viewer); 2270 DMPlexSectionView(dm, viewer, sectiondm); 2271 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2272 DMRestoreLocalVector(sectiondm, &vec); 2273 DMDestroy(§iondm); 2274 DMDestroy(&dm); 2275 .ve 2276 2277 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2278 @*/ 2279 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2280 { 2281 PetscBool ishdf5; 2282 2283 PetscFunctionBegin; 2284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2285 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2286 if (!sectiondm) sectiondm = dm; 2287 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2288 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2289 /* Check consistency */ 2290 { 2291 PetscSection section; 2292 PetscBool includesConstraints; 2293 PetscInt m, m1; 2294 2295 PetscCall(VecGetLocalSize(vec, &m1)); 2296 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2297 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2298 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2299 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2300 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2301 } 2302 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2303 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2307 #else 2308 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2309 #endif 2310 } 2311 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2312 PetscFunctionReturn(PETSC_SUCCESS); 2313 } 2314 2315 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2316 { 2317 PetscBool ishdf5; 2318 2319 PetscFunctionBegin; 2320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2321 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2322 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2323 if (ishdf5) { 2324 #if defined(PETSC_HAVE_HDF5) 2325 PetscViewerFormat format; 2326 PetscCall(PetscViewerGetFormat(viewer, &format)); 2327 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2328 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2329 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2330 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2331 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2332 PetscFunctionReturn(PETSC_SUCCESS); 2333 #else 2334 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2335 #endif 2336 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2337 } 2338 2339 /*@ 2340 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2341 2342 Collective 2343 2344 Input Parameters: 2345 + dm - The `DM` into which the topology is loaded 2346 - viewer - The `PetscViewer` for the saved topology 2347 2348 Output Parameter: 2349 . 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 2350 2351 Level: advanced 2352 2353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2354 `PetscViewer`, `PetscSF` 2355 @*/ 2356 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2357 { 2358 PetscBool ishdf5; 2359 2360 PetscFunctionBegin; 2361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2362 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2363 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2364 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2365 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2366 if (ishdf5) { 2367 #if defined(PETSC_HAVE_HDF5) 2368 PetscViewerFormat format; 2369 PetscCall(PetscViewerGetFormat(viewer, &format)); 2370 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2371 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2372 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2373 #else 2374 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2375 #endif 2376 } 2377 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2378 PetscFunctionReturn(PETSC_SUCCESS); 2379 } 2380 2381 /*@ 2382 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2383 2384 Collective 2385 2386 Input Parameters: 2387 + dm - The `DM` into which the coordinates are loaded 2388 . viewer - The `PetscViewer` for the saved coordinates 2389 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2390 2391 Level: advanced 2392 2393 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2394 `PetscSF`, `PetscViewer` 2395 @*/ 2396 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2397 { 2398 PetscBool ishdf5; 2399 2400 PetscFunctionBegin; 2401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2402 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2403 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2404 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2405 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2406 if (ishdf5) { 2407 #if defined(PETSC_HAVE_HDF5) 2408 PetscViewerFormat format; 2409 PetscCall(PetscViewerGetFormat(viewer, &format)); 2410 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2411 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2412 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2413 #else 2414 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2415 #endif 2416 } 2417 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2418 PetscFunctionReturn(PETSC_SUCCESS); 2419 } 2420 2421 /*@ 2422 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2423 2424 Collective 2425 2426 Input Parameters: 2427 + dm - The `DM` into which the labels are loaded 2428 . viewer - The `PetscViewer` for the saved labels 2429 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2430 2431 Level: advanced 2432 2433 Note: 2434 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2435 2436 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2437 `PetscSF`, `PetscViewer` 2438 @*/ 2439 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2440 { 2441 PetscBool ishdf5; 2442 2443 PetscFunctionBegin; 2444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2445 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2446 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2447 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2448 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2449 if (ishdf5) { 2450 #if defined(PETSC_HAVE_HDF5) 2451 PetscViewerFormat format; 2452 2453 PetscCall(PetscViewerGetFormat(viewer, &format)); 2454 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2455 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2456 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2457 #else 2458 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2459 #endif 2460 } 2461 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2462 PetscFunctionReturn(PETSC_SUCCESS); 2463 } 2464 2465 /*@ 2466 DMPlexSectionLoad - Loads section into a `DMPLEX` 2467 2468 Collective 2469 2470 Input Parameters: 2471 + dm - The `DM` that represents the topology 2472 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2473 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2474 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2475 2476 Output Parameters: 2477 + 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) 2478 - 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) 2479 2480 Level: advanced 2481 2482 Notes: 2483 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. 2484 2485 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2486 2487 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. 2488 2489 Example using 2 processes: 2490 .vb 2491 NX (number of points on dm): 4 2492 sectionA : the on-disk section 2493 vecA : a vector associated with sectionA 2494 sectionB : sectiondm's local section constructed in this function 2495 vecB (local) : a vector associated with sectiondm's local section 2496 vecB (global) : a vector associated with sectiondm's global section 2497 2498 rank 0 rank 1 2499 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2500 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2501 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2502 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2503 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2504 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2505 sectionB->atlasDof : 1 0 1 | 1 3 2506 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2507 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2508 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2509 .ve 2510 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2511 2512 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2513 @*/ 2514 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2515 { 2516 PetscBool ishdf5; 2517 2518 PetscFunctionBegin; 2519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2520 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2521 if (!sectiondm) sectiondm = dm; 2522 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2523 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2524 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2525 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2526 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2527 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2528 if (ishdf5) { 2529 #if defined(PETSC_HAVE_HDF5) 2530 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2531 #else 2532 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2533 #endif 2534 } 2535 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2536 PetscFunctionReturn(PETSC_SUCCESS); 2537 } 2538 2539 /*@ 2540 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2541 2542 Collective 2543 2544 Input Parameters: 2545 + dm - The `DM` that represents the topology 2546 . viewer - The `PetscViewer` that represents the on-disk vector data 2547 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2548 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2549 - vec - The global vector to set values of 2550 2551 Level: advanced 2552 2553 Notes: 2554 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2555 2556 Calling sequence: 2557 .vb 2558 DMCreate(PETSC_COMM_WORLD, &dm); 2559 DMSetType(dm, DMPLEX); 2560 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2561 DMPlexTopologyLoad(dm, viewer, &sfX); 2562 DMClone(dm, §iondm); 2563 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2564 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2565 DMGetGlobalVector(sectiondm, &vec); 2566 PetscObjectSetName((PetscObject)vec, "vec_name"); 2567 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2568 DMRestoreGlobalVector(sectiondm, &vec); 2569 PetscSFDestroy(&gsf); 2570 PetscSFDestroy(&sfX); 2571 DMDestroy(§iondm); 2572 DMDestroy(&dm); 2573 .ve 2574 2575 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2576 `PetscSF`, `PetscViewer` 2577 @*/ 2578 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2579 { 2580 PetscBool ishdf5; 2581 2582 PetscFunctionBegin; 2583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2584 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2585 if (!sectiondm) sectiondm = dm; 2586 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2587 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2588 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2589 /* Check consistency */ 2590 { 2591 PetscSection section; 2592 PetscBool includesConstraints; 2593 PetscInt m, m1; 2594 2595 PetscCall(VecGetLocalSize(vec, &m1)); 2596 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2597 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2598 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2599 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2600 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2601 } 2602 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2603 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2604 if (ishdf5) { 2605 #if defined(PETSC_HAVE_HDF5) 2606 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2607 #else 2608 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2609 #endif 2610 } 2611 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2612 PetscFunctionReturn(PETSC_SUCCESS); 2613 } 2614 2615 /*@ 2616 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2617 2618 Collective 2619 2620 Input Parameters: 2621 + dm - The `DM` that represents the topology 2622 . viewer - The `PetscViewer` that represents the on-disk vector data 2623 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2624 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2625 - vec - The local vector to set values of 2626 2627 Level: advanced 2628 2629 Notes: 2630 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object (or in case `sectiondm` is `NULL`) if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2631 2632 Calling sequence: 2633 .vb 2634 DMCreate(PETSC_COMM_WORLD, &dm); 2635 DMSetType(dm, DMPLEX); 2636 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2637 DMPlexTopologyLoad(dm, viewer, &sfX); 2638 DMClone(dm, §iondm); 2639 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2640 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2641 DMGetLocalVector(sectiondm, &vec); 2642 PetscObjectSetName((PetscObject)vec, "vec_name"); 2643 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2644 DMRestoreLocalVector(sectiondm, &vec); 2645 PetscSFDestroy(&lsf); 2646 PetscSFDestroy(&sfX); 2647 DMDestroy(§iondm); 2648 DMDestroy(&dm); 2649 .ve 2650 2651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2652 `PetscSF`, `PetscViewer` 2653 @*/ 2654 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2655 { 2656 PetscBool ishdf5; 2657 2658 PetscFunctionBegin; 2659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2660 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2661 if (!sectiondm) sectiondm = dm; 2662 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2663 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2664 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2665 /* Check consistency */ 2666 { 2667 PetscSection section; 2668 PetscBool includesConstraints; 2669 PetscInt m, m1; 2670 2671 PetscCall(VecGetLocalSize(vec, &m1)); 2672 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2673 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2674 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2675 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2676 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2677 } 2678 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2679 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2680 if (ishdf5) { 2681 #if defined(PETSC_HAVE_HDF5) 2682 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2683 #else 2684 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2685 #endif 2686 } 2687 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2688 PetscFunctionReturn(PETSC_SUCCESS); 2689 } 2690 2691 PetscErrorCode DMDestroy_Plex(DM dm) 2692 { 2693 DM_Plex *mesh = (DM_Plex *)dm->data; 2694 2695 PetscFunctionBegin; 2696 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2697 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2698 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2699 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2700 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2701 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2702 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2703 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2704 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2705 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2706 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2707 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2708 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2709 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2710 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2711 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2716 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2717 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2718 PetscCall(PetscFree(mesh->cones)); 2719 PetscCall(PetscFree(mesh->coneOrientations)); 2720 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2721 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2722 PetscCall(PetscFree(mesh->supports)); 2723 PetscCall(PetscFree(mesh->cellTypes)); 2724 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2725 PetscCall(PetscFree(mesh->tetgenOpts)); 2726 PetscCall(PetscFree(mesh->triangleOpts)); 2727 PetscCall(PetscFree(mesh->transformType)); 2728 PetscCall(PetscFree(mesh->distributionName)); 2729 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2730 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2731 PetscCall(ISDestroy(&mesh->subpointIS)); 2732 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2733 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2734 if (mesh->periodic.face_sfs) { 2735 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2736 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2737 } 2738 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2739 if (mesh->periodic.periodic_points) { 2740 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2741 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2742 } 2743 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2744 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2745 PetscCall(ISDestroy(&mesh->anchorIS)); 2746 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2747 PetscCall(PetscFree(mesh->parents)); 2748 PetscCall(PetscFree(mesh->childIDs)); 2749 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2750 PetscCall(PetscFree(mesh->children)); 2751 PetscCall(DMDestroy(&mesh->referenceTree)); 2752 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2753 PetscCall(PetscFree(mesh->neighbors)); 2754 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2755 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2756 PetscCall(PetscFree(mesh)); 2757 PetscFunctionReturn(PETSC_SUCCESS); 2758 } 2759 2760 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2761 { 2762 PetscSection sectionGlobal, sectionLocal; 2763 PetscInt bs = -1, mbs; 2764 PetscInt localSize, localStart = 0; 2765 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2766 MatType mtype; 2767 ISLocalToGlobalMapping ltog; 2768 2769 PetscFunctionBegin; 2770 PetscCall(MatInitializePackage()); 2771 mtype = dm->mattype; 2772 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2773 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2774 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2775 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2776 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2777 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2778 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2779 PetscCall(MatSetType(*J, mtype)); 2780 PetscCall(MatSetFromOptions(*J)); 2781 PetscCall(MatGetBlockSize(*J, &mbs)); 2782 if (mbs > 1) bs = mbs; 2783 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2784 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2785 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2786 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2787 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2788 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2789 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2790 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2791 if (!isShell) { 2792 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2793 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2794 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2795 2796 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2797 2798 PetscCall(PetscCalloc1(localSize, &pblocks)); 2799 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2800 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2801 for (p = pStart; p < pEnd; ++p) { 2802 switch (dm->blocking_type) { 2803 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2804 PetscInt bdof, offset; 2805 2806 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2807 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2808 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2809 if (dof > 0) { 2810 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2811 // Signal block concatenation 2812 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2813 } 2814 dof = dof < 0 ? -(dof + 1) : dof; 2815 bdof = cdof && (dof - cdof) ? 1 : dof; 2816 if (dof) { 2817 if (bs < 0) { 2818 bs = bdof; 2819 } else if (bs != bdof) { 2820 bs = 1; 2821 } 2822 } 2823 } break; 2824 case DM_BLOCKING_FIELD_NODE: { 2825 for (PetscInt field = 0; field < num_fields; field++) { 2826 PetscInt num_comp, bdof, offset; 2827 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2828 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2829 if (dof < 0) continue; 2830 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2831 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2832 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); 2833 PetscInt num_nodes = dof / num_comp; 2834 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2835 // Handle possibly constant block size (unlikely) 2836 bdof = cdof && (dof - cdof) ? 1 : dof; 2837 if (dof) { 2838 if (bs < 0) { 2839 bs = bdof; 2840 } else if (bs != bdof) { 2841 bs = 1; 2842 } 2843 } 2844 } 2845 } break; 2846 } 2847 } 2848 /* Must have same blocksize on all procs (some might have no points) */ 2849 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2850 bsLocal[1] = bs; 2851 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2852 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2853 else bs = bsMinMax[0]; 2854 bs = PetscMax(1, bs); 2855 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2856 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2857 PetscCall(MatSetBlockSize(*J, bs)); 2858 PetscCall(MatSetUp(*J)); 2859 } else { 2860 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2861 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2862 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2863 } 2864 if (pblocks) { // Consolidate blocks 2865 PetscInt nblocks = 0; 2866 pblocks[0] = PetscAbs(pblocks[0]); 2867 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2868 if (pblocks[i] == 0) continue; 2869 // Negative block size indicates the blocks should be concatenated 2870 if (pblocks[i] < 0) { 2871 pblocks[i] = -pblocks[i]; 2872 pblocks[nblocks - 1] += pblocks[i]; 2873 } else { 2874 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2875 } 2876 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]); 2877 } 2878 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2879 } 2880 PetscCall(PetscFree(pblocks)); 2881 } 2882 PetscCall(MatSetDM(*J, dm)); 2883 PetscFunctionReturn(PETSC_SUCCESS); 2884 } 2885 2886 /*@ 2887 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2888 2889 Not Collective 2890 2891 Input Parameter: 2892 . dm - The `DMPLEX` 2893 2894 Output Parameter: 2895 . subsection - The subdomain section 2896 2897 Level: developer 2898 2899 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2900 @*/ 2901 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2902 { 2903 DM_Plex *mesh = (DM_Plex *)dm->data; 2904 2905 PetscFunctionBegin; 2906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2907 if (!mesh->subdomainSection) { 2908 PetscSection section; 2909 PetscSF sf; 2910 2911 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2912 PetscCall(DMGetLocalSection(dm, §ion)); 2913 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2914 PetscCall(PetscSFDestroy(&sf)); 2915 } 2916 *subsection = mesh->subdomainSection; 2917 PetscFunctionReturn(PETSC_SUCCESS); 2918 } 2919 2920 /*@ 2921 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2922 2923 Not Collective 2924 2925 Input Parameter: 2926 . dm - The `DMPLEX` 2927 2928 Output Parameters: 2929 + pStart - The first mesh point 2930 - pEnd - The upper bound for mesh points 2931 2932 Level: beginner 2933 2934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2935 @*/ 2936 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2937 { 2938 DM_Plex *mesh = (DM_Plex *)dm->data; 2939 2940 PetscFunctionBegin; 2941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2942 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2943 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2944 PetscFunctionReturn(PETSC_SUCCESS); 2945 } 2946 2947 /*@ 2948 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2949 2950 Not Collective 2951 2952 Input Parameters: 2953 + dm - The `DMPLEX` 2954 . pStart - The first mesh point 2955 - pEnd - The upper bound for mesh points 2956 2957 Level: beginner 2958 2959 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2960 @*/ 2961 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2962 { 2963 DM_Plex *mesh = (DM_Plex *)dm->data; 2964 2965 PetscFunctionBegin; 2966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2967 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2968 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2969 PetscCall(PetscFree(mesh->cellTypes)); 2970 PetscFunctionReturn(PETSC_SUCCESS); 2971 } 2972 2973 /*@ 2974 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2975 2976 Not Collective 2977 2978 Input Parameters: 2979 + dm - The `DMPLEX` 2980 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2981 2982 Output Parameter: 2983 . size - The cone size for point `p` 2984 2985 Level: beginner 2986 2987 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2988 @*/ 2989 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2990 { 2991 DM_Plex *mesh = (DM_Plex *)dm->data; 2992 2993 PetscFunctionBegin; 2994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2995 PetscAssertPointer(size, 3); 2996 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2997 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2998 PetscFunctionReturn(PETSC_SUCCESS); 2999 } 3000 3001 /*@ 3002 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3003 3004 Not Collective 3005 3006 Input Parameters: 3007 + dm - The `DMPLEX` 3008 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3009 - size - The cone size for point `p` 3010 3011 Level: beginner 3012 3013 Note: 3014 This should be called after `DMPlexSetChart()`. 3015 3016 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3017 @*/ 3018 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3019 { 3020 DM_Plex *mesh = (DM_Plex *)dm->data; 3021 3022 PetscFunctionBegin; 3023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3024 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3025 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3026 PetscFunctionReturn(PETSC_SUCCESS); 3027 } 3028 3029 /*@C 3030 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3031 3032 Not Collective 3033 3034 Input Parameters: 3035 + dm - The `DMPLEX` 3036 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3037 3038 Output Parameter: 3039 . cone - An array of points which are on the in-edges for point `p` 3040 3041 Level: beginner 3042 3043 Fortran Notes: 3044 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3045 `DMPlexRestoreCone()` is not needed/available in C. 3046 3047 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3048 @*/ 3049 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3050 { 3051 DM_Plex *mesh = (DM_Plex *)dm->data; 3052 PetscInt off; 3053 3054 PetscFunctionBegin; 3055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3056 PetscAssertPointer(cone, 3); 3057 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3058 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3059 PetscFunctionReturn(PETSC_SUCCESS); 3060 } 3061 3062 /*@ 3063 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3064 3065 Not Collective 3066 3067 Input Parameters: 3068 + dm - The `DMPLEX` 3069 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3070 3071 Output Parameters: 3072 + pConesSection - `PetscSection` describing the layout of `pCones` 3073 - pCones - An array of points which are on the in-edges for the point set `p` 3074 3075 Level: intermediate 3076 3077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3078 @*/ 3079 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3080 { 3081 PetscSection cs, newcs; 3082 PetscInt *cones; 3083 PetscInt *newarr = NULL; 3084 PetscInt n; 3085 3086 PetscFunctionBegin; 3087 PetscCall(DMPlexGetCones(dm, &cones)); 3088 PetscCall(DMPlexGetConeSection(dm, &cs)); 3089 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3090 if (pConesSection) *pConesSection = newcs; 3091 if (pCones) { 3092 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3093 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3094 } 3095 PetscFunctionReturn(PETSC_SUCCESS); 3096 } 3097 3098 /*@ 3099 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3100 3101 Not Collective 3102 3103 Input Parameters: 3104 + dm - The `DMPLEX` 3105 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3106 3107 Output Parameter: 3108 . expandedPoints - An array of vertices recursively expanded from input points 3109 3110 Level: advanced 3111 3112 Notes: 3113 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3114 3115 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3116 3117 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3118 `DMPlexGetDepth()`, `IS` 3119 @*/ 3120 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3121 { 3122 IS *expandedPointsAll; 3123 PetscInt depth; 3124 3125 PetscFunctionBegin; 3126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3127 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3128 PetscAssertPointer(expandedPoints, 3); 3129 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3130 *expandedPoints = expandedPointsAll[0]; 3131 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3132 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3133 PetscFunctionReturn(PETSC_SUCCESS); 3134 } 3135 3136 /*@ 3137 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). 3138 3139 Not Collective 3140 3141 Input Parameters: 3142 + dm - The `DMPLEX` 3143 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3144 3145 Output Parameters: 3146 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3147 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3148 - sections - (optional) An array of sections which describe mappings from points to their cone points 3149 3150 Level: advanced 3151 3152 Notes: 3153 Like `DMPlexGetConeTuple()` but recursive. 3154 3155 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. 3156 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3157 3158 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\: 3159 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3160 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3161 3162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3163 `DMPlexGetDepth()`, `PetscSection`, `IS` 3164 @*/ 3165 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3166 { 3167 const PetscInt *arr0 = NULL, *cone = NULL; 3168 PetscInt *arr = NULL, *newarr = NULL; 3169 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3170 IS *expandedPoints_; 3171 PetscSection *sections_; 3172 3173 PetscFunctionBegin; 3174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3175 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3176 if (depth) PetscAssertPointer(depth, 3); 3177 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3178 if (sections) PetscAssertPointer(sections, 5); 3179 PetscCall(ISGetLocalSize(points, &n)); 3180 PetscCall(ISGetIndices(points, &arr0)); 3181 PetscCall(DMPlexGetDepth(dm, &depth_)); 3182 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3183 PetscCall(PetscCalloc1(depth_, §ions_)); 3184 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3185 for (d = depth_ - 1; d >= 0; d--) { 3186 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3187 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3188 for (i = 0; i < n; i++) { 3189 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3190 if (arr[i] >= start && arr[i] < end) { 3191 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3192 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3193 } else { 3194 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3195 } 3196 } 3197 PetscCall(PetscSectionSetUp(sections_[d])); 3198 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3199 PetscCall(PetscMalloc1(newn, &newarr)); 3200 for (i = 0; i < n; i++) { 3201 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3202 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3203 if (cn > 1) { 3204 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3205 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3206 } else { 3207 newarr[co] = arr[i]; 3208 } 3209 } 3210 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3211 arr = newarr; 3212 n = newn; 3213 } 3214 PetscCall(ISRestoreIndices(points, &arr0)); 3215 *depth = depth_; 3216 if (expandedPoints) *expandedPoints = expandedPoints_; 3217 else { 3218 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3219 PetscCall(PetscFree(expandedPoints_)); 3220 } 3221 if (sections) *sections = sections_; 3222 else { 3223 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3224 PetscCall(PetscFree(sections_)); 3225 } 3226 PetscFunctionReturn(PETSC_SUCCESS); 3227 } 3228 3229 /*@ 3230 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3231 3232 Not Collective 3233 3234 Input Parameters: 3235 + dm - The `DMPLEX` 3236 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3237 3238 Output Parameters: 3239 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3240 . expandedPoints - (optional) An array of recursively expanded cones 3241 - sections - (optional) An array of sections which describe mappings from points to their cone points 3242 3243 Level: advanced 3244 3245 Note: 3246 See `DMPlexGetConeRecursive()` 3247 3248 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3249 `DMPlexGetDepth()`, `IS`, `PetscSection` 3250 @*/ 3251 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3252 { 3253 PetscInt d, depth_; 3254 3255 PetscFunctionBegin; 3256 PetscCall(DMPlexGetDepth(dm, &depth_)); 3257 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3258 if (depth) *depth = 0; 3259 if (expandedPoints) { 3260 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3261 PetscCall(PetscFree(*expandedPoints)); 3262 } 3263 if (sections) { 3264 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3265 PetscCall(PetscFree(*sections)); 3266 } 3267 PetscFunctionReturn(PETSC_SUCCESS); 3268 } 3269 3270 /*@ 3271 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 3272 3273 Not Collective 3274 3275 Input Parameters: 3276 + dm - The `DMPLEX` 3277 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3278 - cone - An array of points which are on the in-edges for point `p` 3279 3280 Level: beginner 3281 3282 Note: 3283 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3284 3285 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3286 @*/ 3287 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3288 { 3289 DM_Plex *mesh = (DM_Plex *)dm->data; 3290 PetscInt dof, off, c; 3291 3292 PetscFunctionBegin; 3293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3294 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3295 if (dof) PetscAssertPointer(cone, 3); 3296 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3297 if (PetscDefined(USE_DEBUG)) { 3298 PetscInt pStart, pEnd; 3299 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3300 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); 3301 for (c = 0; c < dof; ++c) { 3302 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); 3303 mesh->cones[off + c] = cone[c]; 3304 } 3305 } else { 3306 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3307 } 3308 PetscFunctionReturn(PETSC_SUCCESS); 3309 } 3310 3311 /*@C 3312 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3313 3314 Not Collective 3315 3316 Input Parameters: 3317 + dm - The `DMPLEX` 3318 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3319 3320 Output Parameter: 3321 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3322 integer giving the prescription for cone traversal. 3323 3324 Level: beginner 3325 3326 Note: 3327 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3328 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3329 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3330 with the identity. 3331 3332 Fortran Notes: 3333 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3334 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3335 3336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3337 @*/ 3338 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3339 { 3340 DM_Plex *mesh = (DM_Plex *)dm->data; 3341 PetscInt off; 3342 3343 PetscFunctionBegin; 3344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3345 if (PetscDefined(USE_DEBUG)) { 3346 PetscInt dof; 3347 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3348 if (dof) PetscAssertPointer(coneOrientation, 3); 3349 } 3350 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3351 3352 *coneOrientation = &mesh->coneOrientations[off]; 3353 PetscFunctionReturn(PETSC_SUCCESS); 3354 } 3355 3356 /*@ 3357 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point 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 - coneOrientation - An array of orientations 3365 3366 Level: beginner 3367 3368 Notes: 3369 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3370 3371 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3372 3373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3374 @*/ 3375 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3376 { 3377 DM_Plex *mesh = (DM_Plex *)dm->data; 3378 PetscInt pStart, pEnd; 3379 PetscInt dof, off, c; 3380 3381 PetscFunctionBegin; 3382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3383 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3384 if (dof) PetscAssertPointer(coneOrientation, 3); 3385 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3386 if (PetscDefined(USE_DEBUG)) { 3387 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3388 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); 3389 for (c = 0; c < dof; ++c) { 3390 PetscInt cdof, o = coneOrientation[c]; 3391 3392 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3393 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); 3394 mesh->coneOrientations[off + c] = o; 3395 } 3396 } else { 3397 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3398 } 3399 PetscFunctionReturn(PETSC_SUCCESS); 3400 } 3401 3402 /*@ 3403 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3404 3405 Not Collective 3406 3407 Input Parameters: 3408 + dm - The `DMPLEX` 3409 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3410 . conePos - The local index in the cone where the point should be put 3411 - conePoint - The mesh point to insert 3412 3413 Level: beginner 3414 3415 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3416 @*/ 3417 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3418 { 3419 DM_Plex *mesh = (DM_Plex *)dm->data; 3420 PetscInt pStart, pEnd; 3421 PetscInt dof, off; 3422 3423 PetscFunctionBegin; 3424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3425 if (PetscDefined(USE_DEBUG)) { 3426 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3427 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); 3428 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); 3429 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3430 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); 3431 } 3432 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3433 mesh->cones[off + conePos] = conePoint; 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /*@ 3438 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3439 3440 Not Collective 3441 3442 Input Parameters: 3443 + dm - The `DMPLEX` 3444 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3445 . conePos - The local index in the cone where the point should be put 3446 - coneOrientation - The point orientation to insert 3447 3448 Level: beginner 3449 3450 Note: 3451 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3452 3453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3454 @*/ 3455 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3456 { 3457 DM_Plex *mesh = (DM_Plex *)dm->data; 3458 PetscInt pStart, pEnd; 3459 PetscInt dof, off; 3460 3461 PetscFunctionBegin; 3462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3463 if (PetscDefined(USE_DEBUG)) { 3464 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3465 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); 3466 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3467 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); 3468 } 3469 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3470 mesh->coneOrientations[off + conePos] = coneOrientation; 3471 PetscFunctionReturn(PETSC_SUCCESS); 3472 } 3473 3474 /*@C 3475 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3476 3477 Not collective 3478 3479 Input Parameters: 3480 + dm - The DMPlex 3481 - p - The point, which must lie in the chart set with DMPlexSetChart() 3482 3483 Output Parameters: 3484 + cone - An array of points which are on the in-edges for point `p` 3485 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3486 integer giving the prescription for cone traversal. 3487 3488 Level: beginner 3489 3490 Notes: 3491 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3492 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3493 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3494 with the identity. 3495 3496 Fortran Notes: 3497 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3498 `DMPlexRestoreCone()` is not needed/available in C. 3499 3500 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3501 @*/ 3502 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3503 { 3504 DM_Plex *mesh = (DM_Plex *)dm->data; 3505 3506 PetscFunctionBegin; 3507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3508 if (mesh->tr) { 3509 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3510 } else { 3511 PetscInt off; 3512 if (PetscDefined(USE_DEBUG)) { 3513 PetscInt dof; 3514 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3515 if (dof) { 3516 if (cone) PetscAssertPointer(cone, 3); 3517 if (ornt) PetscAssertPointer(ornt, 4); 3518 } 3519 } 3520 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3521 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3522 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3523 } 3524 PetscFunctionReturn(PETSC_SUCCESS); 3525 } 3526 3527 /*@C 3528 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3529 3530 Not Collective 3531 3532 Input Parameters: 3533 + dm - The DMPlex 3534 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3535 . cone - An array of points which are on the in-edges for point p 3536 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3537 integer giving the prescription for cone traversal. 3538 3539 Level: beginner 3540 3541 Notes: 3542 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3543 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3544 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3545 with the identity. 3546 3547 Fortran Notes: 3548 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3549 `DMPlexRestoreCone()` is not needed/available in C. 3550 3551 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3552 @*/ 3553 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3554 { 3555 DM_Plex *mesh = (DM_Plex *)dm->data; 3556 3557 PetscFunctionBegin; 3558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3559 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3560 PetscFunctionReturn(PETSC_SUCCESS); 3561 } 3562 3563 /*@ 3564 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3565 3566 Not Collective 3567 3568 Input Parameters: 3569 + dm - The `DMPLEX` 3570 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3571 3572 Output Parameter: 3573 . size - The support size for point `p` 3574 3575 Level: beginner 3576 3577 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3578 @*/ 3579 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3580 { 3581 DM_Plex *mesh = (DM_Plex *)dm->data; 3582 3583 PetscFunctionBegin; 3584 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3585 PetscAssertPointer(size, 3); 3586 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3587 PetscFunctionReturn(PETSC_SUCCESS); 3588 } 3589 3590 /*@ 3591 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3592 3593 Not Collective 3594 3595 Input Parameters: 3596 + dm - The `DMPLEX` 3597 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3598 - size - The support size for point `p` 3599 3600 Level: beginner 3601 3602 Note: 3603 This should be called after `DMPlexSetChart()`. 3604 3605 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3606 @*/ 3607 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3608 { 3609 DM_Plex *mesh = (DM_Plex *)dm->data; 3610 3611 PetscFunctionBegin; 3612 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3613 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3614 PetscFunctionReturn(PETSC_SUCCESS); 3615 } 3616 3617 /*@C 3618 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3619 3620 Not Collective 3621 3622 Input Parameters: 3623 + dm - The `DMPLEX` 3624 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3625 3626 Output Parameter: 3627 . support - An array of points which are on the out-edges for point `p` 3628 3629 Level: beginner 3630 3631 Fortran Notes: 3632 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3633 `DMPlexRestoreSupport()` is not needed/available in C. 3634 3635 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3636 @*/ 3637 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3638 { 3639 DM_Plex *mesh = (DM_Plex *)dm->data; 3640 PetscInt off; 3641 3642 PetscFunctionBegin; 3643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3644 PetscAssertPointer(support, 3); 3645 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3646 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3647 PetscFunctionReturn(PETSC_SUCCESS); 3648 } 3649 3650 /*@ 3651 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3652 3653 Not Collective 3654 3655 Input Parameters: 3656 + dm - The `DMPLEX` 3657 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3658 - support - An array of points which are on the out-edges for point `p` 3659 3660 Level: beginner 3661 3662 Note: 3663 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3664 3665 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3666 @*/ 3667 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3668 { 3669 DM_Plex *mesh = (DM_Plex *)dm->data; 3670 PetscInt pStart, pEnd; 3671 PetscInt dof, off, c; 3672 3673 PetscFunctionBegin; 3674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3675 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3676 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3677 if (dof) PetscAssertPointer(support, 3); 3678 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3679 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); 3680 for (c = 0; c < dof; ++c) { 3681 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); 3682 mesh->supports[off + c] = support[c]; 3683 } 3684 PetscFunctionReturn(PETSC_SUCCESS); 3685 } 3686 3687 /*@ 3688 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3689 3690 Not Collective 3691 3692 Input Parameters: 3693 + dm - The `DMPLEX` 3694 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3695 . supportPos - The local index in the cone where the point should be put 3696 - supportPoint - The mesh point to insert 3697 3698 Level: beginner 3699 3700 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3701 @*/ 3702 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3703 { 3704 DM_Plex *mesh = (DM_Plex *)dm->data; 3705 PetscInt pStart, pEnd; 3706 PetscInt dof, off; 3707 3708 PetscFunctionBegin; 3709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3710 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3711 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3712 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3713 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); 3714 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); 3715 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); 3716 mesh->supports[off + supportPos] = supportPoint; 3717 PetscFunctionReturn(PETSC_SUCCESS); 3718 } 3719 3720 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3721 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3722 { 3723 switch (ct) { 3724 case DM_POLYTOPE_SEGMENT: 3725 if (o == -1) return -2; 3726 break; 3727 case DM_POLYTOPE_TRIANGLE: 3728 if (o == -3) return -1; 3729 if (o == -2) return -3; 3730 if (o == -1) return -2; 3731 break; 3732 case DM_POLYTOPE_QUADRILATERAL: 3733 if (o == -4) return -2; 3734 if (o == -3) return -1; 3735 if (o == -2) return -4; 3736 if (o == -1) return -3; 3737 break; 3738 default: 3739 return o; 3740 } 3741 return o; 3742 } 3743 3744 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3745 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3746 { 3747 switch (ct) { 3748 case DM_POLYTOPE_SEGMENT: 3749 if ((o == -2) || (o == 1)) return -1; 3750 if (o == -1) return 0; 3751 break; 3752 case DM_POLYTOPE_TRIANGLE: 3753 if (o == -3) return -2; 3754 if (o == -2) return -1; 3755 if (o == -1) return -3; 3756 break; 3757 case DM_POLYTOPE_QUADRILATERAL: 3758 if (o == -4) return -2; 3759 if (o == -3) return -1; 3760 if (o == -2) return -4; 3761 if (o == -1) return -3; 3762 break; 3763 default: 3764 return o; 3765 } 3766 return o; 3767 } 3768 3769 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3770 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3771 { 3772 PetscInt pStart, pEnd, p; 3773 3774 PetscFunctionBegin; 3775 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3776 for (p = pStart; p < pEnd; ++p) { 3777 const PetscInt *cone, *ornt; 3778 PetscInt coneSize, c; 3779 3780 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3781 PetscCall(DMPlexGetCone(dm, p, &cone)); 3782 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3783 for (c = 0; c < coneSize; ++c) { 3784 DMPolytopeType ct; 3785 const PetscInt o = ornt[c]; 3786 3787 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3788 switch (ct) { 3789 case DM_POLYTOPE_SEGMENT: 3790 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3791 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3792 break; 3793 case DM_POLYTOPE_TRIANGLE: 3794 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3795 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3796 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3797 break; 3798 case DM_POLYTOPE_QUADRILATERAL: 3799 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3800 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3801 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3802 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3803 break; 3804 default: 3805 break; 3806 } 3807 } 3808 } 3809 PetscFunctionReturn(PETSC_SUCCESS); 3810 } 3811 3812 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3813 { 3814 DM_Plex *mesh = (DM_Plex *)dm->data; 3815 3816 PetscFunctionBeginHot; 3817 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3818 if (useCone) { 3819 PetscCall(DMPlexGetConeSize(dm, p, size)); 3820 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3821 } else { 3822 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3823 PetscCall(DMPlexGetSupport(dm, p, arr)); 3824 } 3825 } else { 3826 if (useCone) { 3827 const PetscSection s = mesh->coneSection; 3828 const PetscInt ps = p - s->pStart; 3829 const PetscInt off = s->atlasOff[ps]; 3830 3831 *size = s->atlasDof[ps]; 3832 *arr = mesh->cones + off; 3833 *ornt = mesh->coneOrientations + off; 3834 } else { 3835 const PetscSection s = mesh->supportSection; 3836 const PetscInt ps = p - s->pStart; 3837 const PetscInt off = s->atlasOff[ps]; 3838 3839 *size = s->atlasDof[ps]; 3840 *arr = mesh->supports + off; 3841 } 3842 } 3843 PetscFunctionReturn(PETSC_SUCCESS); 3844 } 3845 3846 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3847 { 3848 DM_Plex *mesh = (DM_Plex *)dm->data; 3849 3850 PetscFunctionBeginHot; 3851 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3852 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3853 } 3854 PetscFunctionReturn(PETSC_SUCCESS); 3855 } 3856 3857 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3858 { 3859 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3860 PetscInt *closure; 3861 const PetscInt *tmp = NULL, *tmpO = NULL; 3862 PetscInt off = 0, tmpSize, t; 3863 3864 PetscFunctionBeginHot; 3865 if (ornt) { 3866 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3867 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; 3868 } 3869 if (*points) { 3870 closure = *points; 3871 } else { 3872 PetscInt maxConeSize, maxSupportSize; 3873 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3874 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3875 } 3876 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3877 if (ct == DM_POLYTOPE_UNKNOWN) { 3878 closure[off++] = p; 3879 closure[off++] = 0; 3880 for (t = 0; t < tmpSize; ++t) { 3881 closure[off++] = tmp[t]; 3882 closure[off++] = tmpO ? tmpO[t] : 0; 3883 } 3884 } else { 3885 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3886 3887 /* We assume that cells with a valid type have faces with a valid type */ 3888 closure[off++] = p; 3889 closure[off++] = ornt; 3890 for (t = 0; t < tmpSize; ++t) { 3891 DMPolytopeType ft; 3892 3893 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3894 closure[off++] = tmp[arr[t]]; 3895 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3896 } 3897 } 3898 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3899 if (numPoints) *numPoints = tmpSize + 1; 3900 if (points) *points = closure; 3901 PetscFunctionReturn(PETSC_SUCCESS); 3902 } 3903 3904 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3905 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3906 { 3907 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3908 const PetscInt *cone, *ornt; 3909 PetscInt *pts, *closure = NULL; 3910 DMPolytopeType ft; 3911 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3912 PetscInt dim, coneSize, c, d, clSize, cl; 3913 3914 PetscFunctionBeginHot; 3915 PetscCall(DMGetDimension(dm, &dim)); 3916 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3917 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3918 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3919 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3920 maxSize = PetscMax(coneSeries, supportSeries); 3921 if (*points) { 3922 pts = *points; 3923 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3924 c = 0; 3925 pts[c++] = point; 3926 pts[c++] = o; 3927 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3928 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3929 for (cl = 0; cl < clSize * 2; cl += 2) { 3930 pts[c++] = closure[cl]; 3931 pts[c++] = closure[cl + 1]; 3932 } 3933 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3934 for (cl = 0; cl < clSize * 2; cl += 2) { 3935 pts[c++] = closure[cl]; 3936 pts[c++] = closure[cl + 1]; 3937 } 3938 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3939 for (d = 2; d < coneSize; ++d) { 3940 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3941 pts[c++] = cone[arr[d * 2 + 0]]; 3942 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3943 } 3944 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3945 if (dim >= 3) { 3946 for (d = 2; d < coneSize; ++d) { 3947 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3948 const PetscInt *fcone, *fornt; 3949 PetscInt fconeSize, fc, i; 3950 3951 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3952 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3953 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3954 for (fc = 0; fc < fconeSize; ++fc) { 3955 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3956 const PetscInt co = farr[fc * 2 + 1]; 3957 3958 for (i = 0; i < c; i += 2) 3959 if (pts[i] == cp) break; 3960 if (i == c) { 3961 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3962 pts[c++] = cp; 3963 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3964 } 3965 } 3966 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3967 } 3968 } 3969 *numPoints = c / 2; 3970 *points = pts; 3971 PetscFunctionReturn(PETSC_SUCCESS); 3972 } 3973 3974 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3975 { 3976 DMPolytopeType ct; 3977 PetscInt *closure, *fifo; 3978 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3979 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3980 PetscInt depth, maxSize; 3981 3982 PetscFunctionBeginHot; 3983 PetscCall(DMPlexGetDepth(dm, &depth)); 3984 if (depth == 1) { 3985 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3986 PetscFunctionReturn(PETSC_SUCCESS); 3987 } 3988 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3989 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; 3990 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3991 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3992 PetscFunctionReturn(PETSC_SUCCESS); 3993 } 3994 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3995 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3996 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3997 maxSize = PetscMax(coneSeries, supportSeries); 3998 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3999 if (*points) { 4000 closure = *points; 4001 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4002 closure[closureSize++] = p; 4003 closure[closureSize++] = ornt; 4004 fifo[fifoSize++] = p; 4005 fifo[fifoSize++] = ornt; 4006 fifo[fifoSize++] = ct; 4007 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4008 while (fifoSize - fifoStart) { 4009 const PetscInt q = fifo[fifoStart++]; 4010 const PetscInt o = fifo[fifoStart++]; 4011 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4012 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4013 const PetscInt *tmp, *tmpO = NULL; 4014 PetscInt tmpSize, t; 4015 4016 if (PetscDefined(USE_DEBUG)) { 4017 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4018 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); 4019 } 4020 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4021 for (t = 0; t < tmpSize; ++t) { 4022 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4023 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4024 const PetscInt cp = tmp[ip]; 4025 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4026 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4027 PetscInt c; 4028 4029 /* Check for duplicate */ 4030 for (c = 0; c < closureSize; c += 2) { 4031 if (closure[c] == cp) break; 4032 } 4033 if (c == closureSize) { 4034 closure[closureSize++] = cp; 4035 closure[closureSize++] = co; 4036 fifo[fifoSize++] = cp; 4037 fifo[fifoSize++] = co; 4038 fifo[fifoSize++] = ct; 4039 } 4040 } 4041 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4042 } 4043 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4044 if (numPoints) *numPoints = closureSize / 2; 4045 if (points) *points = closure; 4046 PetscFunctionReturn(PETSC_SUCCESS); 4047 } 4048 4049 /*@C 4050 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4051 4052 Not Collective 4053 4054 Input Parameters: 4055 + dm - The `DMPLEX` 4056 . p - The mesh point 4057 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4058 4059 Input/Output Parameter: 4060 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4061 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4062 4063 Output Parameter: 4064 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4065 4066 Level: beginner 4067 4068 Note: 4069 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4070 4071 Fortran Notes: 4072 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4073 4074 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4075 @*/ 4076 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4077 { 4078 PetscFunctionBeginHot; 4079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4080 if (numPoints) PetscAssertPointer(numPoints, 4); 4081 if (points) PetscAssertPointer(points, 5); 4082 if (PetscDefined(USE_DEBUG)) { 4083 PetscInt pStart, pEnd; 4084 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4085 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4086 } 4087 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4088 PetscFunctionReturn(PETSC_SUCCESS); 4089 } 4090 4091 /*@C 4092 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4093 4094 Not Collective 4095 4096 Input Parameters: 4097 + dm - The `DMPLEX` 4098 . p - The mesh point 4099 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4100 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4101 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4102 4103 Level: beginner 4104 4105 Note: 4106 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4107 4108 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4109 @*/ 4110 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4111 { 4112 PetscFunctionBeginHot; 4113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4114 if (numPoints) *numPoints = 0; 4115 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4116 PetscFunctionReturn(PETSC_SUCCESS); 4117 } 4118 4119 /*@ 4120 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4121 4122 Not Collective 4123 4124 Input Parameter: 4125 . dm - The `DMPLEX` 4126 4127 Output Parameters: 4128 + maxConeSize - The maximum number of in-edges 4129 - maxSupportSize - The maximum number of out-edges 4130 4131 Level: beginner 4132 4133 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4134 @*/ 4135 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4136 { 4137 DM_Plex *mesh = (DM_Plex *)dm->data; 4138 4139 PetscFunctionBegin; 4140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4141 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4142 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4143 PetscFunctionReturn(PETSC_SUCCESS); 4144 } 4145 4146 PetscErrorCode DMSetUp_Plex(DM dm) 4147 { 4148 DM_Plex *mesh = (DM_Plex *)dm->data; 4149 PetscInt size, maxSupportSize; 4150 4151 PetscFunctionBegin; 4152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4153 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4154 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4155 PetscCall(PetscMalloc1(size, &mesh->cones)); 4156 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4157 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4158 if (maxSupportSize) { 4159 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4160 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4161 PetscCall(PetscMalloc1(size, &mesh->supports)); 4162 } 4163 PetscFunctionReturn(PETSC_SUCCESS); 4164 } 4165 4166 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4167 { 4168 PetscFunctionBegin; 4169 if (subdm) PetscCall(DMClone(dm, subdm)); 4170 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4171 if (subdm) (*subdm)->useNatural = dm->useNatural; 4172 if (dm->useNatural && dm->sfMigration) { 4173 PetscSF sfNatural; 4174 4175 (*subdm)->sfMigration = dm->sfMigration; 4176 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4177 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4178 (*subdm)->sfNatural = sfNatural; 4179 } 4180 PetscFunctionReturn(PETSC_SUCCESS); 4181 } 4182 4183 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4184 { 4185 PetscInt i = 0; 4186 4187 PetscFunctionBegin; 4188 PetscCall(DMClone(dms[0], superdm)); 4189 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4190 (*superdm)->useNatural = PETSC_FALSE; 4191 for (i = 0; i < len; i++) { 4192 if (dms[i]->useNatural && dms[i]->sfMigration) { 4193 PetscSF sfNatural; 4194 4195 (*superdm)->sfMigration = dms[i]->sfMigration; 4196 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4197 (*superdm)->useNatural = PETSC_TRUE; 4198 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4199 (*superdm)->sfNatural = sfNatural; 4200 break; 4201 } 4202 } 4203 PetscFunctionReturn(PETSC_SUCCESS); 4204 } 4205 4206 /*@ 4207 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4208 4209 Not Collective 4210 4211 Input Parameter: 4212 . dm - The `DMPLEX` 4213 4214 Level: beginner 4215 4216 Note: 4217 This should be called after all calls to `DMPlexSetCone()` 4218 4219 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4220 @*/ 4221 PetscErrorCode DMPlexSymmetrize(DM dm) 4222 { 4223 DM_Plex *mesh = (DM_Plex *)dm->data; 4224 PetscInt *offsets; 4225 PetscInt supportSize; 4226 PetscInt pStart, pEnd, p; 4227 4228 PetscFunctionBegin; 4229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4230 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4231 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4232 /* Calculate support sizes */ 4233 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4234 for (p = pStart; p < pEnd; ++p) { 4235 PetscInt dof, off, c; 4236 4237 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4238 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4239 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4240 } 4241 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4242 /* Calculate supports */ 4243 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4244 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4245 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4246 for (p = pStart; p < pEnd; ++p) { 4247 PetscInt dof, off, c; 4248 4249 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4250 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4251 for (c = off; c < off + dof; ++c) { 4252 const PetscInt q = mesh->cones[c]; 4253 PetscInt offS; 4254 4255 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4256 4257 mesh->supports[offS + offsets[q]] = p; 4258 ++offsets[q]; 4259 } 4260 } 4261 PetscCall(PetscFree(offsets)); 4262 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4263 PetscFunctionReturn(PETSC_SUCCESS); 4264 } 4265 4266 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4267 { 4268 IS stratumIS; 4269 4270 PetscFunctionBegin; 4271 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4272 if (PetscDefined(USE_DEBUG)) { 4273 PetscInt qStart, qEnd, numLevels, level; 4274 PetscBool overlap = PETSC_FALSE; 4275 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4276 for (level = 0; level < numLevels; level++) { 4277 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4278 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4279 overlap = PETSC_TRUE; 4280 break; 4281 } 4282 } 4283 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); 4284 } 4285 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4286 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4287 PetscCall(ISDestroy(&stratumIS)); 4288 PetscFunctionReturn(PETSC_SUCCESS); 4289 } 4290 4291 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4292 { 4293 PetscInt *pMin, *pMax; 4294 PetscInt pStart, pEnd; 4295 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4296 4297 PetscFunctionBegin; 4298 { 4299 DMLabel label2; 4300 4301 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4302 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4303 } 4304 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4305 for (PetscInt p = pStart; p < pEnd; ++p) { 4306 DMPolytopeType ct; 4307 4308 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4309 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4310 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4311 } 4312 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4313 for (PetscInt d = dmin; d <= dmax; ++d) { 4314 pMin[d] = PETSC_MAX_INT; 4315 pMax[d] = PETSC_MIN_INT; 4316 } 4317 for (PetscInt p = pStart; p < pEnd; ++p) { 4318 DMPolytopeType ct; 4319 PetscInt d; 4320 4321 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4322 d = DMPolytopeTypeGetDim(ct); 4323 pMin[d] = PetscMin(p, pMin[d]); 4324 pMax[d] = PetscMax(p, pMax[d]); 4325 } 4326 for (PetscInt d = dmin; d <= dmax; ++d) { 4327 if (pMin[d] > pMax[d]) continue; 4328 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4329 } 4330 PetscCall(PetscFree2(pMin, pMax)); 4331 PetscFunctionReturn(PETSC_SUCCESS); 4332 } 4333 4334 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4335 { 4336 PetscInt pStart, pEnd; 4337 PetscInt numRoots = 0, numLeaves = 0; 4338 4339 PetscFunctionBegin; 4340 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4341 { 4342 /* Initialize roots and count leaves */ 4343 PetscInt sMin = PETSC_MAX_INT; 4344 PetscInt sMax = PETSC_MIN_INT; 4345 PetscInt coneSize, supportSize; 4346 4347 for (PetscInt p = pStart; p < pEnd; ++p) { 4348 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4349 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4350 if (!coneSize && supportSize) { 4351 sMin = PetscMin(p, sMin); 4352 sMax = PetscMax(p, sMax); 4353 ++numRoots; 4354 } else if (!supportSize && coneSize) { 4355 ++numLeaves; 4356 } else if (!supportSize && !coneSize) { 4357 /* Isolated points */ 4358 sMin = PetscMin(p, sMin); 4359 sMax = PetscMax(p, sMax); 4360 } 4361 } 4362 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4363 } 4364 4365 if (numRoots + numLeaves == (pEnd - pStart)) { 4366 PetscInt sMin = PETSC_MAX_INT; 4367 PetscInt sMax = PETSC_MIN_INT; 4368 PetscInt coneSize, supportSize; 4369 4370 for (PetscInt p = pStart; p < pEnd; ++p) { 4371 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4372 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4373 if (!supportSize && coneSize) { 4374 sMin = PetscMin(p, sMin); 4375 sMax = PetscMax(p, sMax); 4376 } 4377 } 4378 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4379 } else { 4380 PetscInt level = 0; 4381 PetscInt qStart, qEnd; 4382 4383 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4384 while (qEnd > qStart) { 4385 PetscInt sMin = PETSC_MAX_INT; 4386 PetscInt sMax = PETSC_MIN_INT; 4387 4388 for (PetscInt q = qStart; q < qEnd; ++q) { 4389 const PetscInt *support; 4390 PetscInt supportSize; 4391 4392 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4393 PetscCall(DMPlexGetSupport(dm, q, &support)); 4394 for (PetscInt s = 0; s < supportSize; ++s) { 4395 sMin = PetscMin(support[s], sMin); 4396 sMax = PetscMax(support[s], sMax); 4397 } 4398 } 4399 PetscCall(DMLabelGetNumValues(label, &level)); 4400 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4401 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4402 } 4403 } 4404 PetscFunctionReturn(PETSC_SUCCESS); 4405 } 4406 4407 /*@ 4408 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4409 4410 Collective 4411 4412 Input Parameter: 4413 . dm - The `DMPLEX` 4414 4415 Level: beginner 4416 4417 Notes: 4418 The strata group all points of the same grade, and this function calculates the strata. This 4419 grade can be seen as the height (or depth) of the point in the DAG. 4420 4421 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4422 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4423 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4424 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4425 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4426 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4427 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4428 4429 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4430 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4431 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 4432 to interpolate only that one (e0), so that 4433 .vb 4434 cone(c0) = {e0, v2} 4435 cone(e0) = {v0, v1} 4436 .ve 4437 If `DMPlexStratify()` is run on this mesh, it will give depths 4438 .vb 4439 depth 0 = {v0, v1, v2} 4440 depth 1 = {e0, c0} 4441 .ve 4442 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4443 4444 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4445 4446 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4447 @*/ 4448 PetscErrorCode DMPlexStratify(DM dm) 4449 { 4450 DM_Plex *mesh = (DM_Plex *)dm->data; 4451 DMLabel label; 4452 PetscBool flg = PETSC_FALSE; 4453 4454 PetscFunctionBegin; 4455 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4456 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4457 4458 // Create depth label 4459 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4460 PetscCall(DMCreateLabel(dm, "depth")); 4461 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4462 4463 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4464 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4465 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4466 4467 { /* just in case there is an empty process */ 4468 PetscInt numValues, maxValues = 0, v; 4469 4470 PetscCall(DMLabelGetNumValues(label, &numValues)); 4471 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4472 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4473 } 4474 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4475 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4476 PetscFunctionReturn(PETSC_SUCCESS); 4477 } 4478 4479 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4480 { 4481 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4482 PetscInt dim, depth, pheight, coneSize; 4483 4484 PetscFunctionBeginHot; 4485 PetscCall(DMGetDimension(dm, &dim)); 4486 PetscCall(DMPlexGetDepth(dm, &depth)); 4487 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4488 pheight = depth - pdepth; 4489 if (depth <= 1) { 4490 switch (pdepth) { 4491 case 0: 4492 ct = DM_POLYTOPE_POINT; 4493 break; 4494 case 1: 4495 switch (coneSize) { 4496 case 2: 4497 ct = DM_POLYTOPE_SEGMENT; 4498 break; 4499 case 3: 4500 ct = DM_POLYTOPE_TRIANGLE; 4501 break; 4502 case 4: 4503 switch (dim) { 4504 case 2: 4505 ct = DM_POLYTOPE_QUADRILATERAL; 4506 break; 4507 case 3: 4508 ct = DM_POLYTOPE_TETRAHEDRON; 4509 break; 4510 default: 4511 break; 4512 } 4513 break; 4514 case 5: 4515 ct = DM_POLYTOPE_PYRAMID; 4516 break; 4517 case 6: 4518 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4519 break; 4520 case 8: 4521 ct = DM_POLYTOPE_HEXAHEDRON; 4522 break; 4523 default: 4524 break; 4525 } 4526 } 4527 } else { 4528 if (pdepth == 0) { 4529 ct = DM_POLYTOPE_POINT; 4530 } else if (pheight == 0) { 4531 switch (dim) { 4532 case 1: 4533 switch (coneSize) { 4534 case 2: 4535 ct = DM_POLYTOPE_SEGMENT; 4536 break; 4537 default: 4538 break; 4539 } 4540 break; 4541 case 2: 4542 switch (coneSize) { 4543 case 3: 4544 ct = DM_POLYTOPE_TRIANGLE; 4545 break; 4546 case 4: 4547 ct = DM_POLYTOPE_QUADRILATERAL; 4548 break; 4549 default: 4550 break; 4551 } 4552 break; 4553 case 3: 4554 switch (coneSize) { 4555 case 4: 4556 ct = DM_POLYTOPE_TETRAHEDRON; 4557 break; 4558 case 5: { 4559 const PetscInt *cone; 4560 PetscInt faceConeSize; 4561 4562 PetscCall(DMPlexGetCone(dm, p, &cone)); 4563 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4564 switch (faceConeSize) { 4565 case 3: 4566 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4567 break; 4568 case 4: 4569 ct = DM_POLYTOPE_PYRAMID; 4570 break; 4571 } 4572 } break; 4573 case 6: 4574 ct = DM_POLYTOPE_HEXAHEDRON; 4575 break; 4576 default: 4577 break; 4578 } 4579 break; 4580 default: 4581 break; 4582 } 4583 } else if (pheight > 0) { 4584 switch (coneSize) { 4585 case 2: 4586 ct = DM_POLYTOPE_SEGMENT; 4587 break; 4588 case 3: 4589 ct = DM_POLYTOPE_TRIANGLE; 4590 break; 4591 case 4: 4592 ct = DM_POLYTOPE_QUADRILATERAL; 4593 break; 4594 default: 4595 break; 4596 } 4597 } 4598 } 4599 *pt = ct; 4600 PetscFunctionReturn(PETSC_SUCCESS); 4601 } 4602 4603 /*@ 4604 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4605 4606 Collective 4607 4608 Input Parameter: 4609 . dm - The `DMPLEX` 4610 4611 Level: developer 4612 4613 Note: 4614 This function is normally called automatically when a cell type is requested. It creates an 4615 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4616 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4617 4618 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4619 4620 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4621 @*/ 4622 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4623 { 4624 DM_Plex *mesh; 4625 DMLabel ctLabel; 4626 PetscInt pStart, pEnd, p; 4627 4628 PetscFunctionBegin; 4629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4630 mesh = (DM_Plex *)dm->data; 4631 PetscCall(DMCreateLabel(dm, "celltype")); 4632 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4633 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4634 PetscCall(PetscFree(mesh->cellTypes)); 4635 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4636 for (p = pStart; p < pEnd; ++p) { 4637 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4638 PetscInt pdepth; 4639 4640 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4641 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4642 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " has invalid celltype (%s)", p, DMPolytopeTypes[ct]); 4643 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4644 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4645 } 4646 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4647 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4648 PetscFunctionReturn(PETSC_SUCCESS); 4649 } 4650 4651 /*@C 4652 DMPlexGetJoin - Get an array for the join of the set of points 4653 4654 Not Collective 4655 4656 Input Parameters: 4657 + dm - The `DMPLEX` object 4658 . numPoints - The number of input points for the join 4659 - points - The input points 4660 4661 Output Parameters: 4662 + numCoveredPoints - The number of points in the join 4663 - coveredPoints - The points in the join 4664 4665 Level: intermediate 4666 4667 Note: 4668 Currently, this is restricted to a single level join 4669 4670 Fortran Notes: 4671 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4672 4673 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4674 @*/ 4675 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4676 { 4677 DM_Plex *mesh = (DM_Plex *)dm->data; 4678 PetscInt *join[2]; 4679 PetscInt joinSize, i = 0; 4680 PetscInt dof, off, p, c, m; 4681 PetscInt maxSupportSize; 4682 4683 PetscFunctionBegin; 4684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4685 PetscAssertPointer(points, 3); 4686 PetscAssertPointer(numCoveredPoints, 4); 4687 PetscAssertPointer(coveredPoints, 5); 4688 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4689 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4690 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4691 /* Copy in support of first point */ 4692 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4693 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4694 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4695 /* Check each successive support */ 4696 for (p = 1; p < numPoints; ++p) { 4697 PetscInt newJoinSize = 0; 4698 4699 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4700 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4701 for (c = 0; c < dof; ++c) { 4702 const PetscInt point = mesh->supports[off + c]; 4703 4704 for (m = 0; m < joinSize; ++m) { 4705 if (point == join[i][m]) { 4706 join[1 - i][newJoinSize++] = point; 4707 break; 4708 } 4709 } 4710 } 4711 joinSize = newJoinSize; 4712 i = 1 - i; 4713 } 4714 *numCoveredPoints = joinSize; 4715 *coveredPoints = join[i]; 4716 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4717 PetscFunctionReturn(PETSC_SUCCESS); 4718 } 4719 4720 /*@C 4721 DMPlexRestoreJoin - Restore an array for the join of the set of points 4722 4723 Not Collective 4724 4725 Input Parameters: 4726 + dm - The `DMPLEX` object 4727 . numPoints - The number of input points for the join 4728 - points - The input points 4729 4730 Output Parameters: 4731 + numCoveredPoints - The number of points in the join 4732 - coveredPoints - The points in the join 4733 4734 Level: intermediate 4735 4736 Fortran Notes: 4737 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4738 4739 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4740 @*/ 4741 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4742 { 4743 PetscFunctionBegin; 4744 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4745 if (points) PetscAssertPointer(points, 3); 4746 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4747 PetscAssertPointer(coveredPoints, 5); 4748 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4749 if (numCoveredPoints) *numCoveredPoints = 0; 4750 PetscFunctionReturn(PETSC_SUCCESS); 4751 } 4752 4753 /*@C 4754 DMPlexGetFullJoin - Get an array for the join of the set of points 4755 4756 Not Collective 4757 4758 Input Parameters: 4759 + dm - The `DMPLEX` object 4760 . numPoints - The number of input points for the join 4761 - points - The input points 4762 4763 Output Parameters: 4764 + numCoveredPoints - The number of points in the join 4765 - coveredPoints - The points in the join 4766 4767 Level: intermediate 4768 4769 Fortran Notes: 4770 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4771 4772 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4773 @*/ 4774 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4775 { 4776 PetscInt *offsets, **closures; 4777 PetscInt *join[2]; 4778 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4779 PetscInt p, d, c, m, ms; 4780 4781 PetscFunctionBegin; 4782 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4783 PetscAssertPointer(points, 3); 4784 PetscAssertPointer(numCoveredPoints, 4); 4785 PetscAssertPointer(coveredPoints, 5); 4786 4787 PetscCall(DMPlexGetDepth(dm, &depth)); 4788 PetscCall(PetscCalloc1(numPoints, &closures)); 4789 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4790 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4791 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4792 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4793 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4794 4795 for (p = 0; p < numPoints; ++p) { 4796 PetscInt closureSize; 4797 4798 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4799 4800 offsets[p * (depth + 2) + 0] = 0; 4801 for (d = 0; d < depth + 1; ++d) { 4802 PetscInt pStart, pEnd, i; 4803 4804 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4805 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4806 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4807 offsets[p * (depth + 2) + d + 1] = i; 4808 break; 4809 } 4810 } 4811 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4812 } 4813 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); 4814 } 4815 for (d = 0; d < depth + 1; ++d) { 4816 PetscInt dof; 4817 4818 /* Copy in support of first point */ 4819 dof = offsets[d + 1] - offsets[d]; 4820 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4821 /* Check each successive cone */ 4822 for (p = 1; p < numPoints && joinSize; ++p) { 4823 PetscInt newJoinSize = 0; 4824 4825 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4826 for (c = 0; c < dof; ++c) { 4827 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4828 4829 for (m = 0; m < joinSize; ++m) { 4830 if (point == join[i][m]) { 4831 join[1 - i][newJoinSize++] = point; 4832 break; 4833 } 4834 } 4835 } 4836 joinSize = newJoinSize; 4837 i = 1 - i; 4838 } 4839 if (joinSize) break; 4840 } 4841 *numCoveredPoints = joinSize; 4842 *coveredPoints = join[i]; 4843 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4844 PetscCall(PetscFree(closures)); 4845 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4846 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4847 PetscFunctionReturn(PETSC_SUCCESS); 4848 } 4849 4850 /*@C 4851 DMPlexGetMeet - Get an array for the meet of the set of points 4852 4853 Not Collective 4854 4855 Input Parameters: 4856 + dm - The `DMPLEX` object 4857 . numPoints - The number of input points for the meet 4858 - points - The input points 4859 4860 Output Parameters: 4861 + numCoveringPoints - The number of points in the meet 4862 - coveringPoints - The points in the meet 4863 4864 Level: intermediate 4865 4866 Note: 4867 Currently, this is restricted to a single level meet 4868 4869 Fortran Notes: 4870 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4871 4872 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4873 @*/ 4874 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4875 { 4876 DM_Plex *mesh = (DM_Plex *)dm->data; 4877 PetscInt *meet[2]; 4878 PetscInt meetSize, i = 0; 4879 PetscInt dof, off, p, c, m; 4880 PetscInt maxConeSize; 4881 4882 PetscFunctionBegin; 4883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4884 PetscAssertPointer(points, 3); 4885 PetscAssertPointer(numCoveringPoints, 4); 4886 PetscAssertPointer(coveringPoints, 5); 4887 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4888 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4889 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4890 /* Copy in cone of first point */ 4891 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4892 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4893 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4894 /* Check each successive cone */ 4895 for (p = 1; p < numPoints; ++p) { 4896 PetscInt newMeetSize = 0; 4897 4898 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4899 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4900 for (c = 0; c < dof; ++c) { 4901 const PetscInt point = mesh->cones[off + c]; 4902 4903 for (m = 0; m < meetSize; ++m) { 4904 if (point == meet[i][m]) { 4905 meet[1 - i][newMeetSize++] = point; 4906 break; 4907 } 4908 } 4909 } 4910 meetSize = newMeetSize; 4911 i = 1 - i; 4912 } 4913 *numCoveringPoints = meetSize; 4914 *coveringPoints = meet[i]; 4915 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4916 PetscFunctionReturn(PETSC_SUCCESS); 4917 } 4918 4919 /*@C 4920 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4921 4922 Not Collective 4923 4924 Input Parameters: 4925 + dm - The `DMPLEX` object 4926 . numPoints - The number of input points for the meet 4927 - points - The input points 4928 4929 Output Parameters: 4930 + numCoveredPoints - The number of points in the meet 4931 - coveredPoints - The points in the meet 4932 4933 Level: intermediate 4934 4935 Fortran Notes: 4936 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4937 4938 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4939 @*/ 4940 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4941 { 4942 PetscFunctionBegin; 4943 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4944 if (points) PetscAssertPointer(points, 3); 4945 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4946 PetscAssertPointer(coveredPoints, 5); 4947 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4948 if (numCoveredPoints) *numCoveredPoints = 0; 4949 PetscFunctionReturn(PETSC_SUCCESS); 4950 } 4951 4952 /*@C 4953 DMPlexGetFullMeet - Get an array for the meet of the set of points 4954 4955 Not Collective 4956 4957 Input Parameters: 4958 + dm - The `DMPLEX` object 4959 . numPoints - The number of input points for the meet 4960 - points - The input points 4961 4962 Output Parameters: 4963 + numCoveredPoints - The number of points in the meet 4964 - coveredPoints - The points in the meet 4965 4966 Level: intermediate 4967 4968 Fortran Notes: 4969 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4970 4971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4972 @*/ 4973 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4974 { 4975 PetscInt *offsets, **closures; 4976 PetscInt *meet[2]; 4977 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4978 PetscInt p, h, c, m, mc; 4979 4980 PetscFunctionBegin; 4981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4982 PetscAssertPointer(points, 3); 4983 PetscAssertPointer(numCoveredPoints, 4); 4984 PetscAssertPointer(coveredPoints, 5); 4985 4986 PetscCall(DMPlexGetDepth(dm, &height)); 4987 PetscCall(PetscMalloc1(numPoints, &closures)); 4988 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4989 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4990 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4991 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4992 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4993 4994 for (p = 0; p < numPoints; ++p) { 4995 PetscInt closureSize; 4996 4997 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4998 4999 offsets[p * (height + 2) + 0] = 0; 5000 for (h = 0; h < height + 1; ++h) { 5001 PetscInt pStart, pEnd, i; 5002 5003 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5004 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5005 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5006 offsets[p * (height + 2) + h + 1] = i; 5007 break; 5008 } 5009 } 5010 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5011 } 5012 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); 5013 } 5014 for (h = 0; h < height + 1; ++h) { 5015 PetscInt dof; 5016 5017 /* Copy in cone of first point */ 5018 dof = offsets[h + 1] - offsets[h]; 5019 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5020 /* Check each successive cone */ 5021 for (p = 1; p < numPoints && meetSize; ++p) { 5022 PetscInt newMeetSize = 0; 5023 5024 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5025 for (c = 0; c < dof; ++c) { 5026 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5027 5028 for (m = 0; m < meetSize; ++m) { 5029 if (point == meet[i][m]) { 5030 meet[1 - i][newMeetSize++] = point; 5031 break; 5032 } 5033 } 5034 } 5035 meetSize = newMeetSize; 5036 i = 1 - i; 5037 } 5038 if (meetSize) break; 5039 } 5040 *numCoveredPoints = meetSize; 5041 *coveredPoints = meet[i]; 5042 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5043 PetscCall(PetscFree(closures)); 5044 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5045 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5046 PetscFunctionReturn(PETSC_SUCCESS); 5047 } 5048 5049 /*@ 5050 DMPlexEqual - Determine if two `DM` have the same topology 5051 5052 Not Collective 5053 5054 Input Parameters: 5055 + dmA - A `DMPLEX` object 5056 - dmB - A `DMPLEX` object 5057 5058 Output Parameter: 5059 . equal - `PETSC_TRUE` if the topologies are identical 5060 5061 Level: intermediate 5062 5063 Note: 5064 We are not solving graph isomorphism, so we do not permute. 5065 5066 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5067 @*/ 5068 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5069 { 5070 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5071 5072 PetscFunctionBegin; 5073 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5074 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5075 PetscAssertPointer(equal, 3); 5076 5077 *equal = PETSC_FALSE; 5078 PetscCall(DMPlexGetDepth(dmA, &depth)); 5079 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5080 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5081 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5082 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5083 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5084 for (p = pStart; p < pEnd; ++p) { 5085 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5086 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5087 5088 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5089 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5090 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5091 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5092 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5093 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5094 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5095 for (c = 0; c < coneSize; ++c) { 5096 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5097 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5098 } 5099 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5100 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5101 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5102 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5103 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5104 for (s = 0; s < supportSize; ++s) { 5105 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5106 } 5107 } 5108 *equal = PETSC_TRUE; 5109 PetscFunctionReturn(PETSC_SUCCESS); 5110 } 5111 5112 /*@ 5113 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5114 5115 Not Collective 5116 5117 Input Parameters: 5118 + dm - The `DMPLEX` 5119 . cellDim - The cell dimension 5120 - numCorners - The number of vertices on a cell 5121 5122 Output Parameter: 5123 . numFaceVertices - The number of vertices on a face 5124 5125 Level: developer 5126 5127 Note: 5128 Of course this can only work for a restricted set of symmetric shapes 5129 5130 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5131 @*/ 5132 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5133 { 5134 MPI_Comm comm; 5135 5136 PetscFunctionBegin; 5137 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5138 PetscAssertPointer(numFaceVertices, 4); 5139 switch (cellDim) { 5140 case 0: 5141 *numFaceVertices = 0; 5142 break; 5143 case 1: 5144 *numFaceVertices = 1; 5145 break; 5146 case 2: 5147 switch (numCorners) { 5148 case 3: /* triangle */ 5149 *numFaceVertices = 2; /* Edge has 2 vertices */ 5150 break; 5151 case 4: /* quadrilateral */ 5152 *numFaceVertices = 2; /* Edge has 2 vertices */ 5153 break; 5154 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5155 *numFaceVertices = 3; /* Edge has 3 vertices */ 5156 break; 5157 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5158 *numFaceVertices = 3; /* Edge has 3 vertices */ 5159 break; 5160 default: 5161 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5162 } 5163 break; 5164 case 3: 5165 switch (numCorners) { 5166 case 4: /* tetradehdron */ 5167 *numFaceVertices = 3; /* Face has 3 vertices */ 5168 break; 5169 case 6: /* tet cohesive cells */ 5170 *numFaceVertices = 4; /* Face has 4 vertices */ 5171 break; 5172 case 8: /* hexahedron */ 5173 *numFaceVertices = 4; /* Face has 4 vertices */ 5174 break; 5175 case 9: /* tet cohesive Lagrange cells */ 5176 *numFaceVertices = 6; /* Face has 6 vertices */ 5177 break; 5178 case 10: /* quadratic tetrahedron */ 5179 *numFaceVertices = 6; /* Face has 6 vertices */ 5180 break; 5181 case 12: /* hex cohesive Lagrange cells */ 5182 *numFaceVertices = 6; /* Face has 6 vertices */ 5183 break; 5184 case 18: /* quadratic tet cohesive Lagrange cells */ 5185 *numFaceVertices = 6; /* Face has 6 vertices */ 5186 break; 5187 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5188 *numFaceVertices = 9; /* Face has 9 vertices */ 5189 break; 5190 default: 5191 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5192 } 5193 break; 5194 default: 5195 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5196 } 5197 PetscFunctionReturn(PETSC_SUCCESS); 5198 } 5199 5200 /*@ 5201 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5202 5203 Not Collective 5204 5205 Input Parameter: 5206 . dm - The `DMPLEX` object 5207 5208 Output Parameter: 5209 . depthLabel - The `DMLabel` recording point depth 5210 5211 Level: developer 5212 5213 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5214 @*/ 5215 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5216 { 5217 PetscFunctionBegin; 5218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5219 PetscAssertPointer(depthLabel, 2); 5220 *depthLabel = dm->depthLabel; 5221 PetscFunctionReturn(PETSC_SUCCESS); 5222 } 5223 5224 /*@ 5225 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5226 5227 Not Collective 5228 5229 Input Parameter: 5230 . dm - The `DMPLEX` object 5231 5232 Output Parameter: 5233 . depth - The number of strata (breadth first levels) in the DAG 5234 5235 Level: developer 5236 5237 Notes: 5238 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5239 5240 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5241 5242 An empty mesh gives -1. 5243 5244 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5245 @*/ 5246 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5247 { 5248 DM_Plex *mesh = (DM_Plex *)dm->data; 5249 DMLabel label; 5250 PetscInt d = -1; 5251 5252 PetscFunctionBegin; 5253 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5254 PetscAssertPointer(depth, 2); 5255 if (mesh->tr) { 5256 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5257 } else { 5258 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5259 // Allow missing depths 5260 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5261 *depth = d; 5262 } 5263 PetscFunctionReturn(PETSC_SUCCESS); 5264 } 5265 5266 /*@ 5267 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5268 5269 Not Collective 5270 5271 Input Parameters: 5272 + dm - The `DMPLEX` object 5273 - depth - The requested depth 5274 5275 Output Parameters: 5276 + start - The first point at this `depth` 5277 - end - One beyond the last point at this `depth` 5278 5279 Level: developer 5280 5281 Notes: 5282 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5283 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5284 higher dimension, e.g., "edges". 5285 5286 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5287 @*/ 5288 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5289 { 5290 DM_Plex *mesh = (DM_Plex *)dm->data; 5291 DMLabel label; 5292 PetscInt pStart, pEnd; 5293 5294 PetscFunctionBegin; 5295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5296 if (start) { 5297 PetscAssertPointer(start, 3); 5298 *start = 0; 5299 } 5300 if (end) { 5301 PetscAssertPointer(end, 4); 5302 *end = 0; 5303 } 5304 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5305 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5306 if (depth < 0) { 5307 if (start) *start = pStart; 5308 if (end) *end = pEnd; 5309 PetscFunctionReturn(PETSC_SUCCESS); 5310 } 5311 if (mesh->tr) { 5312 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5313 } else { 5314 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5315 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5316 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5317 } 5318 PetscFunctionReturn(PETSC_SUCCESS); 5319 } 5320 5321 /*@ 5322 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5323 5324 Not Collective 5325 5326 Input Parameters: 5327 + dm - The `DMPLEX` object 5328 - height - The requested height 5329 5330 Output Parameters: 5331 + start - The first point at this `height` 5332 - end - One beyond the last point at this `height` 5333 5334 Level: developer 5335 5336 Notes: 5337 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5338 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5339 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5340 5341 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5342 @*/ 5343 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5344 { 5345 DMLabel label; 5346 PetscInt depth, pStart, pEnd; 5347 5348 PetscFunctionBegin; 5349 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5350 if (start) { 5351 PetscAssertPointer(start, 3); 5352 *start = 0; 5353 } 5354 if (end) { 5355 PetscAssertPointer(end, 4); 5356 *end = 0; 5357 } 5358 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5359 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5360 if (height < 0) { 5361 if (start) *start = pStart; 5362 if (end) *end = pEnd; 5363 PetscFunctionReturn(PETSC_SUCCESS); 5364 } 5365 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5366 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5367 else PetscCall(DMGetDimension(dm, &depth)); 5368 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5369 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5370 PetscFunctionReturn(PETSC_SUCCESS); 5371 } 5372 5373 /*@ 5374 DMPlexGetPointDepth - Get the `depth` of a given point 5375 5376 Not Collective 5377 5378 Input Parameters: 5379 + dm - The `DMPLEX` object 5380 - point - The point 5381 5382 Output Parameter: 5383 . depth - The depth of the `point` 5384 5385 Level: intermediate 5386 5387 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5388 @*/ 5389 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5390 { 5391 PetscFunctionBegin; 5392 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5393 PetscAssertPointer(depth, 3); 5394 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5395 PetscFunctionReturn(PETSC_SUCCESS); 5396 } 5397 5398 /*@ 5399 DMPlexGetPointHeight - Get the `height` of a given point 5400 5401 Not Collective 5402 5403 Input Parameters: 5404 + dm - The `DMPLEX` object 5405 - point - The point 5406 5407 Output Parameter: 5408 . height - The height of the `point` 5409 5410 Level: intermediate 5411 5412 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5413 @*/ 5414 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5415 { 5416 PetscInt n, pDepth; 5417 5418 PetscFunctionBegin; 5419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5420 PetscAssertPointer(height, 3); 5421 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5422 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5423 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5424 PetscFunctionReturn(PETSC_SUCCESS); 5425 } 5426 5427 /*@ 5428 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5429 5430 Not Collective 5431 5432 Input Parameter: 5433 . dm - The `DMPLEX` object 5434 5435 Output Parameter: 5436 . celltypeLabel - The `DMLabel` recording cell polytope type 5437 5438 Level: developer 5439 5440 Note: 5441 This function will trigger automatica computation of cell types. This can be disabled by calling 5442 `DMCreateLabel`(dm, "celltype") beforehand. 5443 5444 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5445 @*/ 5446 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5447 { 5448 PetscFunctionBegin; 5449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5450 PetscAssertPointer(celltypeLabel, 2); 5451 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5452 *celltypeLabel = dm->celltypeLabel; 5453 PetscFunctionReturn(PETSC_SUCCESS); 5454 } 5455 5456 /*@ 5457 DMPlexGetCellType - Get the polytope type of a given cell 5458 5459 Not Collective 5460 5461 Input Parameters: 5462 + dm - The `DMPLEX` object 5463 - cell - The cell 5464 5465 Output Parameter: 5466 . celltype - The polytope type of the cell 5467 5468 Level: intermediate 5469 5470 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5471 @*/ 5472 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5473 { 5474 DM_Plex *mesh = (DM_Plex *)dm->data; 5475 DMLabel label; 5476 PetscInt ct; 5477 5478 PetscFunctionBegin; 5479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5480 PetscAssertPointer(celltype, 3); 5481 if (mesh->tr) { 5482 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5483 } else { 5484 PetscInt pStart, pEnd; 5485 5486 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5487 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5488 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5489 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5490 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5491 for (PetscInt p = pStart; p < pEnd; p++) { 5492 PetscCall(DMLabelGetValue(label, p, &ct)); 5493 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5494 } 5495 } 5496 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5497 if (PetscDefined(USE_DEBUG)) { 5498 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5499 PetscCall(DMLabelGetValue(label, cell, &ct)); 5500 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5501 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5502 } 5503 } 5504 PetscFunctionReturn(PETSC_SUCCESS); 5505 } 5506 5507 /*@ 5508 DMPlexSetCellType - Set the polytope type of a given cell 5509 5510 Not Collective 5511 5512 Input Parameters: 5513 + dm - The `DMPLEX` object 5514 . cell - The cell 5515 - celltype - The polytope type of the cell 5516 5517 Level: advanced 5518 5519 Note: 5520 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5521 is executed. This function will override the computed type. However, if automatic classification will not succeed 5522 and a user wants to manually specify all types, the classification must be disabled by calling 5523 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5524 5525 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5526 @*/ 5527 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5528 { 5529 DM_Plex *mesh = (DM_Plex *)dm->data; 5530 DMLabel label; 5531 PetscInt pStart, pEnd; 5532 5533 PetscFunctionBegin; 5534 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5535 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5536 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5537 PetscCall(DMLabelSetValue(label, cell, celltype)); 5538 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5539 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5540 PetscFunctionReturn(PETSC_SUCCESS); 5541 } 5542 5543 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5544 { 5545 PetscSection section; 5546 PetscInt maxHeight; 5547 const char *prefix; 5548 5549 PetscFunctionBegin; 5550 PetscCall(DMClone(dm, cdm)); 5551 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5552 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5553 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5554 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5555 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5556 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5557 PetscCall(DMSetLocalSection(*cdm, section)); 5558 PetscCall(PetscSectionDestroy(§ion)); 5559 5560 PetscCall(DMSetNumFields(*cdm, 1)); 5561 PetscCall(DMCreateDS(*cdm)); 5562 (*cdm)->cloneOpts = PETSC_TRUE; 5563 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5564 PetscFunctionReturn(PETSC_SUCCESS); 5565 } 5566 5567 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5568 { 5569 Vec coordsLocal, cellCoordsLocal; 5570 DM coordsDM, cellCoordsDM; 5571 5572 PetscFunctionBegin; 5573 *field = NULL; 5574 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5575 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5576 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5577 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5578 if (coordsLocal && coordsDM) { 5579 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5580 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5581 } 5582 PetscFunctionReturn(PETSC_SUCCESS); 5583 } 5584 5585 /*@ 5586 DMPlexGetConeSection - Return a section which describes the layout of cone data 5587 5588 Not Collective 5589 5590 Input Parameter: 5591 . dm - The `DMPLEX` object 5592 5593 Output Parameter: 5594 . section - The `PetscSection` object 5595 5596 Level: developer 5597 5598 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5599 @*/ 5600 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5601 { 5602 DM_Plex *mesh = (DM_Plex *)dm->data; 5603 5604 PetscFunctionBegin; 5605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5606 if (section) *section = mesh->coneSection; 5607 PetscFunctionReturn(PETSC_SUCCESS); 5608 } 5609 5610 /*@ 5611 DMPlexGetSupportSection - Return a section which describes the layout of support data 5612 5613 Not Collective 5614 5615 Input Parameter: 5616 . dm - The `DMPLEX` object 5617 5618 Output Parameter: 5619 . section - The `PetscSection` object 5620 5621 Level: developer 5622 5623 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5624 @*/ 5625 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5626 { 5627 DM_Plex *mesh = (DM_Plex *)dm->data; 5628 5629 PetscFunctionBegin; 5630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5631 if (section) *section = mesh->supportSection; 5632 PetscFunctionReturn(PETSC_SUCCESS); 5633 } 5634 5635 /*@C 5636 DMPlexGetCones - Return cone data 5637 5638 Not Collective 5639 5640 Input Parameter: 5641 . dm - The `DMPLEX` object 5642 5643 Output Parameter: 5644 . cones - The cone for each point 5645 5646 Level: developer 5647 5648 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5649 @*/ 5650 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5651 { 5652 DM_Plex *mesh = (DM_Plex *)dm->data; 5653 5654 PetscFunctionBegin; 5655 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5656 if (cones) *cones = mesh->cones; 5657 PetscFunctionReturn(PETSC_SUCCESS); 5658 } 5659 5660 /*@C 5661 DMPlexGetConeOrientations - Return cone orientation data 5662 5663 Not Collective 5664 5665 Input Parameter: 5666 . dm - The `DMPLEX` object 5667 5668 Output Parameter: 5669 . coneOrientations - The array of cone orientations for all points 5670 5671 Level: developer 5672 5673 Notes: 5674 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5675 5676 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5677 5678 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5679 @*/ 5680 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5681 { 5682 DM_Plex *mesh = (DM_Plex *)dm->data; 5683 5684 PetscFunctionBegin; 5685 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5686 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5687 PetscFunctionReturn(PETSC_SUCCESS); 5688 } 5689 5690 /******************************** FEM Support **********************************/ 5691 5692 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5693 { 5694 PetscInt depth; 5695 5696 PetscFunctionBegin; 5697 PetscCall(DMPlexGetDepth(plex, &depth)); 5698 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5699 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5700 PetscFunctionReturn(PETSC_SUCCESS); 5701 } 5702 5703 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5704 { 5705 PetscInt depth; 5706 5707 PetscFunctionBegin; 5708 PetscCall(DMPlexGetDepth(plex, &depth)); 5709 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5710 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5711 PetscFunctionReturn(PETSC_SUCCESS); 5712 } 5713 5714 /* 5715 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5716 representing a line in the section. 5717 */ 5718 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5719 { 5720 PetscObject obj; 5721 PetscClassId id; 5722 PetscFE fe = NULL; 5723 5724 PetscFunctionBeginHot; 5725 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5726 PetscCall(DMGetField(dm, field, NULL, &obj)); 5727 PetscCall(PetscObjectGetClassId(obj, &id)); 5728 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5729 5730 if (!fe) { 5731 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5732 /* An order k SEM disc has k-1 dofs on an edge */ 5733 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5734 *k = *k / *Nc + 1; 5735 } else { 5736 PetscInt dual_space_size, dim; 5737 PetscDualSpace dsp; 5738 5739 PetscCall(DMGetDimension(dm, &dim)); 5740 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5741 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5742 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5743 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5744 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5745 } 5746 PetscFunctionReturn(PETSC_SUCCESS); 5747 } 5748 5749 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5750 { 5751 PetscFunctionBeginHot; 5752 if (tensor) { 5753 *dof = PetscPowInt(k + 1, dim); 5754 } else { 5755 switch (dim) { 5756 case 1: 5757 *dof = k + 1; 5758 break; 5759 case 2: 5760 *dof = ((k + 1) * (k + 2)) / 2; 5761 break; 5762 case 3: 5763 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5764 break; 5765 default: 5766 *dof = 0; 5767 } 5768 } 5769 PetscFunctionReturn(PETSC_SUCCESS); 5770 } 5771 5772 /*@ 5773 5774 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5775 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5776 section provided (or the section of the `DM`). 5777 5778 Input Parameters: 5779 + dm - The `DM` 5780 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5781 - section - The `PetscSection` to reorder, or `NULL` for the default section 5782 5783 Example: 5784 A typical interpolated single-quad mesh might order points as 5785 .vb 5786 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5787 5788 v4 -- e6 -- v3 5789 | | 5790 e7 c0 e8 5791 | | 5792 v1 -- e5 -- v2 5793 .ve 5794 5795 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5796 dofs in the order of points, e.g., 5797 .vb 5798 c0 -> [0,1,2,3] 5799 v1 -> [4] 5800 ... 5801 e5 -> [8, 9] 5802 .ve 5803 5804 which corresponds to the dofs 5805 .vb 5806 6 10 11 7 5807 13 2 3 15 5808 12 0 1 14 5809 4 8 9 5 5810 .ve 5811 5812 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5813 .vb 5814 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5815 .ve 5816 5817 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5818 .vb 5819 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5820 .ve 5821 5822 Level: developer 5823 5824 Notes: 5825 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5826 degree of the basis. 5827 5828 This is required to run with libCEED. 5829 5830 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5831 @*/ 5832 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5833 { 5834 DMLabel label; 5835 PetscInt dim, depth = -1, eStart = -1, Nf; 5836 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5837 5838 PetscFunctionBegin; 5839 PetscCall(DMGetDimension(dm, &dim)); 5840 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5841 if (point < 0) { 5842 PetscInt sStart, sEnd; 5843 5844 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5845 point = sEnd - sStart ? sStart : point; 5846 } 5847 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5848 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5849 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5850 if (depth == 1) { 5851 eStart = point; 5852 } else if (depth == dim) { 5853 const PetscInt *cone; 5854 5855 PetscCall(DMPlexGetCone(dm, point, &cone)); 5856 if (dim == 2) eStart = cone[0]; 5857 else if (dim == 3) { 5858 const PetscInt *cone2; 5859 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5860 eStart = cone2[0]; 5861 } 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); 5862 } 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); 5863 5864 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5865 for (PetscInt d = 1; d <= dim; d++) { 5866 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5867 PetscInt *perm; 5868 5869 for (f = 0; f < Nf; ++f) { 5870 PetscInt dof; 5871 5872 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5873 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5874 if (!continuous && d < dim) continue; 5875 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5876 size += dof * Nc; 5877 } 5878 PetscCall(PetscMalloc1(size, &perm)); 5879 for (f = 0; f < Nf; ++f) { 5880 switch (d) { 5881 case 1: 5882 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5883 if (!continuous && d < dim) continue; 5884 /* 5885 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5886 We want [ vtx0; edge of length k-1; vtx1 ] 5887 */ 5888 if (continuous) { 5889 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5890 for (i = 0; i < k - 1; i++) 5891 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5892 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5893 foffset = offset; 5894 } else { 5895 PetscInt dof; 5896 5897 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5898 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5899 foffset = offset; 5900 } 5901 break; 5902 case 2: 5903 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5904 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5905 if (!continuous && d < dim) continue; 5906 /* The SEM order is 5907 5908 v_lb, {e_b}, v_rb, 5909 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5910 v_lt, reverse {e_t}, v_rt 5911 */ 5912 if (continuous) { 5913 const PetscInt of = 0; 5914 const PetscInt oeb = of + PetscSqr(k - 1); 5915 const PetscInt oer = oeb + (k - 1); 5916 const PetscInt oet = oer + (k - 1); 5917 const PetscInt oel = oet + (k - 1); 5918 const PetscInt ovlb = oel + (k - 1); 5919 const PetscInt ovrb = ovlb + 1; 5920 const PetscInt ovrt = ovrb + 1; 5921 const PetscInt ovlt = ovrt + 1; 5922 PetscInt o; 5923 5924 /* bottom */ 5925 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5926 for (o = oeb; o < oer; ++o) 5927 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5928 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5929 /* middle */ 5930 for (i = 0; i < k - 1; ++i) { 5931 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5932 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5933 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5934 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5935 } 5936 /* top */ 5937 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5938 for (o = oel - 1; o >= oet; --o) 5939 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5940 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5941 foffset = offset; 5942 } else { 5943 PetscInt dof; 5944 5945 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5946 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5947 foffset = offset; 5948 } 5949 break; 5950 case 3: 5951 /* The original hex closure is 5952 5953 {c, 5954 f_b, f_t, f_f, f_b, f_r, f_l, 5955 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5956 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5957 */ 5958 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5959 if (!continuous && d < dim) continue; 5960 /* The SEM order is 5961 Bottom Slice 5962 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5963 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5964 v_blb, {e_bb}, v_brb, 5965 5966 Middle Slice (j) 5967 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5968 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5969 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5970 5971 Top Slice 5972 v_tlf, {e_tf}, v_trf, 5973 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5974 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5975 */ 5976 if (continuous) { 5977 const PetscInt oc = 0; 5978 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5979 const PetscInt oft = ofb + PetscSqr(k - 1); 5980 const PetscInt off = oft + PetscSqr(k - 1); 5981 const PetscInt ofk = off + PetscSqr(k - 1); 5982 const PetscInt ofr = ofk + PetscSqr(k - 1); 5983 const PetscInt ofl = ofr + PetscSqr(k - 1); 5984 const PetscInt oebl = ofl + PetscSqr(k - 1); 5985 const PetscInt oebb = oebl + (k - 1); 5986 const PetscInt oebr = oebb + (k - 1); 5987 const PetscInt oebf = oebr + (k - 1); 5988 const PetscInt oetf = oebf + (k - 1); 5989 const PetscInt oetr = oetf + (k - 1); 5990 const PetscInt oetb = oetr + (k - 1); 5991 const PetscInt oetl = oetb + (k - 1); 5992 const PetscInt oerf = oetl + (k - 1); 5993 const PetscInt oelf = oerf + (k - 1); 5994 const PetscInt oelb = oelf + (k - 1); 5995 const PetscInt oerb = oelb + (k - 1); 5996 const PetscInt ovblf = oerb + (k - 1); 5997 const PetscInt ovblb = ovblf + 1; 5998 const PetscInt ovbrb = ovblb + 1; 5999 const PetscInt ovbrf = ovbrb + 1; 6000 const PetscInt ovtlf = ovbrf + 1; 6001 const PetscInt ovtrf = ovtlf + 1; 6002 const PetscInt ovtrb = ovtrf + 1; 6003 const PetscInt ovtlb = ovtrb + 1; 6004 PetscInt o, n; 6005 6006 /* Bottom Slice */ 6007 /* bottom */ 6008 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6009 for (o = oetf - 1; o >= oebf; --o) 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6011 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6012 /* middle */ 6013 for (i = 0; i < k - 1; ++i) { 6014 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6015 for (n = 0; n < k - 1; ++n) { 6016 o = ofb + n * (k - 1) + i; 6017 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6018 } 6019 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6020 } 6021 /* top */ 6022 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6023 for (o = oebb; o < oebr; ++o) 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6025 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6026 6027 /* Middle Slice */ 6028 for (j = 0; j < k - 1; ++j) { 6029 /* bottom */ 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6031 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6032 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6033 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6034 /* middle */ 6035 for (i = 0; i < k - 1; ++i) { 6036 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6037 for (n = 0; n < k - 1; ++n) 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6039 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6040 } 6041 /* top */ 6042 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6043 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6046 } 6047 6048 /* Top Slice */ 6049 /* bottom */ 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6051 for (o = oetf; o < oetr; ++o) 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6053 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6054 /* middle */ 6055 for (i = 0; i < k - 1; ++i) { 6056 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6057 for (n = 0; n < k - 1; ++n) 6058 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6059 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6060 } 6061 /* top */ 6062 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6063 for (o = oetl - 1; o >= oetb; --o) 6064 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6065 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6066 6067 foffset = offset; 6068 } else { 6069 PetscInt dof; 6070 6071 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6072 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6073 foffset = offset; 6074 } 6075 break; 6076 default: 6077 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6078 } 6079 } 6080 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6081 /* Check permutation */ 6082 { 6083 PetscInt *check; 6084 6085 PetscCall(PetscMalloc1(size, &check)); 6086 for (i = 0; i < size; ++i) { 6087 check[i] = -1; 6088 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6089 } 6090 for (i = 0; i < size; ++i) check[perm[i]] = i; 6091 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6092 PetscCall(PetscFree(check)); 6093 } 6094 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6095 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6096 PetscInt *loc_perm; 6097 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6098 for (PetscInt i = 0; i < size; i++) { 6099 loc_perm[i] = perm[i]; 6100 loc_perm[size + i] = size + perm[i]; 6101 } 6102 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6103 } 6104 } 6105 PetscFunctionReturn(PETSC_SUCCESS); 6106 } 6107 6108 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6109 { 6110 PetscDS prob; 6111 PetscInt depth, Nf, h; 6112 DMLabel label; 6113 6114 PetscFunctionBeginHot; 6115 PetscCall(DMGetDS(dm, &prob)); 6116 Nf = prob->Nf; 6117 label = dm->depthLabel; 6118 *dspace = NULL; 6119 if (field < Nf) { 6120 PetscObject disc = prob->disc[field]; 6121 6122 if (disc->classid == PETSCFE_CLASSID) { 6123 PetscDualSpace dsp; 6124 6125 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6126 PetscCall(DMLabelGetNumValues(label, &depth)); 6127 PetscCall(DMLabelGetValue(label, point, &h)); 6128 h = depth - 1 - h; 6129 if (h) { 6130 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6131 } else { 6132 *dspace = dsp; 6133 } 6134 } 6135 } 6136 PetscFunctionReturn(PETSC_SUCCESS); 6137 } 6138 6139 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6140 { 6141 PetscScalar *array; 6142 const PetscScalar *vArray; 6143 const PetscInt *cone, *coneO; 6144 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6145 6146 PetscFunctionBeginHot; 6147 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6148 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6149 PetscCall(DMPlexGetCone(dm, point, &cone)); 6150 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6151 if (!values || !*values) { 6152 if ((point >= pStart) && (point < pEnd)) { 6153 PetscInt dof; 6154 6155 PetscCall(PetscSectionGetDof(section, point, &dof)); 6156 size += dof; 6157 } 6158 for (p = 0; p < numPoints; ++p) { 6159 const PetscInt cp = cone[p]; 6160 PetscInt dof; 6161 6162 if ((cp < pStart) || (cp >= pEnd)) continue; 6163 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6164 size += dof; 6165 } 6166 if (!values) { 6167 if (csize) *csize = size; 6168 PetscFunctionReturn(PETSC_SUCCESS); 6169 } 6170 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6171 } else { 6172 array = *values; 6173 } 6174 size = 0; 6175 PetscCall(VecGetArrayRead(v, &vArray)); 6176 if ((point >= pStart) && (point < pEnd)) { 6177 PetscInt dof, off, d; 6178 const PetscScalar *varr; 6179 6180 PetscCall(PetscSectionGetDof(section, point, &dof)); 6181 PetscCall(PetscSectionGetOffset(section, point, &off)); 6182 varr = PetscSafePointerPlusOffset(vArray, off); 6183 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6184 size += dof; 6185 } 6186 for (p = 0; p < numPoints; ++p) { 6187 const PetscInt cp = cone[p]; 6188 PetscInt o = coneO[p]; 6189 PetscInt dof, off, d; 6190 const PetscScalar *varr; 6191 6192 if ((cp < pStart) || (cp >= pEnd)) continue; 6193 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6194 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6195 varr = PetscSafePointerPlusOffset(vArray, off); 6196 if (o >= 0) { 6197 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6198 } else { 6199 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6200 } 6201 size += dof; 6202 } 6203 PetscCall(VecRestoreArrayRead(v, &vArray)); 6204 if (!*values) { 6205 if (csize) *csize = size; 6206 *values = array; 6207 } else { 6208 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6209 *csize = size; 6210 } 6211 PetscFunctionReturn(PETSC_SUCCESS); 6212 } 6213 6214 /* Compress out points not in the section */ 6215 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6216 { 6217 const PetscInt np = *numPoints; 6218 PetscInt pStart, pEnd, p, q; 6219 6220 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6221 for (p = 0, q = 0; p < np; ++p) { 6222 const PetscInt r = points[p * 2]; 6223 if ((r >= pStart) && (r < pEnd)) { 6224 points[q * 2] = r; 6225 points[q * 2 + 1] = points[p * 2 + 1]; 6226 ++q; 6227 } 6228 } 6229 *numPoints = q; 6230 return PETSC_SUCCESS; 6231 } 6232 6233 /* Compressed closure does not apply closure permutation */ 6234 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6235 { 6236 const PetscInt *cla = NULL; 6237 PetscInt np, *pts = NULL; 6238 6239 PetscFunctionBeginHot; 6240 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6241 if (!ornt && *clPoints) { 6242 PetscInt dof, off; 6243 6244 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6245 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6246 PetscCall(ISGetIndices(*clPoints, &cla)); 6247 np = dof / 2; 6248 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6249 } else { 6250 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6251 PetscCall(CompressPoints_Private(section, &np, pts)); 6252 } 6253 *numPoints = np; 6254 *points = pts; 6255 *clp = cla; 6256 PetscFunctionReturn(PETSC_SUCCESS); 6257 } 6258 6259 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6260 { 6261 PetscFunctionBeginHot; 6262 if (!*clPoints) { 6263 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6264 } else { 6265 PetscCall(ISRestoreIndices(*clPoints, clp)); 6266 } 6267 *numPoints = 0; 6268 *points = NULL; 6269 *clSec = NULL; 6270 *clPoints = NULL; 6271 *clp = NULL; 6272 PetscFunctionReturn(PETSC_SUCCESS); 6273 } 6274 6275 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6276 { 6277 PetscInt offset = 0, p; 6278 const PetscInt **perms = NULL; 6279 const PetscScalar **flips = NULL; 6280 6281 PetscFunctionBeginHot; 6282 *size = 0; 6283 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6284 for (p = 0; p < numPoints; p++) { 6285 const PetscInt point = points[2 * p]; 6286 const PetscInt *perm = perms ? perms[p] : NULL; 6287 const PetscScalar *flip = flips ? flips[p] : NULL; 6288 PetscInt dof, off, d; 6289 const PetscScalar *varr; 6290 6291 PetscCall(PetscSectionGetDof(section, point, &dof)); 6292 PetscCall(PetscSectionGetOffset(section, point, &off)); 6293 varr = PetscSafePointerPlusOffset(vArray, off); 6294 if (clperm) { 6295 if (perm) { 6296 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6297 } else { 6298 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6299 } 6300 if (flip) { 6301 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6302 } 6303 } else { 6304 if (perm) { 6305 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6306 } else { 6307 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6308 } 6309 if (flip) { 6310 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6311 } 6312 } 6313 offset += dof; 6314 } 6315 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6316 *size = offset; 6317 PetscFunctionReturn(PETSC_SUCCESS); 6318 } 6319 6320 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[]) 6321 { 6322 PetscInt offset = 0, f; 6323 6324 PetscFunctionBeginHot; 6325 *size = 0; 6326 for (f = 0; f < numFields; ++f) { 6327 PetscInt p; 6328 const PetscInt **perms = NULL; 6329 const PetscScalar **flips = NULL; 6330 6331 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6332 for (p = 0; p < numPoints; p++) { 6333 const PetscInt point = points[2 * p]; 6334 PetscInt fdof, foff, b; 6335 const PetscScalar *varr; 6336 const PetscInt *perm = perms ? perms[p] : NULL; 6337 const PetscScalar *flip = flips ? flips[p] : NULL; 6338 6339 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6340 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6341 varr = &vArray[foff]; 6342 if (clperm) { 6343 if (perm) { 6344 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6345 } else { 6346 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6347 } 6348 if (flip) { 6349 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6350 } 6351 } else { 6352 if (perm) { 6353 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6354 } else { 6355 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6356 } 6357 if (flip) { 6358 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6359 } 6360 } 6361 offset += fdof; 6362 } 6363 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6364 } 6365 *size = offset; 6366 PetscFunctionReturn(PETSC_SUCCESS); 6367 } 6368 6369 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6370 { 6371 PetscSection clSection; 6372 IS clPoints; 6373 PetscInt *points = NULL; 6374 const PetscInt *clp, *perm = NULL; 6375 PetscInt depth, numFields, numPoints, asize; 6376 6377 PetscFunctionBeginHot; 6378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6379 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6380 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6381 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6382 PetscCall(DMPlexGetDepth(dm, &depth)); 6383 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6384 if (depth == 1 && numFields < 2) { 6385 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6386 PetscFunctionReturn(PETSC_SUCCESS); 6387 } 6388 /* Get points */ 6389 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6390 /* Get sizes */ 6391 asize = 0; 6392 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6393 PetscInt dof; 6394 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6395 asize += dof; 6396 } 6397 if (values) { 6398 const PetscScalar *vArray; 6399 PetscInt size; 6400 6401 if (*values) { 6402 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); 6403 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6404 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6405 PetscCall(VecGetArrayRead(v, &vArray)); 6406 /* Get values */ 6407 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6408 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6409 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6410 /* Cleanup array */ 6411 PetscCall(VecRestoreArrayRead(v, &vArray)); 6412 } 6413 if (csize) *csize = asize; 6414 /* Cleanup points */ 6415 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6416 PetscFunctionReturn(PETSC_SUCCESS); 6417 } 6418 6419 /*@C 6420 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6421 6422 Not collective 6423 6424 Input Parameters: 6425 + dm - The `DM` 6426 . section - The section describing the layout in `v`, or `NULL` to use the default section 6427 . v - The local vector 6428 - point - The point in the `DM` 6429 6430 Input/Output Parameters: 6431 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6432 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6433 if the user provided `NULL`, it is a borrowed array and should not be freed 6434 6435 Level: intermediate 6436 6437 Notes: 6438 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6439 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6440 assembly function, and a user may already have allocated storage for this operation. 6441 6442 A typical use could be 6443 .vb 6444 values = NULL; 6445 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6446 for (cl = 0; cl < clSize; ++cl) { 6447 <Compute on closure> 6448 } 6449 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6450 .ve 6451 or 6452 .vb 6453 PetscMalloc1(clMaxSize, &values); 6454 for (p = pStart; p < pEnd; ++p) { 6455 clSize = clMaxSize; 6456 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6457 for (cl = 0; cl < clSize; ++cl) { 6458 <Compute on closure> 6459 } 6460 } 6461 PetscFree(values); 6462 .ve 6463 6464 Fortran Notes: 6465 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6466 6467 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6468 @*/ 6469 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6470 { 6471 PetscFunctionBeginHot; 6472 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6473 PetscFunctionReturn(PETSC_SUCCESS); 6474 } 6475 6476 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6477 { 6478 DMLabel depthLabel; 6479 PetscSection clSection; 6480 IS clPoints; 6481 PetscScalar *array; 6482 const PetscScalar *vArray; 6483 PetscInt *points = NULL; 6484 const PetscInt *clp, *perm = NULL; 6485 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6486 6487 PetscFunctionBeginHot; 6488 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6489 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6490 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6491 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6492 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6493 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6494 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6495 if (mdepth == 1 && numFields < 2) { 6496 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6497 PetscFunctionReturn(PETSC_SUCCESS); 6498 } 6499 /* Get points */ 6500 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6501 for (clsize = 0, p = 0; p < Np; p++) { 6502 PetscInt dof; 6503 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6504 clsize += dof; 6505 } 6506 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6507 /* Filter points */ 6508 for (p = 0; p < numPoints * 2; p += 2) { 6509 PetscInt dep; 6510 6511 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6512 if (dep != depth) continue; 6513 points[Np * 2 + 0] = points[p]; 6514 points[Np * 2 + 1] = points[p + 1]; 6515 ++Np; 6516 } 6517 /* Get array */ 6518 if (!values || !*values) { 6519 PetscInt asize = 0, dof; 6520 6521 for (p = 0; p < Np * 2; p += 2) { 6522 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6523 asize += dof; 6524 } 6525 if (!values) { 6526 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6527 if (csize) *csize = asize; 6528 PetscFunctionReturn(PETSC_SUCCESS); 6529 } 6530 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6531 } else { 6532 array = *values; 6533 } 6534 PetscCall(VecGetArrayRead(v, &vArray)); 6535 /* Get values */ 6536 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6537 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6538 /* Cleanup points */ 6539 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6540 /* Cleanup array */ 6541 PetscCall(VecRestoreArrayRead(v, &vArray)); 6542 if (!*values) { 6543 if (csize) *csize = size; 6544 *values = array; 6545 } else { 6546 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6547 *csize = size; 6548 } 6549 PetscFunctionReturn(PETSC_SUCCESS); 6550 } 6551 6552 /*@C 6553 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6554 6555 Not collective 6556 6557 Input Parameters: 6558 + dm - The `DM` 6559 . section - The section describing the layout in `v`, or `NULL` to use the default section 6560 . v - The local vector 6561 . point - The point in the `DM` 6562 . csize - The number of values in the closure, or `NULL` 6563 - values - The array of values, which is a borrowed array and should not be freed 6564 6565 Level: intermediate 6566 6567 Note: 6568 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6569 6570 Fortran Notes: 6571 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6572 6573 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6574 @*/ 6575 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6576 { 6577 PetscInt size = 0; 6578 6579 PetscFunctionBegin; 6580 /* Should work without recalculating size */ 6581 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6582 *values = NULL; 6583 PetscFunctionReturn(PETSC_SUCCESS); 6584 } 6585 6586 static inline void add(PetscScalar *x, PetscScalar y) 6587 { 6588 *x += y; 6589 } 6590 static inline void insert(PetscScalar *x, PetscScalar y) 6591 { 6592 *x = y; 6593 } 6594 6595 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[]) 6596 { 6597 PetscInt cdof; /* The number of constraints on this point */ 6598 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6599 PetscScalar *a; 6600 PetscInt off, cind = 0, k; 6601 6602 PetscFunctionBegin; 6603 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6604 PetscCall(PetscSectionGetOffset(section, point, &off)); 6605 a = &array[off]; 6606 if (!cdof || setBC) { 6607 if (clperm) { 6608 if (perm) { 6609 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6610 } else { 6611 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6612 } 6613 } else { 6614 if (perm) { 6615 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6616 } else { 6617 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6618 } 6619 } 6620 } else { 6621 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6622 if (clperm) { 6623 if (perm) { 6624 for (k = 0; k < dof; ++k) { 6625 if ((cind < cdof) && (k == cdofs[cind])) { 6626 ++cind; 6627 continue; 6628 } 6629 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6630 } 6631 } else { 6632 for (k = 0; k < dof; ++k) { 6633 if ((cind < cdof) && (k == cdofs[cind])) { 6634 ++cind; 6635 continue; 6636 } 6637 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6638 } 6639 } 6640 } else { 6641 if (perm) { 6642 for (k = 0; k < dof; ++k) { 6643 if ((cind < cdof) && (k == cdofs[cind])) { 6644 ++cind; 6645 continue; 6646 } 6647 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6648 } 6649 } else { 6650 for (k = 0; k < dof; ++k) { 6651 if ((cind < cdof) && (k == cdofs[cind])) { 6652 ++cind; 6653 continue; 6654 } 6655 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6656 } 6657 } 6658 } 6659 } 6660 PetscFunctionReturn(PETSC_SUCCESS); 6661 } 6662 6663 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[]) 6664 { 6665 PetscInt cdof; /* The number of constraints on this point */ 6666 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6667 PetscScalar *a; 6668 PetscInt off, cind = 0, k; 6669 6670 PetscFunctionBegin; 6671 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6672 PetscCall(PetscSectionGetOffset(section, point, &off)); 6673 a = &array[off]; 6674 if (cdof) { 6675 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6676 if (clperm) { 6677 if (perm) { 6678 for (k = 0; k < dof; ++k) { 6679 if ((cind < cdof) && (k == cdofs[cind])) { 6680 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6681 cind++; 6682 } 6683 } 6684 } else { 6685 for (k = 0; k < dof; ++k) { 6686 if ((cind < cdof) && (k == cdofs[cind])) { 6687 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6688 cind++; 6689 } 6690 } 6691 } 6692 } else { 6693 if (perm) { 6694 for (k = 0; k < dof; ++k) { 6695 if ((cind < cdof) && (k == cdofs[cind])) { 6696 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6697 cind++; 6698 } 6699 } 6700 } else { 6701 for (k = 0; k < dof; ++k) { 6702 if ((cind < cdof) && (k == cdofs[cind])) { 6703 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6704 cind++; 6705 } 6706 } 6707 } 6708 } 6709 } 6710 PetscFunctionReturn(PETSC_SUCCESS); 6711 } 6712 6713 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[]) 6714 { 6715 PetscScalar *a; 6716 PetscInt fdof, foff, fcdof, foffset = *offset; 6717 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6718 PetscInt cind = 0, b; 6719 6720 PetscFunctionBegin; 6721 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6722 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6723 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6724 a = &array[foff]; 6725 if (!fcdof || setBC) { 6726 if (clperm) { 6727 if (perm) { 6728 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6729 } else { 6730 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6731 } 6732 } else { 6733 if (perm) { 6734 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6735 } else { 6736 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6737 } 6738 } 6739 } else { 6740 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6741 if (clperm) { 6742 if (perm) { 6743 for (b = 0; b < fdof; b++) { 6744 if ((cind < fcdof) && (b == fcdofs[cind])) { 6745 ++cind; 6746 continue; 6747 } 6748 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6749 } 6750 } else { 6751 for (b = 0; b < fdof; b++) { 6752 if ((cind < fcdof) && (b == fcdofs[cind])) { 6753 ++cind; 6754 continue; 6755 } 6756 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6757 } 6758 } 6759 } else { 6760 if (perm) { 6761 for (b = 0; b < fdof; b++) { 6762 if ((cind < fcdof) && (b == fcdofs[cind])) { 6763 ++cind; 6764 continue; 6765 } 6766 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6767 } 6768 } else { 6769 for (b = 0; b < fdof; b++) { 6770 if ((cind < fcdof) && (b == fcdofs[cind])) { 6771 ++cind; 6772 continue; 6773 } 6774 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6775 } 6776 } 6777 } 6778 } 6779 *offset += fdof; 6780 PetscFunctionReturn(PETSC_SUCCESS); 6781 } 6782 6783 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[]) 6784 { 6785 PetscScalar *a; 6786 PetscInt fdof, foff, fcdof, foffset = *offset; 6787 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6788 PetscInt Nc, cind = 0, ncind = 0, b; 6789 PetscBool ncSet, fcSet; 6790 6791 PetscFunctionBegin; 6792 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6793 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6794 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6795 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6796 a = &array[foff]; 6797 if (fcdof) { 6798 /* We just override fcdof and fcdofs with Ncc and comps */ 6799 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6800 if (clperm) { 6801 if (perm) { 6802 if (comps) { 6803 for (b = 0; b < fdof; b++) { 6804 ncSet = fcSet = PETSC_FALSE; 6805 if (b % Nc == comps[ncind]) { 6806 ncind = (ncind + 1) % Ncc; 6807 ncSet = PETSC_TRUE; 6808 } 6809 if ((cind < fcdof) && (b == fcdofs[cind])) { 6810 ++cind; 6811 fcSet = PETSC_TRUE; 6812 } 6813 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6814 } 6815 } else { 6816 for (b = 0; b < fdof; b++) { 6817 if ((cind < fcdof) && (b == fcdofs[cind])) { 6818 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6819 ++cind; 6820 } 6821 } 6822 } 6823 } else { 6824 if (comps) { 6825 for (b = 0; b < fdof; b++) { 6826 ncSet = fcSet = PETSC_FALSE; 6827 if (b % Nc == comps[ncind]) { 6828 ncind = (ncind + 1) % Ncc; 6829 ncSet = PETSC_TRUE; 6830 } 6831 if ((cind < fcdof) && (b == fcdofs[cind])) { 6832 ++cind; 6833 fcSet = PETSC_TRUE; 6834 } 6835 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6836 } 6837 } else { 6838 for (b = 0; b < fdof; b++) { 6839 if ((cind < fcdof) && (b == fcdofs[cind])) { 6840 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6841 ++cind; 6842 } 6843 } 6844 } 6845 } 6846 } else { 6847 if (perm) { 6848 if (comps) { 6849 for (b = 0; b < fdof; b++) { 6850 ncSet = fcSet = PETSC_FALSE; 6851 if (b % Nc == comps[ncind]) { 6852 ncind = (ncind + 1) % Ncc; 6853 ncSet = PETSC_TRUE; 6854 } 6855 if ((cind < fcdof) && (b == fcdofs[cind])) { 6856 ++cind; 6857 fcSet = PETSC_TRUE; 6858 } 6859 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6860 } 6861 } else { 6862 for (b = 0; b < fdof; b++) { 6863 if ((cind < fcdof) && (b == fcdofs[cind])) { 6864 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6865 ++cind; 6866 } 6867 } 6868 } 6869 } else { 6870 if (comps) { 6871 for (b = 0; b < fdof; b++) { 6872 ncSet = fcSet = PETSC_FALSE; 6873 if (b % Nc == comps[ncind]) { 6874 ncind = (ncind + 1) % Ncc; 6875 ncSet = PETSC_TRUE; 6876 } 6877 if ((cind < fcdof) && (b == fcdofs[cind])) { 6878 ++cind; 6879 fcSet = PETSC_TRUE; 6880 } 6881 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6882 } 6883 } else { 6884 for (b = 0; b < fdof; b++) { 6885 if ((cind < fcdof) && (b == fcdofs[cind])) { 6886 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6887 ++cind; 6888 } 6889 } 6890 } 6891 } 6892 } 6893 } 6894 *offset += fdof; 6895 PetscFunctionReturn(PETSC_SUCCESS); 6896 } 6897 6898 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6899 { 6900 PetscScalar *array; 6901 const PetscInt *cone, *coneO; 6902 PetscInt pStart, pEnd, p, numPoints, off, dof; 6903 6904 PetscFunctionBeginHot; 6905 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6906 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6907 PetscCall(DMPlexGetCone(dm, point, &cone)); 6908 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6909 PetscCall(VecGetArray(v, &array)); 6910 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6911 const PetscInt cp = !p ? point : cone[p - 1]; 6912 const PetscInt o = !p ? 0 : coneO[p - 1]; 6913 6914 if ((cp < pStart) || (cp >= pEnd)) { 6915 dof = 0; 6916 continue; 6917 } 6918 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6919 /* ADD_VALUES */ 6920 { 6921 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6922 PetscScalar *a; 6923 PetscInt cdof, coff, cind = 0, k; 6924 6925 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6926 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6927 a = &array[coff]; 6928 if (!cdof) { 6929 if (o >= 0) { 6930 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6931 } else { 6932 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6933 } 6934 } else { 6935 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6936 if (o >= 0) { 6937 for (k = 0; k < dof; ++k) { 6938 if ((cind < cdof) && (k == cdofs[cind])) { 6939 ++cind; 6940 continue; 6941 } 6942 a[k] += values[off + k]; 6943 } 6944 } else { 6945 for (k = 0; k < dof; ++k) { 6946 if ((cind < cdof) && (k == cdofs[cind])) { 6947 ++cind; 6948 continue; 6949 } 6950 a[k] += values[off + dof - k - 1]; 6951 } 6952 } 6953 } 6954 } 6955 } 6956 PetscCall(VecRestoreArray(v, &array)); 6957 PetscFunctionReturn(PETSC_SUCCESS); 6958 } 6959 6960 /*@C 6961 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6962 6963 Not collective 6964 6965 Input Parameters: 6966 + dm - The `DM` 6967 . section - The section describing the layout in `v`, or `NULL` to use the default section 6968 . v - The local vector 6969 . point - The point in the `DM` 6970 . values - The array of values 6971 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6972 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6973 6974 Level: intermediate 6975 6976 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6977 @*/ 6978 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6979 { 6980 PetscSection clSection; 6981 IS clPoints; 6982 PetscScalar *array; 6983 PetscInt *points = NULL; 6984 const PetscInt *clp, *clperm = NULL; 6985 PetscInt depth, numFields, numPoints, p, clsize; 6986 6987 PetscFunctionBeginHot; 6988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6989 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6990 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6991 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6992 PetscCall(DMPlexGetDepth(dm, &depth)); 6993 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6994 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6995 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6996 PetscFunctionReturn(PETSC_SUCCESS); 6997 } 6998 /* Get points */ 6999 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7000 for (clsize = 0, p = 0; p < numPoints; p++) { 7001 PetscInt dof; 7002 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7003 clsize += dof; 7004 } 7005 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7006 /* Get array */ 7007 PetscCall(VecGetArray(v, &array)); 7008 /* Get values */ 7009 if (numFields > 0) { 7010 PetscInt offset = 0, f; 7011 for (f = 0; f < numFields; ++f) { 7012 const PetscInt **perms = NULL; 7013 const PetscScalar **flips = NULL; 7014 7015 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7016 switch (mode) { 7017 case INSERT_VALUES: 7018 for (p = 0; p < numPoints; p++) { 7019 const PetscInt point = points[2 * p]; 7020 const PetscInt *perm = perms ? perms[p] : NULL; 7021 const PetscScalar *flip = flips ? flips[p] : NULL; 7022 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7023 } 7024 break; 7025 case INSERT_ALL_VALUES: 7026 for (p = 0; p < numPoints; p++) { 7027 const PetscInt point = points[2 * p]; 7028 const PetscInt *perm = perms ? perms[p] : NULL; 7029 const PetscScalar *flip = flips ? flips[p] : NULL; 7030 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7031 } 7032 break; 7033 case INSERT_BC_VALUES: 7034 for (p = 0; p < numPoints; p++) { 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(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7039 } 7040 break; 7041 case ADD_VALUES: 7042 for (p = 0; p < numPoints; p++) { 7043 const PetscInt point = points[2 * p]; 7044 const PetscInt *perm = perms ? perms[p] : NULL; 7045 const PetscScalar *flip = flips ? flips[p] : NULL; 7046 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7047 } 7048 break; 7049 case ADD_ALL_VALUES: 7050 for (p = 0; p < numPoints; p++) { 7051 const PetscInt point = points[2 * p]; 7052 const PetscInt *perm = perms ? perms[p] : NULL; 7053 const PetscScalar *flip = flips ? flips[p] : NULL; 7054 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7055 } 7056 break; 7057 case ADD_BC_VALUES: 7058 for (p = 0; p < numPoints; p++) { 7059 const PetscInt point = points[2 * p]; 7060 const PetscInt *perm = perms ? perms[p] : NULL; 7061 const PetscScalar *flip = flips ? flips[p] : NULL; 7062 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7063 } 7064 break; 7065 default: 7066 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7067 } 7068 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7069 } 7070 } else { 7071 PetscInt dof, off; 7072 const PetscInt **perms = NULL; 7073 const PetscScalar **flips = NULL; 7074 7075 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7076 switch (mode) { 7077 case INSERT_VALUES: 7078 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7079 const PetscInt point = points[2 * p]; 7080 const PetscInt *perm = perms ? perms[p] : NULL; 7081 const PetscScalar *flip = flips ? flips[p] : NULL; 7082 PetscCall(PetscSectionGetDof(section, point, &dof)); 7083 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7084 } 7085 break; 7086 case INSERT_ALL_VALUES: 7087 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7088 const PetscInt point = points[2 * p]; 7089 const PetscInt *perm = perms ? perms[p] : NULL; 7090 const PetscScalar *flip = flips ? flips[p] : NULL; 7091 PetscCall(PetscSectionGetDof(section, point, &dof)); 7092 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7093 } 7094 break; 7095 case INSERT_BC_VALUES: 7096 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7097 const PetscInt point = points[2 * p]; 7098 const PetscInt *perm = perms ? perms[p] : NULL; 7099 const PetscScalar *flip = flips ? flips[p] : NULL; 7100 PetscCall(PetscSectionGetDof(section, point, &dof)); 7101 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7102 } 7103 break; 7104 case ADD_VALUES: 7105 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7106 const PetscInt point = points[2 * p]; 7107 const PetscInt *perm = perms ? perms[p] : NULL; 7108 const PetscScalar *flip = flips ? flips[p] : NULL; 7109 PetscCall(PetscSectionGetDof(section, point, &dof)); 7110 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7111 } 7112 break; 7113 case ADD_ALL_VALUES: 7114 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7115 const PetscInt point = points[2 * p]; 7116 const PetscInt *perm = perms ? perms[p] : NULL; 7117 const PetscScalar *flip = flips ? flips[p] : NULL; 7118 PetscCall(PetscSectionGetDof(section, point, &dof)); 7119 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7120 } 7121 break; 7122 case ADD_BC_VALUES: 7123 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7124 const PetscInt point = points[2 * p]; 7125 const PetscInt *perm = perms ? perms[p] : NULL; 7126 const PetscScalar *flip = flips ? flips[p] : NULL; 7127 PetscCall(PetscSectionGetDof(section, point, &dof)); 7128 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7129 } 7130 break; 7131 default: 7132 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7133 } 7134 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7135 } 7136 /* Cleanup points */ 7137 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7138 /* Cleanup array */ 7139 PetscCall(VecRestoreArray(v, &array)); 7140 PetscFunctionReturn(PETSC_SUCCESS); 7141 } 7142 7143 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7144 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7145 { 7146 PetscFunctionBegin; 7147 *contains = PETSC_TRUE; 7148 if (label) { 7149 PetscInt fdof; 7150 7151 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7152 if (!*contains) { 7153 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7154 *offset += fdof; 7155 PetscFunctionReturn(PETSC_SUCCESS); 7156 } 7157 } 7158 PetscFunctionReturn(PETSC_SUCCESS); 7159 } 7160 7161 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7162 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) 7163 { 7164 PetscSection clSection; 7165 IS clPoints; 7166 PetscScalar *array; 7167 PetscInt *points = NULL; 7168 const PetscInt *clp; 7169 PetscInt numFields, numPoints, p; 7170 PetscInt offset = 0, f; 7171 7172 PetscFunctionBeginHot; 7173 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7174 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7175 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7176 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7177 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7178 /* Get points */ 7179 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7180 /* Get array */ 7181 PetscCall(VecGetArray(v, &array)); 7182 /* Get values */ 7183 for (f = 0; f < numFields; ++f) { 7184 const PetscInt **perms = NULL; 7185 const PetscScalar **flips = NULL; 7186 PetscBool contains; 7187 7188 if (!fieldActive[f]) { 7189 for (p = 0; p < numPoints * 2; p += 2) { 7190 PetscInt fdof; 7191 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7192 offset += fdof; 7193 } 7194 continue; 7195 } 7196 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7197 switch (mode) { 7198 case INSERT_VALUES: 7199 for (p = 0; p < numPoints; p++) { 7200 const PetscInt point = points[2 * p]; 7201 const PetscInt *perm = perms ? perms[p] : NULL; 7202 const PetscScalar *flip = flips ? flips[p] : NULL; 7203 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7204 if (!contains) continue; 7205 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7206 } 7207 break; 7208 case INSERT_ALL_VALUES: 7209 for (p = 0; p < numPoints; p++) { 7210 const PetscInt point = points[2 * p]; 7211 const PetscInt *perm = perms ? perms[p] : NULL; 7212 const PetscScalar *flip = flips ? flips[p] : NULL; 7213 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7214 if (!contains) continue; 7215 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7216 } 7217 break; 7218 case INSERT_BC_VALUES: 7219 for (p = 0; p < numPoints; p++) { 7220 const PetscInt point = points[2 * p]; 7221 const PetscInt *perm = perms ? perms[p] : NULL; 7222 const PetscScalar *flip = flips ? flips[p] : NULL; 7223 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7224 if (!contains) continue; 7225 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7226 } 7227 break; 7228 case ADD_VALUES: 7229 for (p = 0; p < numPoints; p++) { 7230 const PetscInt point = points[2 * p]; 7231 const PetscInt *perm = perms ? perms[p] : NULL; 7232 const PetscScalar *flip = flips ? flips[p] : NULL; 7233 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7234 if (!contains) continue; 7235 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7236 } 7237 break; 7238 case ADD_ALL_VALUES: 7239 for (p = 0; p < numPoints; p++) { 7240 const PetscInt point = points[2 * p]; 7241 const PetscInt *perm = perms ? perms[p] : NULL; 7242 const PetscScalar *flip = flips ? flips[p] : NULL; 7243 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7244 if (!contains) continue; 7245 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7246 } 7247 break; 7248 default: 7249 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7250 } 7251 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7252 } 7253 /* Cleanup points */ 7254 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7255 /* Cleanup array */ 7256 PetscCall(VecRestoreArray(v, &array)); 7257 PetscFunctionReturn(PETSC_SUCCESS); 7258 } 7259 7260 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7261 { 7262 PetscMPIInt rank; 7263 PetscInt i, j; 7264 7265 PetscFunctionBegin; 7266 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7267 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7268 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7269 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7270 numCIndices = numCIndices ? numCIndices : numRIndices; 7271 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7272 for (i = 0; i < numRIndices; i++) { 7273 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7274 for (j = 0; j < numCIndices; j++) { 7275 #if defined(PETSC_USE_COMPLEX) 7276 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7277 #else 7278 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7279 #endif 7280 } 7281 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7282 } 7283 PetscFunctionReturn(PETSC_SUCCESS); 7284 } 7285 7286 /* 7287 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7288 7289 Input Parameters: 7290 + section - The section for this data layout 7291 . islocal - Is the section (and thus indices being requested) local or global? 7292 . point - The point contributing dofs with these indices 7293 . off - The global offset of this point 7294 . loff - The local offset of each field 7295 . setBC - The flag determining whether to include indices of boundary values 7296 . perm - A permutation of the dofs on this point, or NULL 7297 - indperm - A permutation of the entire indices array, or NULL 7298 7299 Output Parameter: 7300 . indices - Indices for dofs on this point 7301 7302 Level: developer 7303 7304 Note: The indices could be local or global, depending on the value of 'off'. 7305 */ 7306 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7307 { 7308 PetscInt dof; /* The number of unknowns on this point */ 7309 PetscInt cdof; /* The number of constraints on this point */ 7310 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7311 PetscInt cind = 0, k; 7312 7313 PetscFunctionBegin; 7314 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7315 PetscCall(PetscSectionGetDof(section, point, &dof)); 7316 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7317 if (!cdof || setBC) { 7318 for (k = 0; k < dof; ++k) { 7319 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7320 const PetscInt ind = indperm ? indperm[preind] : preind; 7321 7322 indices[ind] = off + k; 7323 } 7324 } else { 7325 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7326 for (k = 0; k < dof; ++k) { 7327 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7328 const PetscInt ind = indperm ? indperm[preind] : preind; 7329 7330 if ((cind < cdof) && (k == cdofs[cind])) { 7331 /* Insert check for returning constrained indices */ 7332 indices[ind] = -(off + k + 1); 7333 ++cind; 7334 } else { 7335 indices[ind] = off + k - (islocal ? 0 : cind); 7336 } 7337 } 7338 } 7339 *loff += dof; 7340 PetscFunctionReturn(PETSC_SUCCESS); 7341 } 7342 7343 /* 7344 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7345 7346 Input Parameters: 7347 + section - a section (global or local) 7348 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7349 . point - point within section 7350 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7351 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7352 . setBC - identify constrained (boundary condition) points via involution. 7353 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7354 . permsoff - offset 7355 - indperm - index permutation 7356 7357 Output Parameter: 7358 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7359 . indices - array to hold indices (as defined by section) of each dof associated with point 7360 7361 Notes: 7362 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7363 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7364 in the local vector. 7365 7366 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7367 significant). It is invalid to call with a global section and setBC=true. 7368 7369 Developer Note: 7370 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7371 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7372 offset could be obtained from the section instead of passing it explicitly as we do now. 7373 7374 Example: 7375 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7376 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7377 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7378 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. 7379 7380 Level: developer 7381 */ 7382 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[]) 7383 { 7384 PetscInt numFields, foff, f; 7385 7386 PetscFunctionBegin; 7387 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7388 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7389 for (f = 0, foff = 0; f < numFields; ++f) { 7390 PetscInt fdof, cfdof; 7391 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7392 PetscInt cind = 0, b; 7393 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7394 7395 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7396 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7397 if (!cfdof || setBC) { 7398 for (b = 0; b < fdof; ++b) { 7399 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7400 const PetscInt ind = indperm ? indperm[preind] : preind; 7401 7402 indices[ind] = off + foff + b; 7403 } 7404 } else { 7405 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7406 for (b = 0; b < fdof; ++b) { 7407 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7408 const PetscInt ind = indperm ? indperm[preind] : preind; 7409 7410 if ((cind < cfdof) && (b == fcdofs[cind])) { 7411 indices[ind] = -(off + foff + b + 1); 7412 ++cind; 7413 } else { 7414 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7415 } 7416 } 7417 } 7418 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7419 foffs[f] += fdof; 7420 } 7421 PetscFunctionReturn(PETSC_SUCCESS); 7422 } 7423 7424 /* 7425 This version believes the globalSection offsets for each field, rather than just the point offset 7426 7427 . foffs - The offset into 'indices' for each field, since it is segregated by field 7428 7429 Notes: 7430 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7431 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7432 */ 7433 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7434 { 7435 PetscInt numFields, foff, f; 7436 7437 PetscFunctionBegin; 7438 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7439 for (f = 0; f < numFields; ++f) { 7440 PetscInt fdof, cfdof; 7441 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7442 PetscInt cind = 0, b; 7443 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7444 7445 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7446 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7447 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7448 if (!cfdof) { 7449 for (b = 0; b < fdof; ++b) { 7450 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7451 const PetscInt ind = indperm ? indperm[preind] : preind; 7452 7453 indices[ind] = foff + b; 7454 } 7455 } else { 7456 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7457 for (b = 0; b < fdof; ++b) { 7458 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7459 const PetscInt ind = indperm ? indperm[preind] : preind; 7460 7461 if ((cind < cfdof) && (b == fcdofs[cind])) { 7462 indices[ind] = -(foff + b + 1); 7463 ++cind; 7464 } else { 7465 indices[ind] = foff + b - cind; 7466 } 7467 } 7468 } 7469 foffs[f] += fdof; 7470 } 7471 PetscFunctionReturn(PETSC_SUCCESS); 7472 } 7473 7474 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7475 { 7476 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7477 7478 PetscFunctionBegin; 7479 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7480 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7481 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7482 for (PetscInt p = 0; p < nPoints; p++) { 7483 PetscInt b = pnts[2 * p]; 7484 PetscInt bSecDof = 0, bOff; 7485 PetscInt cSecDof = 0; 7486 PetscSection indices_section; 7487 7488 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7489 if (!bSecDof) continue; 7490 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7491 indices_section = cSecDof > 0 ? cSec : section; 7492 if (numFields) { 7493 PetscInt fStart[32], fEnd[32]; 7494 7495 fStart[0] = 0; 7496 fEnd[0] = 0; 7497 for (PetscInt f = 0; f < numFields; f++) { 7498 PetscInt fDof = 0; 7499 7500 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7501 fStart[f + 1] = fStart[f] + fDof; 7502 fEnd[f + 1] = fStart[f + 1]; 7503 } 7504 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7505 // only apply permutations on one side 7506 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7507 for (PetscInt f = 0; f < numFields; f++) { 7508 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7509 } 7510 } else { 7511 PetscInt bEnd = 0; 7512 7513 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7514 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7515 7516 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7517 } 7518 } 7519 PetscFunctionReturn(PETSC_SUCCESS); 7520 } 7521 7522 PETSC_INTERN PetscErrorCode DMPlexAnchorsGetSubMatModification(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscInt offsets[], PetscScalar *outMat[]) 7523 { 7524 Mat cMat; 7525 PetscSection aSec, cSec; 7526 IS aIS; 7527 PetscInt aStart = -1, aEnd = -1; 7528 PetscInt sStart = -1, sEnd = -1; 7529 PetscInt cStart = -1, cEnd = -1; 7530 const PetscInt *anchors; 7531 PetscInt numFields, p; 7532 PetscInt newNumPoints = 0, newNumIndices = 0; 7533 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7534 PetscInt oldOffsets[32]; 7535 PetscInt newOffsets[32]; 7536 PetscInt oldOffsetsCopy[32]; 7537 PetscInt newOffsetsCopy[32]; 7538 PetscScalar *modMat = NULL; 7539 PetscBool anyConstrained = PETSC_FALSE; 7540 7541 PetscFunctionBegin; 7542 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7543 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7544 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7545 7546 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7547 /* if there are point-to-point constraints */ 7548 if (aSec) { 7549 PetscCall(PetscArrayzero(newOffsets, 32)); 7550 PetscCall(PetscArrayzero(oldOffsets, 32)); 7551 PetscCall(ISGetIndices(aIS, &anchors)); 7552 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7553 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7554 /* figure out how many points are going to be in the new element matrix 7555 * (we allow double counting, because it's all just going to be summed 7556 * into the global matrix anyway) */ 7557 for (p = 0; p < 2 * numPoints; p += 2) { 7558 PetscInt b = points[p]; 7559 PetscInt bDof = 0, bSecDof = 0; 7560 7561 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7562 if (!bSecDof) continue; 7563 7564 for (PetscInt f = 0; f < numFields; f++) { 7565 PetscInt fDof = 0; 7566 7567 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7568 oldOffsets[f + 1] += fDof; 7569 } 7570 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7571 if (bDof) { 7572 /* this point is constrained */ 7573 /* it is going to be replaced by its anchors */ 7574 PetscInt bOff, q; 7575 7576 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7577 for (q = 0; q < bDof; q++) { 7578 PetscInt a = anchors[bOff + q]; 7579 PetscInt aDof = 0; 7580 7581 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7582 if (aDof) { 7583 anyConstrained = PETSC_TRUE; 7584 newNumPoints += 1; 7585 } 7586 newNumIndices += aDof; 7587 for (PetscInt f = 0; f < numFields; ++f) { 7588 PetscInt fDof = 0; 7589 7590 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7591 newOffsets[f + 1] += fDof; 7592 } 7593 } 7594 } else { 7595 /* this point is not constrained */ 7596 newNumPoints++; 7597 newNumIndices += bSecDof; 7598 for (PetscInt f = 0; f < numFields; ++f) { 7599 PetscInt fDof; 7600 7601 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7602 newOffsets[f + 1] += fDof; 7603 } 7604 } 7605 } 7606 } 7607 if (!anyConstrained) { 7608 if (outNumPoints) *outNumPoints = 0; 7609 if (outNumIndices) *outNumIndices = 0; 7610 if (outPoints) *outPoints = NULL; 7611 if (outMat) *outMat = NULL; 7612 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7613 PetscFunctionReturn(PETSC_SUCCESS); 7614 } 7615 7616 if (outNumPoints) *outNumPoints = newNumPoints; 7617 if (outNumIndices) *outNumIndices = newNumIndices; 7618 7619 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7620 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7621 7622 if (!outPoints && !outMat) { 7623 if (offsets) { 7624 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7625 } 7626 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7627 PetscFunctionReturn(PETSC_SUCCESS); 7628 } 7629 7630 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7631 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7632 7633 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7634 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7635 7636 /* output arrays */ 7637 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7638 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7639 7640 // get the new Points 7641 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7642 PetscInt b = points[2 * p]; 7643 PetscInt bDof = 0, bSecDof = 0, bOff; 7644 7645 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7646 if (!bSecDof) continue; 7647 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7648 if (bDof) { 7649 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7650 for (PetscInt q = 0; q < bDof; q++) { 7651 PetscInt a = anchors[bOff + q], aDof = 0; 7652 7653 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7654 if (aDof) { 7655 newPoints[2 * newP] = a; 7656 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7657 newP++; 7658 } 7659 } 7660 } else { 7661 newPoints[2 * newP] = b; 7662 newPoints[2 * newP + 1] = points[2 * p + 1]; 7663 newP++; 7664 } 7665 } 7666 7667 if (outMat) { 7668 PetscScalar *tmpMat; 7669 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7670 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7671 7672 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7673 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7674 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7675 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7676 7677 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7678 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7679 7680 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7681 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7682 7683 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7684 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7685 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7686 // for each field, insert the anchor modification into modMat 7687 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7688 PetscInt fStart = oldOffsets[f]; 7689 PetscInt fNewStart = newOffsets[f]; 7690 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7691 PetscInt b = points[2 * p]; 7692 PetscInt bDof = 0, bSecDof = 0, bOff; 7693 7694 if (b >= sStart && b < sEnd) { 7695 if (numFields) { 7696 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7697 } else { 7698 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7699 } 7700 } 7701 if (!bSecDof) continue; 7702 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7703 if (bDof) { 7704 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7705 for (PetscInt q = 0; q < bDof; q++, newP++) { 7706 PetscInt a = anchors[bOff + q], aDof = 0; 7707 7708 if (a >= sStart && a < sEnd) { 7709 if (numFields) { 7710 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7711 } else { 7712 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7713 } 7714 } 7715 if (aDof) { 7716 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7717 for (PetscInt d = 0; d < bSecDof; d++) { 7718 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7719 } 7720 } 7721 oNew += aDof; 7722 } 7723 } else { 7724 // Insert the identity matrix in this block 7725 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7726 oNew += bSecDof; 7727 newP++; 7728 } 7729 o += bSecDof; 7730 } 7731 } 7732 7733 *outMat = modMat; 7734 7735 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7736 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7737 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7738 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7739 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7740 } 7741 PetscCall(ISRestoreIndices(aIS, &anchors)); 7742 7743 /* output */ 7744 if (outPoints) { 7745 *outPoints = newPoints; 7746 } else { 7747 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7748 } 7749 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7750 PetscFunctionReturn(PETSC_SUCCESS); 7751 } 7752 7753 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat_Internal(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, PetscInt numRows, PetscInt numCols, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyRight, PetscBool multiplyLeft) 7754 { 7755 PetscScalar *modMat = NULL; 7756 PetscInt newNumIndices = -1; 7757 7758 PetscFunctionBegin; 7759 /* If M is the matrix represented by values, get the matrix C such that we will add M * C (or, if multiplyLeft, C^T * M * C) into the global matrix. 7760 modMat is that matrix C */ 7761 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7762 if (outNumIndices) *outNumIndices = newNumIndices; 7763 if (modMat) { 7764 const PetscScalar *newValues = values; 7765 7766 if (multiplyRight) { 7767 PetscScalar *newNewValues = NULL; 7768 PetscBLASInt M = newNumIndices; 7769 PetscBLASInt N = numRows; 7770 PetscBLASInt K = numIndices; 7771 PetscScalar a = 1.0, b = 0.0; 7772 7773 PetscCheck(numCols == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of columns: %" PetscInt_FMT ", expected %" PetscInt_FMT, numCols, numIndices); 7774 7775 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7776 // row-major to column-major conversion, right multiplication becomes left multiplication 7777 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7778 7779 numCols = newNumIndices; 7780 newValues = newNewValues; 7781 } 7782 7783 if (multiplyLeft) { 7784 PetscScalar *newNewValues = NULL; 7785 PetscBLASInt M = numCols; 7786 PetscBLASInt N = newNumIndices; 7787 PetscBLASInt K = numIndices; 7788 PetscScalar a = 1.0, b = 0.0; 7789 7790 PetscCheck(numRows == numIndices, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "values matrix has the wrong number of rows: %" PetscInt_FMT ", expected %" PetscInt_FMT, numRows, numIndices); 7791 7792 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7793 // row-major to column-major conversion, left multiplication becomes right multiplication 7794 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7795 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7796 newValues = newNewValues; 7797 } 7798 *outValues = (PetscScalar *)newValues; 7799 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7800 } 7801 PetscFunctionReturn(PETSC_SUCCESS); 7802 } 7803 7804 PETSC_INTERN PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscInt ***perms, const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 7805 { 7806 PetscFunctionBegin; 7807 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7808 PetscFunctionReturn(PETSC_SUCCESS); 7809 } 7810 7811 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7812 { 7813 /* Closure ordering */ 7814 PetscSection clSection; 7815 IS clPoints; 7816 const PetscInt *clp; 7817 PetscInt *points; 7818 PetscInt Ncl, Ni = 0; 7819 7820 PetscFunctionBeginHot; 7821 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7822 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7823 PetscInt dof; 7824 7825 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7826 Ni += dof; 7827 } 7828 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7829 *closureSize = Ni; 7830 PetscFunctionReturn(PETSC_SUCCESS); 7831 } 7832 7833 static PetscErrorCode DMPlexGetClosureIndices_Internal(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numRows, PetscInt *numCols, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[], PetscBool multiplyRight, PetscBool multiplyLeft) 7834 { 7835 /* Closure ordering */ 7836 PetscSection clSection; 7837 IS clPoints; 7838 const PetscInt *clp; 7839 PetscInt *points; 7840 const PetscInt *clperm = NULL; 7841 /* Dof permutation and sign flips */ 7842 const PetscInt **perms[32] = {NULL}; 7843 const PetscScalar **flips[32] = {NULL}; 7844 PetscScalar *valCopy = NULL; 7845 /* Hanging node constraints */ 7846 PetscInt *pointsC = NULL; 7847 PetscScalar *valuesC = NULL; 7848 PetscInt NclC, NiC; 7849 7850 PetscInt *idx; 7851 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7852 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7853 PetscInt idxStart, idxEnd; 7854 PetscInt nRows, nCols; 7855 7856 PetscFunctionBeginHot; 7857 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7858 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7859 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7860 PetscAssertPointer(numRows, 6); 7861 PetscAssertPointer(numCols, 7); 7862 if (indices) PetscAssertPointer(indices, 8); 7863 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7864 if (values) PetscAssertPointer(values, 10); 7865 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7866 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7867 PetscCall(PetscArrayzero(offsets, 32)); 7868 /* 1) Get points in closure */ 7869 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7870 if (useClPerm) { 7871 PetscInt depth, clsize; 7872 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7873 for (clsize = 0, p = 0; p < Ncl; p++) { 7874 PetscInt dof; 7875 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7876 clsize += dof; 7877 } 7878 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7879 } 7880 /* 2) Get number of indices on these points and field offsets from section */ 7881 for (p = 0; p < Ncl * 2; p += 2) { 7882 PetscInt dof, fdof; 7883 7884 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7885 for (f = 0; f < Nf; ++f) { 7886 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7887 offsets[f + 1] += fdof; 7888 } 7889 Ni += dof; 7890 } 7891 if (*numRows == -1) *numRows = Ni; 7892 if (*numCols == -1) *numCols = Ni; 7893 nRows = *numRows; 7894 nCols = *numCols; 7895 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7896 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7897 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7898 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7899 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7900 for (f = 0; f < PetscMax(1, Nf); ++f) { 7901 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7902 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7903 /* may need to apply sign changes to the element matrix */ 7904 if (values && flips[f]) { 7905 PetscInt foffset = offsets[f]; 7906 7907 for (p = 0; p < Ncl; ++p) { 7908 PetscInt pnt = points[2 * p], fdof; 7909 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7910 7911 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7912 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7913 if (flip) { 7914 PetscInt i, j, k; 7915 7916 if (!valCopy) { 7917 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7918 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7919 *values = valCopy; 7920 } 7921 for (i = 0; i < fdof; ++i) { 7922 PetscScalar fval = flip[i]; 7923 7924 if (multiplyRight) { 7925 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7926 } 7927 if (multiplyLeft) { 7928 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7929 } 7930 } 7931 } 7932 foffset += fdof; 7933 } 7934 } 7935 } 7936 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7937 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7938 if (NclC) { 7939 if (multiplyRight) { *numCols = nCols = NiC; } 7940 if (multiplyLeft) { *numRows = nRows = NiC; } 7941 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7942 for (f = 0; f < PetscMax(1, Nf); ++f) { 7943 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7944 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7945 } 7946 for (f = 0; f < PetscMax(1, Nf); ++f) { 7947 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7948 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7949 } 7950 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7951 Ncl = NclC; 7952 Ni = NiC; 7953 points = pointsC; 7954 if (values) *values = valuesC; 7955 } 7956 /* 5) Calculate indices */ 7957 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7958 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 7959 if (Nf) { 7960 PetscInt idxOff; 7961 PetscBool useFieldOffsets; 7962 7963 if (outOffsets) { 7964 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7965 } 7966 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7967 if (useFieldOffsets) { 7968 for (p = 0; p < Ncl; ++p) { 7969 const PetscInt pnt = points[p * 2]; 7970 7971 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7972 } 7973 } else { 7974 for (p = 0; p < Ncl; ++p) { 7975 const PetscInt pnt = points[p * 2]; 7976 7977 if (pnt < idxStart || pnt >= idxEnd) continue; 7978 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7979 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7980 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7981 * global section. */ 7982 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7983 } 7984 } 7985 } else { 7986 PetscInt off = 0, idxOff; 7987 7988 for (p = 0; p < Ncl; ++p) { 7989 const PetscInt pnt = points[p * 2]; 7990 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7991 7992 if (pnt < idxStart || pnt >= idxEnd) continue; 7993 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7994 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7995 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7996 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7997 } 7998 } 7999 /* 6) Cleanup */ 8000 for (f = 0; f < PetscMax(1, Nf); ++f) { 8001 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8002 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8003 } 8004 if (NclC) { 8005 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8006 } else { 8007 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8008 } 8009 8010 if (indices) *indices = idx; 8011 PetscFunctionReturn(PETSC_SUCCESS); 8012 } 8013 8014 /*@C 8015 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8016 8017 Not collective 8018 8019 Input Parameters: 8020 + dm - The `DM` 8021 . section - The `PetscSection` describing the points (a local section) 8022 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8023 . point - The point defining the closure 8024 - useClPerm - Use the closure point permutation if available 8025 8026 Output Parameters: 8027 + numIndices - The number of dof indices in the closure of point with the input sections 8028 . indices - The dof indices 8029 . outOffsets - Array to write the field offsets into, or `NULL` 8030 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8031 8032 Level: advanced 8033 8034 Notes: 8035 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 8036 8037 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8038 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8039 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8040 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8041 indices (with the above semantics) are implied. 8042 8043 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8044 `PetscSection`, `DMGetGlobalSection()` 8045 @*/ 8046 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8047 { 8048 PetscInt numRows = -1, numCols = -1; 8049 8050 PetscFunctionBeginHot; 8051 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8052 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8053 *numIndices = numRows; 8054 PetscFunctionReturn(PETSC_SUCCESS); 8055 } 8056 8057 /*@C 8058 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8059 8060 Not collective 8061 8062 Input Parameters: 8063 + dm - The `DM` 8064 . section - The `PetscSection` describing the points (a local section) 8065 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8066 . point - The point defining the closure 8067 - useClPerm - Use the closure point permutation if available 8068 8069 Output Parameters: 8070 + numIndices - The number of dof indices in the closure of point with the input sections 8071 . indices - The dof indices 8072 . outOffsets - Array to write the field offsets into, or `NULL` 8073 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8074 8075 Level: advanced 8076 8077 Notes: 8078 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8079 8080 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8081 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8082 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8083 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8084 indices (with the above semantics) are implied. 8085 8086 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8087 @*/ 8088 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8089 { 8090 PetscFunctionBegin; 8091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8092 PetscAssertPointer(indices, 7); 8093 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8094 PetscFunctionReturn(PETSC_SUCCESS); 8095 } 8096 8097 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8098 { 8099 DM_Plex *mesh = (DM_Plex *)dm->data; 8100 PetscInt *indices; 8101 PetscInt numIndices; 8102 const PetscScalar *valuesOrig = values; 8103 PetscErrorCode ierr; 8104 8105 PetscFunctionBegin; 8106 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8107 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8108 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8109 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8110 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8111 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8112 8113 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8114 8115 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8116 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8117 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8118 if (ierr) { 8119 PetscMPIInt rank; 8120 8121 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8122 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8123 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8124 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8125 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8126 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8127 } 8128 if (mesh->printFEM > 1) { 8129 PetscInt i; 8130 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8131 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8132 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8133 } 8134 8135 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8136 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8137 PetscFunctionReturn(PETSC_SUCCESS); 8138 } 8139 8140 /*@C 8141 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8142 8143 Not collective 8144 8145 Input Parameters: 8146 + dm - The `DM` 8147 . section - The section describing the layout in `v`, or `NULL` to use the default section 8148 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8149 . A - The matrix 8150 . point - The point in the `DM` 8151 . values - The array of values 8152 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8153 8154 Level: intermediate 8155 8156 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8157 @*/ 8158 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8159 { 8160 PetscFunctionBegin; 8161 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8162 PetscFunctionReturn(PETSC_SUCCESS); 8163 } 8164 8165 /*@C 8166 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8167 8168 Not collective 8169 8170 Input Parameters: 8171 + dmRow - The `DM` for the row fields 8172 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8173 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8174 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8175 . dmCol - The `DM` for the column fields 8176 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8177 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8178 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8179 . A - The matrix 8180 . point - The point in the `DM` 8181 . values - The array of values 8182 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8183 8184 Level: intermediate 8185 8186 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8187 @*/ 8188 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) 8189 { 8190 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8191 PetscInt *indicesRow, *indicesCol; 8192 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8193 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8194 8195 PetscErrorCode ierr; 8196 8197 PetscFunctionBegin; 8198 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8199 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8200 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8201 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8202 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8203 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8204 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8205 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8206 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8207 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8208 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8209 8210 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8211 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8212 valuesV1 = valuesV0; 8213 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8214 valuesV2 = valuesV1; 8215 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8216 8217 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8218 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8219 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8220 if (ierr) { 8221 PetscMPIInt rank; 8222 8223 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8224 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8225 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8226 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8227 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8228 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8229 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8230 } 8231 8232 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8233 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8234 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8235 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8236 PetscFunctionReturn(PETSC_SUCCESS); 8237 } 8238 8239 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8240 { 8241 DM_Plex *mesh = (DM_Plex *)dmf->data; 8242 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8243 PetscInt *cpoints = NULL; 8244 PetscInt *findices, *cindices; 8245 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8246 PetscInt foffsets[32], coffsets[32]; 8247 DMPolytopeType ct; 8248 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8249 PetscErrorCode ierr; 8250 8251 PetscFunctionBegin; 8252 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8253 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8254 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8255 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8256 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8257 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8258 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8259 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8260 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8261 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8262 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8263 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8264 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8265 PetscCall(PetscArrayzero(foffsets, 32)); 8266 PetscCall(PetscArrayzero(coffsets, 32)); 8267 /* Column indices */ 8268 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8269 maxFPoints = numCPoints; 8270 /* Compress out points not in the section */ 8271 /* TODO: Squeeze out points with 0 dof as well */ 8272 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8273 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8274 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8275 cpoints[q * 2] = cpoints[p]; 8276 cpoints[q * 2 + 1] = cpoints[p + 1]; 8277 ++q; 8278 } 8279 } 8280 numCPoints = q; 8281 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8282 PetscInt fdof; 8283 8284 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8285 if (!dof) continue; 8286 for (f = 0; f < numFields; ++f) { 8287 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8288 coffsets[f + 1] += fdof; 8289 } 8290 numCIndices += dof; 8291 } 8292 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8293 /* Row indices */ 8294 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8295 { 8296 DMPlexTransform tr; 8297 DMPolytopeType *rct; 8298 PetscInt *rsize, *rcone, *rornt, Nt; 8299 8300 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8301 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8302 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8303 numSubcells = rsize[Nt - 1]; 8304 PetscCall(DMPlexTransformDestroy(&tr)); 8305 } 8306 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8307 for (r = 0, q = 0; r < numSubcells; ++r) { 8308 /* TODO Map from coarse to fine cells */ 8309 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8310 /* Compress out points not in the section */ 8311 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8312 for (p = 0; p < numFPoints * 2; p += 2) { 8313 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8314 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8315 if (!dof) continue; 8316 for (s = 0; s < q; ++s) 8317 if (fpoints[p] == ftotpoints[s * 2]) break; 8318 if (s < q) continue; 8319 ftotpoints[q * 2] = fpoints[p]; 8320 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8321 ++q; 8322 } 8323 } 8324 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8325 } 8326 numFPoints = q; 8327 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8328 PetscInt fdof; 8329 8330 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8331 if (!dof) continue; 8332 for (f = 0; f < numFields; ++f) { 8333 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8334 foffsets[f + 1] += fdof; 8335 } 8336 numFIndices += dof; 8337 } 8338 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8339 8340 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8341 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8342 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8343 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8344 if (numFields) { 8345 const PetscInt **permsF[32] = {NULL}; 8346 const PetscInt **permsC[32] = {NULL}; 8347 8348 for (f = 0; f < numFields; f++) { 8349 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8350 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8351 } 8352 for (p = 0; p < numFPoints; p++) { 8353 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8354 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8355 } 8356 for (p = 0; p < numCPoints; p++) { 8357 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8358 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8359 } 8360 for (f = 0; f < numFields; f++) { 8361 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8362 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8363 } 8364 } else { 8365 const PetscInt **permsF = NULL; 8366 const PetscInt **permsC = NULL; 8367 8368 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8369 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8370 for (p = 0, off = 0; p < numFPoints; p++) { 8371 const PetscInt *perm = permsF ? permsF[p] : NULL; 8372 8373 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8374 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8375 } 8376 for (p = 0, off = 0; p < numCPoints; p++) { 8377 const PetscInt *perm = permsC ? permsC[p] : NULL; 8378 8379 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8380 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8381 } 8382 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8383 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8384 } 8385 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8386 /* TODO: flips */ 8387 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8388 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8389 if (ierr) { 8390 PetscMPIInt rank; 8391 8392 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8393 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8394 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8395 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8396 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8397 } 8398 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8399 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8400 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8401 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8402 PetscFunctionReturn(PETSC_SUCCESS); 8403 } 8404 8405 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8406 { 8407 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8408 PetscInt *cpoints = NULL; 8409 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8410 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8411 DMPolytopeType ct; 8412 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8413 8414 PetscFunctionBegin; 8415 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8416 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8417 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8418 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8419 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8420 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8421 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8422 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8423 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8424 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8425 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8426 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8427 /* Column indices */ 8428 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8429 maxFPoints = numCPoints; 8430 /* Compress out points not in the section */ 8431 /* TODO: Squeeze out points with 0 dof as well */ 8432 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8433 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8434 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8435 cpoints[q * 2] = cpoints[p]; 8436 cpoints[q * 2 + 1] = cpoints[p + 1]; 8437 ++q; 8438 } 8439 } 8440 numCPoints = q; 8441 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8442 PetscInt fdof; 8443 8444 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8445 if (!dof) continue; 8446 for (f = 0; f < numFields; ++f) { 8447 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8448 coffsets[f + 1] += fdof; 8449 } 8450 numCIndices += dof; 8451 } 8452 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8453 /* Row indices */ 8454 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8455 { 8456 DMPlexTransform tr; 8457 DMPolytopeType *rct; 8458 PetscInt *rsize, *rcone, *rornt, Nt; 8459 8460 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8461 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8462 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8463 numSubcells = rsize[Nt - 1]; 8464 PetscCall(DMPlexTransformDestroy(&tr)); 8465 } 8466 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8467 for (r = 0, q = 0; r < numSubcells; ++r) { 8468 /* TODO Map from coarse to fine cells */ 8469 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8470 /* Compress out points not in the section */ 8471 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8472 for (p = 0; p < numFPoints * 2; p += 2) { 8473 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8474 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8475 if (!dof) continue; 8476 for (s = 0; s < q; ++s) 8477 if (fpoints[p] == ftotpoints[s * 2]) break; 8478 if (s < q) continue; 8479 ftotpoints[q * 2] = fpoints[p]; 8480 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8481 ++q; 8482 } 8483 } 8484 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8485 } 8486 numFPoints = q; 8487 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8488 PetscInt fdof; 8489 8490 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8491 if (!dof) continue; 8492 for (f = 0; f < numFields; ++f) { 8493 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8494 foffsets[f + 1] += fdof; 8495 } 8496 numFIndices += dof; 8497 } 8498 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8499 8500 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8501 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8502 if (numFields) { 8503 const PetscInt **permsF[32] = {NULL}; 8504 const PetscInt **permsC[32] = {NULL}; 8505 8506 for (f = 0; f < numFields; f++) { 8507 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8508 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8509 } 8510 for (p = 0; p < numFPoints; p++) { 8511 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8512 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8513 } 8514 for (p = 0; p < numCPoints; p++) { 8515 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8516 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8517 } 8518 for (f = 0; f < numFields; f++) { 8519 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8520 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8521 } 8522 } else { 8523 const PetscInt **permsF = NULL; 8524 const PetscInt **permsC = NULL; 8525 8526 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8527 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8528 for (p = 0, off = 0; p < numFPoints; p++) { 8529 const PetscInt *perm = permsF ? permsF[p] : NULL; 8530 8531 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8532 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8533 } 8534 for (p = 0, off = 0; p < numCPoints; p++) { 8535 const PetscInt *perm = permsC ? permsC[p] : NULL; 8536 8537 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8538 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8539 } 8540 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8541 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8542 } 8543 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8544 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8545 PetscFunctionReturn(PETSC_SUCCESS); 8546 } 8547 8548 /*@ 8549 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8550 8551 Input Parameter: 8552 . dm - The `DMPLEX` object 8553 8554 Output Parameter: 8555 . cellHeight - The height of a cell 8556 8557 Level: developer 8558 8559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8560 @*/ 8561 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8562 { 8563 DM_Plex *mesh = (DM_Plex *)dm->data; 8564 8565 PetscFunctionBegin; 8566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8567 PetscAssertPointer(cellHeight, 2); 8568 *cellHeight = mesh->vtkCellHeight; 8569 PetscFunctionReturn(PETSC_SUCCESS); 8570 } 8571 8572 /*@ 8573 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8574 8575 Input Parameters: 8576 + dm - The `DMPLEX` object 8577 - cellHeight - The height of a cell 8578 8579 Level: developer 8580 8581 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8582 @*/ 8583 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8584 { 8585 DM_Plex *mesh = (DM_Plex *)dm->data; 8586 8587 PetscFunctionBegin; 8588 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8589 mesh->vtkCellHeight = cellHeight; 8590 PetscFunctionReturn(PETSC_SUCCESS); 8591 } 8592 8593 /*@ 8594 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8595 8596 Input Parameters: 8597 + dm - The `DMPLEX` object 8598 - ct - The `DMPolytopeType` of the cell 8599 8600 Output Parameters: 8601 + start - The first cell of this type, or `NULL` 8602 - end - The upper bound on this celltype, or `NULL` 8603 8604 Level: advanced 8605 8606 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8607 @*/ 8608 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8609 { 8610 DM_Plex *mesh = (DM_Plex *)dm->data; 8611 DMLabel label; 8612 PetscInt pStart, pEnd; 8613 8614 PetscFunctionBegin; 8615 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8616 if (start) { 8617 PetscAssertPointer(start, 3); 8618 *start = 0; 8619 } 8620 if (end) { 8621 PetscAssertPointer(end, 4); 8622 *end = 0; 8623 } 8624 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8625 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8626 if (mesh->tr) { 8627 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8628 } else { 8629 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8630 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8631 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8632 } 8633 PetscFunctionReturn(PETSC_SUCCESS); 8634 } 8635 8636 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8637 { 8638 PetscSection section, globalSection; 8639 PetscInt *numbers, p; 8640 8641 PetscFunctionBegin; 8642 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8643 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8644 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8645 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8646 PetscCall(PetscSectionSetUp(section)); 8647 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8648 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8649 for (p = pStart; p < pEnd; ++p) { 8650 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8651 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8652 else numbers[p - pStart] += shift; 8653 } 8654 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8655 if (globalSize) { 8656 PetscLayout layout; 8657 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8658 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8659 PetscCall(PetscLayoutDestroy(&layout)); 8660 } 8661 PetscCall(PetscSectionDestroy(§ion)); 8662 PetscCall(PetscSectionDestroy(&globalSection)); 8663 PetscFunctionReturn(PETSC_SUCCESS); 8664 } 8665 8666 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8667 { 8668 PetscInt cellHeight, cStart, cEnd; 8669 8670 PetscFunctionBegin; 8671 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8672 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8673 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8674 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8675 PetscFunctionReturn(PETSC_SUCCESS); 8676 } 8677 8678 /*@ 8679 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8680 8681 Input Parameter: 8682 . dm - The `DMPLEX` object 8683 8684 Output Parameter: 8685 . globalCellNumbers - Global cell numbers for all cells on this process 8686 8687 Level: developer 8688 8689 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8690 @*/ 8691 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8692 { 8693 DM_Plex *mesh = (DM_Plex *)dm->data; 8694 8695 PetscFunctionBegin; 8696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8697 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8698 *globalCellNumbers = mesh->globalCellNumbers; 8699 PetscFunctionReturn(PETSC_SUCCESS); 8700 } 8701 8702 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8703 { 8704 PetscInt vStart, vEnd; 8705 8706 PetscFunctionBegin; 8707 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8708 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8709 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8710 PetscFunctionReturn(PETSC_SUCCESS); 8711 } 8712 8713 /*@ 8714 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8715 8716 Input Parameter: 8717 . dm - The `DMPLEX` object 8718 8719 Output Parameter: 8720 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8721 8722 Level: developer 8723 8724 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8725 @*/ 8726 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8727 { 8728 DM_Plex *mesh = (DM_Plex *)dm->data; 8729 8730 PetscFunctionBegin; 8731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8732 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8733 *globalVertexNumbers = mesh->globalVertexNumbers; 8734 PetscFunctionReturn(PETSC_SUCCESS); 8735 } 8736 8737 /*@ 8738 DMPlexCreatePointNumbering - Create a global numbering for all points. 8739 8740 Collective 8741 8742 Input Parameter: 8743 . dm - The `DMPLEX` object 8744 8745 Output Parameter: 8746 . globalPointNumbers - Global numbers for all points on this process 8747 8748 Level: developer 8749 8750 Notes: 8751 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8752 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8753 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8754 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8755 8756 The partitioned mesh is 8757 ``` 8758 (2)--0--(3)--1--(4) (1)--0--(2) 8759 ``` 8760 and its global numbering is 8761 ``` 8762 (3)--0--(4)--1--(5)--2--(6) 8763 ``` 8764 Then the global numbering is provided as 8765 ``` 8766 [0] Number of indices in set 5 8767 [0] 0 0 8768 [0] 1 1 8769 [0] 2 3 8770 [0] 3 4 8771 [0] 4 -6 8772 [1] Number of indices in set 3 8773 [1] 0 2 8774 [1] 1 5 8775 [1] 2 6 8776 ``` 8777 8778 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8779 @*/ 8780 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8781 { 8782 IS nums[4]; 8783 PetscInt depths[4], gdepths[4], starts[4]; 8784 PetscInt depth, d, shift = 0; 8785 PetscBool empty = PETSC_FALSE; 8786 8787 PetscFunctionBegin; 8788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8789 PetscCall(DMPlexGetDepth(dm, &depth)); 8790 // For unstratified meshes use dim instead of depth 8791 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8792 // If any stratum is empty, we must mark all empty 8793 for (d = 0; d <= depth; ++d) { 8794 PetscInt end; 8795 8796 depths[d] = depth - d; 8797 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8798 if (!(starts[d] - end)) empty = PETSC_TRUE; 8799 } 8800 if (empty) 8801 for (d = 0; d <= depth; ++d) { 8802 depths[d] = -1; 8803 starts[d] = -1; 8804 } 8805 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8806 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8807 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]); 8808 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8809 for (d = 0; d <= depth; ++d) { 8810 PetscInt pStart, pEnd, gsize; 8811 8812 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8813 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8814 shift += gsize; 8815 } 8816 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8817 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8818 PetscFunctionReturn(PETSC_SUCCESS); 8819 } 8820 8821 /*@ 8822 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8823 8824 Input Parameter: 8825 . dm - The `DMPLEX` object 8826 8827 Output Parameter: 8828 . ranks - The rank field 8829 8830 Options Database Key: 8831 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8832 8833 Level: intermediate 8834 8835 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8836 @*/ 8837 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8838 { 8839 DM rdm; 8840 PetscFE fe; 8841 PetscScalar *r; 8842 PetscMPIInt rank; 8843 DMPolytopeType ct; 8844 PetscInt dim, cStart, cEnd, c; 8845 PetscBool simplex; 8846 8847 PetscFunctionBeginUser; 8848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8849 PetscAssertPointer(ranks, 2); 8850 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8851 PetscCall(DMClone(dm, &rdm)); 8852 PetscCall(DMGetDimension(rdm, &dim)); 8853 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8854 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8855 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8856 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8857 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8858 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8859 PetscCall(PetscFEDestroy(&fe)); 8860 PetscCall(DMCreateDS(rdm)); 8861 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8862 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8863 PetscCall(VecGetArray(*ranks, &r)); 8864 for (c = cStart; c < cEnd; ++c) { 8865 PetscScalar *lr; 8866 8867 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8868 if (lr) *lr = rank; 8869 } 8870 PetscCall(VecRestoreArray(*ranks, &r)); 8871 PetscCall(DMDestroy(&rdm)); 8872 PetscFunctionReturn(PETSC_SUCCESS); 8873 } 8874 8875 /*@ 8876 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8877 8878 Input Parameters: 8879 + dm - The `DMPLEX` 8880 - label - The `DMLabel` 8881 8882 Output Parameter: 8883 . val - The label value field 8884 8885 Options Database Key: 8886 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8887 8888 Level: intermediate 8889 8890 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8891 @*/ 8892 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8893 { 8894 DM rdm, plex; 8895 Vec lval; 8896 PetscSection section; 8897 PetscFE fe; 8898 PetscScalar *v; 8899 PetscInt dim, pStart, pEnd, p, cStart; 8900 DMPolytopeType ct; 8901 char name[PETSC_MAX_PATH_LEN]; 8902 const char *lname, *prefix; 8903 8904 PetscFunctionBeginUser; 8905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8906 PetscAssertPointer(label, 2); 8907 PetscAssertPointer(val, 3); 8908 PetscCall(DMClone(dm, &rdm)); 8909 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8910 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8911 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8912 PetscCall(DMDestroy(&plex)); 8913 PetscCall(DMGetDimension(rdm, &dim)); 8914 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8915 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8916 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8917 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8918 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8919 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8920 PetscCall(PetscFEDestroy(&fe)); 8921 PetscCall(DMCreateDS(rdm)); 8922 PetscCall(DMCreateGlobalVector(rdm, val)); 8923 PetscCall(DMCreateLocalVector(rdm, &lval)); 8924 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8925 PetscCall(DMGetLocalSection(rdm, §ion)); 8926 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8927 PetscCall(VecGetArray(lval, &v)); 8928 for (p = pStart; p < pEnd; ++p) { 8929 PetscInt cval, dof, off; 8930 8931 PetscCall(PetscSectionGetDof(section, p, &dof)); 8932 if (!dof) continue; 8933 PetscCall(DMLabelGetValue(label, p, &cval)); 8934 PetscCall(PetscSectionGetOffset(section, p, &off)); 8935 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8936 } 8937 PetscCall(VecRestoreArray(lval, &v)); 8938 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8939 PetscCall(VecDestroy(&lval)); 8940 PetscCall(DMDestroy(&rdm)); 8941 PetscFunctionReturn(PETSC_SUCCESS); 8942 } 8943 8944 /*@ 8945 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8946 8947 Input Parameter: 8948 . dm - The `DMPLEX` object 8949 8950 Level: developer 8951 8952 Notes: 8953 This is a useful diagnostic when creating meshes programmatically. 8954 8955 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8956 8957 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8958 @*/ 8959 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8960 { 8961 PetscSection coneSection, supportSection; 8962 const PetscInt *cone, *support; 8963 PetscInt coneSize, c, supportSize, s; 8964 PetscInt pStart, pEnd, p, pp, csize, ssize; 8965 PetscBool storagecheck = PETSC_TRUE; 8966 8967 PetscFunctionBegin; 8968 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8969 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8970 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8971 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8972 /* Check that point p is found in the support of its cone points, and vice versa */ 8973 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8974 for (p = pStart; p < pEnd; ++p) { 8975 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8976 PetscCall(DMPlexGetCone(dm, p, &cone)); 8977 for (c = 0; c < coneSize; ++c) { 8978 PetscBool dup = PETSC_FALSE; 8979 PetscInt d; 8980 for (d = c - 1; d >= 0; --d) { 8981 if (cone[c] == cone[d]) { 8982 dup = PETSC_TRUE; 8983 break; 8984 } 8985 } 8986 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8987 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8988 for (s = 0; s < supportSize; ++s) { 8989 if (support[s] == p) break; 8990 } 8991 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8992 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8993 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8994 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8995 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8996 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8997 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8998 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]); 8999 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9000 } 9001 } 9002 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9003 if (p != pp) { 9004 storagecheck = PETSC_FALSE; 9005 continue; 9006 } 9007 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9008 PetscCall(DMPlexGetSupport(dm, p, &support)); 9009 for (s = 0; s < supportSize; ++s) { 9010 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9011 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9012 for (c = 0; c < coneSize; ++c) { 9013 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9014 if (cone[c] != pp) { 9015 c = 0; 9016 break; 9017 } 9018 if (cone[c] == p) break; 9019 } 9020 if (c >= coneSize) { 9021 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9022 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9023 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9024 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9025 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9026 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9027 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9028 } 9029 } 9030 } 9031 if (storagecheck) { 9032 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9033 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9034 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9035 } 9036 PetscFunctionReturn(PETSC_SUCCESS); 9037 } 9038 9039 /* 9040 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. 9041 */ 9042 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9043 { 9044 DMPolytopeType cct; 9045 PetscInt ptpoints[4]; 9046 const PetscInt *cone, *ccone, *ptcone; 9047 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9048 9049 PetscFunctionBegin; 9050 *unsplit = 0; 9051 switch (ct) { 9052 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9053 ptpoints[npt++] = c; 9054 break; 9055 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9056 PetscCall(DMPlexGetCone(dm, c, &cone)); 9057 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9058 for (cp = 0; cp < coneSize; ++cp) { 9059 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9060 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9061 } 9062 break; 9063 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9064 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9065 PetscCall(DMPlexGetCone(dm, c, &cone)); 9066 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9067 for (cp = 0; cp < coneSize; ++cp) { 9068 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9069 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9070 for (ccp = 0; ccp < cconeSize; ++ccp) { 9071 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9072 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9073 PetscInt p; 9074 for (p = 0; p < npt; ++p) 9075 if (ptpoints[p] == ccone[ccp]) break; 9076 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9077 } 9078 } 9079 } 9080 break; 9081 default: 9082 break; 9083 } 9084 for (pt = 0; pt < npt; ++pt) { 9085 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9086 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9087 } 9088 PetscFunctionReturn(PETSC_SUCCESS); 9089 } 9090 9091 /*@ 9092 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9093 9094 Input Parameters: 9095 + dm - The `DMPLEX` object 9096 - cellHeight - Normally 0 9097 9098 Level: developer 9099 9100 Notes: 9101 This is a useful diagnostic when creating meshes programmatically. 9102 Currently applicable only to homogeneous simplex or tensor meshes. 9103 9104 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9105 9106 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9107 @*/ 9108 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9109 { 9110 DMPlexInterpolatedFlag interp; 9111 DMPolytopeType ct; 9112 PetscInt vStart, vEnd, cStart, cEnd, c; 9113 9114 PetscFunctionBegin; 9115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9116 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9117 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9118 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9119 for (c = cStart; c < cEnd; ++c) { 9120 PetscInt *closure = NULL; 9121 PetscInt coneSize, closureSize, cl, Nv = 0; 9122 9123 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9124 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9125 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9126 if (interp == DMPLEX_INTERPOLATED_FULL) { 9127 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9128 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)); 9129 } 9130 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9131 for (cl = 0; cl < closureSize * 2; cl += 2) { 9132 const PetscInt p = closure[cl]; 9133 if ((p >= vStart) && (p < vEnd)) ++Nv; 9134 } 9135 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9136 /* Special Case: Tensor faces with identified vertices */ 9137 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9138 PetscInt unsplit; 9139 9140 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9141 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9142 } 9143 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)); 9144 } 9145 PetscFunctionReturn(PETSC_SUCCESS); 9146 } 9147 9148 /*@ 9149 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9150 9151 Collective 9152 9153 Input Parameters: 9154 + dm - The `DMPLEX` object 9155 - cellHeight - Normally 0 9156 9157 Level: developer 9158 9159 Notes: 9160 This is a useful diagnostic when creating meshes programmatically. 9161 This routine is only relevant for meshes that are fully interpolated across all ranks. 9162 It will error out if a partially interpolated mesh is given on some rank. 9163 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9164 9165 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9166 9167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9168 @*/ 9169 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9170 { 9171 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9172 DMPlexInterpolatedFlag interpEnum; 9173 9174 PetscFunctionBegin; 9175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9176 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9177 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9178 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9179 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9180 PetscFunctionReturn(PETSC_SUCCESS); 9181 } 9182 9183 PetscCall(DMGetDimension(dm, &dim)); 9184 PetscCall(DMPlexGetDepth(dm, &depth)); 9185 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9186 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9187 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9188 for (c = cStart; c < cEnd; ++c) { 9189 const PetscInt *cone, *ornt, *faceSizes, *faces; 9190 const DMPolytopeType *faceTypes; 9191 DMPolytopeType ct; 9192 PetscInt numFaces, coneSize, f; 9193 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9194 9195 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9196 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9197 if (unsplit) continue; 9198 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9199 PetscCall(DMPlexGetCone(dm, c, &cone)); 9200 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9201 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9202 for (cl = 0; cl < closureSize * 2; cl += 2) { 9203 const PetscInt p = closure[cl]; 9204 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9205 } 9206 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9207 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); 9208 for (f = 0; f < numFaces; ++f) { 9209 DMPolytopeType fct; 9210 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9211 9212 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9213 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9214 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9215 const PetscInt p = fclosure[cl]; 9216 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9217 } 9218 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]); 9219 for (v = 0; v < fnumCorners; ++v) { 9220 if (fclosure[v] != faces[fOff + v]) { 9221 PetscInt v1; 9222 9223 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9224 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9225 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9226 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9227 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9228 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]); 9229 } 9230 } 9231 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9232 fOff += faceSizes[f]; 9233 } 9234 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9235 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9236 } 9237 } 9238 PetscFunctionReturn(PETSC_SUCCESS); 9239 } 9240 9241 /*@ 9242 DMPlexCheckGeometry - Check the geometry of mesh cells 9243 9244 Input Parameter: 9245 . dm - The `DMPLEX` object 9246 9247 Level: developer 9248 9249 Notes: 9250 This is a useful diagnostic when creating meshes programmatically. 9251 9252 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9253 9254 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9255 @*/ 9256 PetscErrorCode DMPlexCheckGeometry(DM dm) 9257 { 9258 Vec coordinates; 9259 PetscReal detJ, J[9], refVol = 1.0; 9260 PetscReal vol; 9261 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9262 9263 PetscFunctionBegin; 9264 PetscCall(DMGetDimension(dm, &dim)); 9265 PetscCall(DMGetCoordinateDim(dm, &dE)); 9266 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9267 PetscCall(DMPlexGetDepth(dm, &depth)); 9268 for (d = 0; d < dim; ++d) refVol *= 2.0; 9269 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9270 /* Make sure local coordinates are created, because that step is collective */ 9271 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9272 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9273 for (c = cStart; c < cEnd; ++c) { 9274 DMPolytopeType ct; 9275 PetscInt unsplit; 9276 PetscBool ignoreZeroVol = PETSC_FALSE; 9277 9278 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9279 switch (ct) { 9280 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9281 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9282 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9283 ignoreZeroVol = PETSC_TRUE; 9284 break; 9285 default: 9286 break; 9287 } 9288 switch (ct) { 9289 case DM_POLYTOPE_TRI_PRISM: 9290 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9291 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9292 case DM_POLYTOPE_PYRAMID: 9293 continue; 9294 default: 9295 break; 9296 } 9297 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9298 if (unsplit) continue; 9299 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9300 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); 9301 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9302 /* This should work with periodicity since DG coordinates should be used */ 9303 if (depth > 1) { 9304 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9305 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); 9306 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9307 } 9308 } 9309 PetscFunctionReturn(PETSC_SUCCESS); 9310 } 9311 9312 /*@ 9313 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9314 9315 Collective 9316 9317 Input Parameters: 9318 + dm - The `DMPLEX` object 9319 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9320 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9321 9322 Level: developer 9323 9324 Notes: 9325 This is mainly intended for debugging/testing purposes. 9326 9327 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9328 9329 Extra roots can come from periodic cuts, where additional points appear on the boundary 9330 9331 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9332 @*/ 9333 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9334 { 9335 PetscInt l, nleaves, nroots, overlap; 9336 const PetscInt *locals; 9337 const PetscSFNode *remotes; 9338 PetscBool distributed; 9339 MPI_Comm comm; 9340 PetscMPIInt rank; 9341 9342 PetscFunctionBegin; 9343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9344 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9345 else pointSF = dm->sf; 9346 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9347 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9348 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9349 { 9350 PetscMPIInt mpiFlag; 9351 9352 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9353 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9354 } 9355 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9356 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9357 if (!distributed) { 9358 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); 9359 PetscFunctionReturn(PETSC_SUCCESS); 9360 } 9361 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); 9362 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9363 9364 /* Check SF graph is compatible with DMPlex chart */ 9365 { 9366 PetscInt pStart, pEnd, maxLeaf; 9367 9368 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9369 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9370 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9371 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9372 } 9373 9374 /* Check Point SF has no local points referenced */ 9375 for (l = 0; l < nleaves; l++) { 9376 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); 9377 } 9378 9379 /* Check there are no cells in interface */ 9380 if (!overlap) { 9381 PetscInt cellHeight, cStart, cEnd; 9382 9383 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9384 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9385 for (l = 0; l < nleaves; ++l) { 9386 const PetscInt point = locals ? locals[l] : l; 9387 9388 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9389 } 9390 } 9391 9392 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9393 { 9394 const PetscInt *rootdegree; 9395 9396 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9397 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9398 for (l = 0; l < nleaves; ++l) { 9399 const PetscInt point = locals ? locals[l] : l; 9400 const PetscInt *cone; 9401 PetscInt coneSize, c, idx; 9402 9403 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9404 PetscCall(DMPlexGetCone(dm, point, &cone)); 9405 for (c = 0; c < coneSize; ++c) { 9406 if (!rootdegree[cone[c]]) { 9407 if (locals) { 9408 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9409 } else { 9410 idx = (cone[c] < nleaves) ? cone[c] : -1; 9411 } 9412 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9413 } 9414 } 9415 } 9416 } 9417 PetscFunctionReturn(PETSC_SUCCESS); 9418 } 9419 9420 /*@ 9421 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9422 9423 Input Parameter: 9424 . dm - The `DMPLEX` object 9425 9426 Level: developer 9427 9428 Notes: 9429 This is a useful diagnostic when creating meshes programmatically. 9430 9431 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9432 9433 Currently does not include `DMPlexCheckCellShape()`. 9434 9435 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9436 @*/ 9437 PetscErrorCode DMPlexCheck(DM dm) 9438 { 9439 PetscInt cellHeight; 9440 9441 PetscFunctionBegin; 9442 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9443 PetscCall(DMPlexCheckSymmetry(dm)); 9444 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9445 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9446 PetscCall(DMPlexCheckGeometry(dm)); 9447 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9448 PetscCall(DMPlexCheckInterfaceCones(dm)); 9449 PetscFunctionReturn(PETSC_SUCCESS); 9450 } 9451 9452 typedef struct cell_stats { 9453 PetscReal min, max, sum, squaresum; 9454 PetscInt count; 9455 } cell_stats_t; 9456 9457 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9458 { 9459 PetscInt i, N = *len; 9460 9461 for (i = 0; i < N; i++) { 9462 cell_stats_t *A = (cell_stats_t *)a; 9463 cell_stats_t *B = (cell_stats_t *)b; 9464 9465 B->min = PetscMin(A->min, B->min); 9466 B->max = PetscMax(A->max, B->max); 9467 B->sum += A->sum; 9468 B->squaresum += A->squaresum; 9469 B->count += A->count; 9470 } 9471 } 9472 9473 /*@ 9474 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9475 9476 Collective 9477 9478 Input Parameters: 9479 + dm - The `DMPLEX` object 9480 . output - If true, statistics will be displayed on `stdout` 9481 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9482 9483 Level: developer 9484 9485 Notes: 9486 This is mainly intended for debugging/testing purposes. 9487 9488 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9489 9490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9491 @*/ 9492 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9493 { 9494 DM dmCoarse; 9495 cell_stats_t stats, globalStats; 9496 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9497 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9498 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9499 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9500 PetscMPIInt rank, size; 9501 9502 PetscFunctionBegin; 9503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9504 stats.min = PETSC_MAX_REAL; 9505 stats.max = PETSC_MIN_REAL; 9506 stats.sum = stats.squaresum = 0.; 9507 stats.count = 0; 9508 9509 PetscCallMPI(MPI_Comm_size(comm, &size)); 9510 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9511 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9512 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9513 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9514 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9515 for (c = cStart; c < cEnd; c++) { 9516 PetscInt i; 9517 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9518 9519 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9520 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9521 for (i = 0; i < PetscSqr(cdim); ++i) { 9522 frobJ += J[i] * J[i]; 9523 frobInvJ += invJ[i] * invJ[i]; 9524 } 9525 cond2 = frobJ * frobInvJ; 9526 cond = PetscSqrtReal(cond2); 9527 9528 stats.min = PetscMin(stats.min, cond); 9529 stats.max = PetscMax(stats.max, cond); 9530 stats.sum += cond; 9531 stats.squaresum += cond2; 9532 stats.count++; 9533 if (output && cond > limit) { 9534 PetscSection coordSection; 9535 Vec coordsLocal; 9536 PetscScalar *coords = NULL; 9537 PetscInt Nv, d, clSize, cl, *closure = NULL; 9538 9539 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9540 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9541 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9542 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9543 for (i = 0; i < Nv / cdim; ++i) { 9544 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9545 for (d = 0; d < cdim; ++d) { 9546 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9547 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9548 } 9549 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9550 } 9551 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9552 for (cl = 0; cl < clSize * 2; cl += 2) { 9553 const PetscInt edge = closure[cl]; 9554 9555 if ((edge >= eStart) && (edge < eEnd)) { 9556 PetscReal len; 9557 9558 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9559 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9560 } 9561 } 9562 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9563 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9564 } 9565 } 9566 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9567 9568 if (size > 1) { 9569 PetscMPIInt blockLengths[2] = {4, 1}; 9570 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9571 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9572 MPI_Op statReduce; 9573 9574 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9575 PetscCallMPI(MPI_Type_commit(&statType)); 9576 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9577 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9578 PetscCallMPI(MPI_Op_free(&statReduce)); 9579 PetscCallMPI(MPI_Type_free(&statType)); 9580 } else { 9581 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9582 } 9583 if (rank == 0) { 9584 count = globalStats.count; 9585 min = globalStats.min; 9586 max = globalStats.max; 9587 mean = globalStats.sum / globalStats.count; 9588 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9589 } 9590 9591 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)); 9592 PetscCall(PetscFree2(J, invJ)); 9593 9594 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9595 if (dmCoarse) { 9596 PetscBool isplex; 9597 9598 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9599 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9600 } 9601 PetscFunctionReturn(PETSC_SUCCESS); 9602 } 9603 9604 /*@ 9605 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9606 orthogonal quality below given tolerance. 9607 9608 Collective 9609 9610 Input Parameters: 9611 + dm - The `DMPLEX` object 9612 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9613 - atol - [0, 1] Absolute tolerance for tagging cells. 9614 9615 Output Parameters: 9616 + OrthQual - `Vec` containing orthogonal quality per cell 9617 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9618 9619 Options Database Keys: 9620 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9621 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9622 9623 Level: intermediate 9624 9625 Notes: 9626 Orthogonal quality is given by the following formula\: 9627 9628 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9629 9630 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 9631 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9632 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9633 calculating the cosine of the angle between these vectors. 9634 9635 Orthogonal quality ranges from 1 (best) to 0 (worst). 9636 9637 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9638 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9639 9640 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9641 9642 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9643 @*/ 9644 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9645 { 9646 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9647 PetscInt *idx; 9648 PetscScalar *oqVals; 9649 const PetscScalar *cellGeomArr, *faceGeomArr; 9650 PetscReal *ci, *fi, *Ai; 9651 MPI_Comm comm; 9652 Vec cellgeom, facegeom; 9653 DM dmFace, dmCell; 9654 IS glob; 9655 ISLocalToGlobalMapping ltog; 9656 PetscViewer vwr; 9657 9658 PetscFunctionBegin; 9659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9660 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9661 PetscAssertPointer(OrthQual, 4); 9662 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9663 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9664 PetscCall(DMGetDimension(dm, &nc)); 9665 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9666 { 9667 DMPlexInterpolatedFlag interpFlag; 9668 9669 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9670 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9671 PetscMPIInt rank; 9672 9673 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9674 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9675 } 9676 } 9677 if (OrthQualLabel) { 9678 PetscAssertPointer(OrthQualLabel, 5); 9679 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9680 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9681 } else { 9682 *OrthQualLabel = NULL; 9683 } 9684 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9685 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9686 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9687 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9688 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9689 PetscCall(VecCreate(comm, OrthQual)); 9690 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9691 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9692 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9693 PetscCall(VecSetUp(*OrthQual)); 9694 PetscCall(ISDestroy(&glob)); 9695 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9696 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9697 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9698 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9699 PetscCall(VecGetDM(cellgeom, &dmCell)); 9700 PetscCall(VecGetDM(facegeom, &dmFace)); 9701 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9702 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9703 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9704 PetscInt cellarr[2], *adj = NULL; 9705 PetscScalar *cArr, *fArr; 9706 PetscReal minvalc = 1.0, minvalf = 1.0; 9707 PetscFVCellGeom *cg; 9708 9709 idx[cellIter] = cell - cStart; 9710 cellarr[0] = cell; 9711 /* Make indexing into cellGeom easier */ 9712 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9713 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9714 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9715 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9716 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9717 PetscInt i; 9718 const PetscInt neigh = adj[cellneigh]; 9719 PetscReal normci = 0, normfi = 0, normai = 0; 9720 PetscFVCellGeom *cgneigh; 9721 PetscFVFaceGeom *fg; 9722 9723 /* Don't count ourselves in the neighbor list */ 9724 if (neigh == cell) continue; 9725 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9726 cellarr[1] = neigh; 9727 { 9728 PetscInt numcovpts; 9729 const PetscInt *covpts; 9730 9731 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9732 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9733 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9734 } 9735 9736 /* Compute c_i, f_i and their norms */ 9737 for (i = 0; i < nc; i++) { 9738 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9739 fi[i] = fg->centroid[i] - cg->centroid[i]; 9740 Ai[i] = fg->normal[i]; 9741 normci += PetscPowReal(ci[i], 2); 9742 normfi += PetscPowReal(fi[i], 2); 9743 normai += PetscPowReal(Ai[i], 2); 9744 } 9745 normci = PetscSqrtReal(normci); 9746 normfi = PetscSqrtReal(normfi); 9747 normai = PetscSqrtReal(normai); 9748 9749 /* Normalize and compute for each face-cell-normal pair */ 9750 for (i = 0; i < nc; i++) { 9751 ci[i] = ci[i] / normci; 9752 fi[i] = fi[i] / normfi; 9753 Ai[i] = Ai[i] / normai; 9754 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9755 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9756 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9757 } 9758 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9759 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9760 } 9761 PetscCall(PetscFree(adj)); 9762 PetscCall(PetscFree2(cArr, fArr)); 9763 /* Defer to cell if they're equal */ 9764 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9765 if (OrthQualLabel) { 9766 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9767 } 9768 } 9769 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9770 PetscCall(VecAssemblyBegin(*OrthQual)); 9771 PetscCall(VecAssemblyEnd(*OrthQual)); 9772 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9773 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9774 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9775 if (OrthQualLabel) { 9776 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9777 } 9778 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9779 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9780 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9781 PetscFunctionReturn(PETSC_SUCCESS); 9782 } 9783 9784 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9785 * interpolator construction */ 9786 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9787 { 9788 PetscSection section, newSection, gsection; 9789 PetscSF sf; 9790 PetscBool hasConstraints, ghasConstraints; 9791 9792 PetscFunctionBegin; 9793 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9794 PetscAssertPointer(odm, 2); 9795 PetscCall(DMGetLocalSection(dm, §ion)); 9796 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9797 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9798 if (!ghasConstraints) { 9799 PetscCall(PetscObjectReference((PetscObject)dm)); 9800 *odm = dm; 9801 PetscFunctionReturn(PETSC_SUCCESS); 9802 } 9803 PetscCall(DMClone(dm, odm)); 9804 PetscCall(DMCopyFields(dm, *odm)); 9805 PetscCall(DMGetLocalSection(*odm, &newSection)); 9806 PetscCall(DMGetPointSF(*odm, &sf)); 9807 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9808 PetscCall(DMSetGlobalSection(*odm, gsection)); 9809 PetscCall(PetscSectionDestroy(&gsection)); 9810 PetscFunctionReturn(PETSC_SUCCESS); 9811 } 9812 9813 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9814 { 9815 DM dmco, dmfo; 9816 Mat interpo; 9817 Vec rscale; 9818 Vec cglobalo, clocal; 9819 Vec fglobal, fglobalo, flocal; 9820 PetscBool regular; 9821 9822 PetscFunctionBegin; 9823 PetscCall(DMGetFullDM(dmc, &dmco)); 9824 PetscCall(DMGetFullDM(dmf, &dmfo)); 9825 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9826 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9827 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9828 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9829 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9830 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9831 PetscCall(VecSet(cglobalo, 0.)); 9832 PetscCall(VecSet(clocal, 0.)); 9833 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9834 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9835 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9836 PetscCall(VecSet(fglobal, 0.)); 9837 PetscCall(VecSet(fglobalo, 0.)); 9838 PetscCall(VecSet(flocal, 0.)); 9839 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9840 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9841 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9842 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9843 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9844 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9845 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9846 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9847 *shift = fglobal; 9848 PetscCall(VecDestroy(&flocal)); 9849 PetscCall(VecDestroy(&fglobalo)); 9850 PetscCall(VecDestroy(&clocal)); 9851 PetscCall(VecDestroy(&cglobalo)); 9852 PetscCall(VecDestroy(&rscale)); 9853 PetscCall(MatDestroy(&interpo)); 9854 PetscCall(DMDestroy(&dmfo)); 9855 PetscCall(DMDestroy(&dmco)); 9856 PetscFunctionReturn(PETSC_SUCCESS); 9857 } 9858 9859 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9860 { 9861 PetscObject shifto; 9862 Vec shift; 9863 9864 PetscFunctionBegin; 9865 if (!interp) { 9866 Vec rscale; 9867 9868 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9869 PetscCall(VecDestroy(&rscale)); 9870 } else { 9871 PetscCall(PetscObjectReference((PetscObject)interp)); 9872 } 9873 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9874 if (!shifto) { 9875 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9876 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9877 shifto = (PetscObject)shift; 9878 PetscCall(VecDestroy(&shift)); 9879 } 9880 shift = (Vec)shifto; 9881 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9882 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9883 PetscCall(MatDestroy(&interp)); 9884 PetscFunctionReturn(PETSC_SUCCESS); 9885 } 9886 9887 /* Pointwise interpolation 9888 Just code FEM for now 9889 u^f = I u^c 9890 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9891 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9892 I_{ij} = psi^f_i phi^c_j 9893 */ 9894 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9895 { 9896 PetscSection gsc, gsf; 9897 PetscInt m, n; 9898 void *ctx; 9899 DM cdm; 9900 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9901 9902 PetscFunctionBegin; 9903 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9904 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9905 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9906 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9907 9908 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9909 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9910 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9911 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9912 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9913 9914 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9915 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9916 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9917 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9918 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9919 if (scaling) { 9920 /* Use naive scaling */ 9921 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9922 } 9923 PetscFunctionReturn(PETSC_SUCCESS); 9924 } 9925 9926 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9927 { 9928 VecScatter ctx; 9929 9930 PetscFunctionBegin; 9931 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9932 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9933 PetscCall(VecScatterDestroy(&ctx)); 9934 PetscFunctionReturn(PETSC_SUCCESS); 9935 } 9936 9937 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[]) 9938 { 9939 const PetscInt Nc = uOff[1] - uOff[0]; 9940 PetscInt c; 9941 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9942 } 9943 9944 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9945 { 9946 DM dmc; 9947 PetscDS ds; 9948 Vec ones, locmass; 9949 IS cellIS; 9950 PetscFormKey key; 9951 PetscInt depth; 9952 9953 PetscFunctionBegin; 9954 PetscCall(DMClone(dm, &dmc)); 9955 PetscCall(DMCopyDisc(dm, dmc)); 9956 PetscCall(DMGetDS(dmc, &ds)); 9957 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9958 PetscCall(DMCreateGlobalVector(dmc, mass)); 9959 PetscCall(DMGetLocalVector(dmc, &ones)); 9960 PetscCall(DMGetLocalVector(dmc, &locmass)); 9961 PetscCall(DMPlexGetDepth(dmc, &depth)); 9962 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9963 PetscCall(VecSet(locmass, 0.0)); 9964 PetscCall(VecSet(ones, 1.0)); 9965 key.label = NULL; 9966 key.value = 0; 9967 key.field = 0; 9968 key.part = 0; 9969 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9970 PetscCall(ISDestroy(&cellIS)); 9971 PetscCall(VecSet(*mass, 0.0)); 9972 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9973 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9974 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9975 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9976 PetscCall(DMDestroy(&dmc)); 9977 PetscFunctionReturn(PETSC_SUCCESS); 9978 } 9979 9980 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9981 { 9982 PetscSection gsc, gsf; 9983 PetscInt m, n; 9984 void *ctx; 9985 DM cdm; 9986 PetscBool regular; 9987 9988 PetscFunctionBegin; 9989 if (dmFine == dmCoarse) { 9990 DM dmc; 9991 PetscDS ds; 9992 PetscWeakForm wf; 9993 Vec u; 9994 IS cellIS; 9995 PetscFormKey key; 9996 PetscInt depth; 9997 9998 PetscCall(DMClone(dmFine, &dmc)); 9999 PetscCall(DMCopyDisc(dmFine, dmc)); 10000 PetscCall(DMGetDS(dmc, &ds)); 10001 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10002 PetscCall(PetscWeakFormClear(wf)); 10003 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10004 PetscCall(DMCreateMatrix(dmc, mass)); 10005 PetscCall(DMGetLocalVector(dmc, &u)); 10006 PetscCall(DMPlexGetDepth(dmc, &depth)); 10007 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10008 PetscCall(MatZeroEntries(*mass)); 10009 key.label = NULL; 10010 key.value = 0; 10011 key.field = 0; 10012 key.part = 0; 10013 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10014 PetscCall(ISDestroy(&cellIS)); 10015 PetscCall(DMRestoreLocalVector(dmc, &u)); 10016 PetscCall(DMDestroy(&dmc)); 10017 } else { 10018 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10019 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10020 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10021 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10022 10023 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10024 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10025 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10026 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10027 10028 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10029 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10030 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10031 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10032 } 10033 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10034 PetscFunctionReturn(PETSC_SUCCESS); 10035 } 10036 10037 /*@ 10038 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10039 10040 Input Parameter: 10041 . dm - The `DMPLEX` object 10042 10043 Output Parameter: 10044 . regular - The flag 10045 10046 Level: intermediate 10047 10048 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10049 @*/ 10050 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10051 { 10052 PetscFunctionBegin; 10053 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10054 PetscAssertPointer(regular, 2); 10055 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10056 PetscFunctionReturn(PETSC_SUCCESS); 10057 } 10058 10059 /*@ 10060 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10061 10062 Input Parameters: 10063 + dm - The `DMPLEX` object 10064 - regular - The flag 10065 10066 Level: intermediate 10067 10068 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10069 @*/ 10070 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10071 { 10072 PetscFunctionBegin; 10073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10074 ((DM_Plex *)dm->data)->regularRefinement = regular; 10075 PetscFunctionReturn(PETSC_SUCCESS); 10076 } 10077 10078 /*@ 10079 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10080 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10081 10082 Not Collective 10083 10084 Input Parameter: 10085 . dm - The `DMPLEX` object 10086 10087 Output Parameters: 10088 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10089 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10090 10091 Level: intermediate 10092 10093 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10094 @*/ 10095 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10096 { 10097 DM_Plex *plex = (DM_Plex *)dm->data; 10098 10099 PetscFunctionBegin; 10100 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10101 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10102 if (anchorSection) *anchorSection = plex->anchorSection; 10103 if (anchorIS) *anchorIS = plex->anchorIS; 10104 PetscFunctionReturn(PETSC_SUCCESS); 10105 } 10106 10107 /*@ 10108 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10109 10110 Collective 10111 10112 Input Parameters: 10113 + dm - The `DMPLEX` object 10114 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10115 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10116 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10117 10118 Level: intermediate 10119 10120 Notes: 10121 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10122 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10123 combination of other points' degrees of freedom. 10124 10125 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10126 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10127 10128 The reference counts of `anchorSection` and `anchorIS` are incremented. 10129 10130 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10131 @*/ 10132 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10133 { 10134 DM_Plex *plex = (DM_Plex *)dm->data; 10135 PetscMPIInt result; 10136 10137 PetscFunctionBegin; 10138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10139 if (anchorSection) { 10140 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10141 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10142 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10143 } 10144 if (anchorIS) { 10145 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10146 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10147 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10148 } 10149 10150 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10151 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10152 plex->anchorSection = anchorSection; 10153 10154 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10155 PetscCall(ISDestroy(&plex->anchorIS)); 10156 plex->anchorIS = anchorIS; 10157 10158 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10159 PetscInt size, a, pStart, pEnd; 10160 const PetscInt *anchors; 10161 10162 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10163 PetscCall(ISGetLocalSize(anchorIS, &size)); 10164 PetscCall(ISGetIndices(anchorIS, &anchors)); 10165 for (a = 0; a < size; a++) { 10166 PetscInt p; 10167 10168 p = anchors[a]; 10169 if (p >= pStart && p < pEnd) { 10170 PetscInt dof; 10171 10172 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10173 if (dof) { 10174 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10175 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10176 } 10177 } 10178 } 10179 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10180 } 10181 /* reset the generic constraints */ 10182 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10183 PetscFunctionReturn(PETSC_SUCCESS); 10184 } 10185 10186 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10187 { 10188 PetscSection anchorSection; 10189 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10190 10191 PetscFunctionBegin; 10192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10193 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10194 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10195 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10196 if (numFields) { 10197 PetscInt f; 10198 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10199 10200 for (f = 0; f < numFields; f++) { 10201 PetscInt numComp; 10202 10203 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10204 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10205 } 10206 } 10207 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10208 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10209 pStart = PetscMax(pStart, sStart); 10210 pEnd = PetscMin(pEnd, sEnd); 10211 pEnd = PetscMax(pStart, pEnd); 10212 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10213 for (p = pStart; p < pEnd; p++) { 10214 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10215 if (dof) { 10216 PetscCall(PetscSectionGetDof(section, p, &dof)); 10217 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10218 for (f = 0; f < numFields; f++) { 10219 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10220 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10221 } 10222 } 10223 } 10224 PetscCall(PetscSectionSetUp(*cSec)); 10225 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10226 PetscFunctionReturn(PETSC_SUCCESS); 10227 } 10228 10229 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10230 { 10231 PetscSection aSec; 10232 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10233 const PetscInt *anchors; 10234 PetscInt numFields, f; 10235 IS aIS; 10236 MatType mtype; 10237 PetscBool iscuda, iskokkos; 10238 10239 PetscFunctionBegin; 10240 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10241 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10242 PetscCall(PetscSectionGetStorageSize(section, &n)); 10243 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10244 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10245 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10246 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10247 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10248 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10249 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10250 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10251 else mtype = MATSEQAIJ; 10252 PetscCall(MatSetType(*cMat, mtype)); 10253 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10254 PetscCall(ISGetIndices(aIS, &anchors)); 10255 /* cSec will be a subset of aSec and section */ 10256 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10257 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10258 PetscCall(PetscMalloc1(m + 1, &i)); 10259 i[0] = 0; 10260 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10261 for (p = pStart; p < pEnd; p++) { 10262 PetscInt rDof, rOff, r; 10263 10264 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10265 if (!rDof) continue; 10266 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10267 if (numFields) { 10268 for (f = 0; f < numFields; f++) { 10269 annz = 0; 10270 for (r = 0; r < rDof; r++) { 10271 a = anchors[rOff + r]; 10272 if (a < sStart || a >= sEnd) continue; 10273 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10274 annz += aDof; 10275 } 10276 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10277 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10278 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10279 } 10280 } else { 10281 annz = 0; 10282 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10283 for (q = 0; q < dof; q++) { 10284 a = anchors[rOff + q]; 10285 if (a < sStart || a >= sEnd) continue; 10286 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10287 annz += aDof; 10288 } 10289 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10290 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10291 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10292 } 10293 } 10294 nnz = i[m]; 10295 PetscCall(PetscMalloc1(nnz, &j)); 10296 offset = 0; 10297 for (p = pStart; p < pEnd; p++) { 10298 if (numFields) { 10299 for (f = 0; f < numFields; f++) { 10300 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10301 for (q = 0; q < dof; q++) { 10302 PetscInt rDof, rOff, r; 10303 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10304 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10305 for (r = 0; r < rDof; r++) { 10306 PetscInt s; 10307 10308 a = anchors[rOff + r]; 10309 if (a < sStart || a >= sEnd) continue; 10310 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10311 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10312 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10313 } 10314 } 10315 } 10316 } else { 10317 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10318 for (q = 0; q < dof; q++) { 10319 PetscInt rDof, rOff, r; 10320 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10321 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10322 for (r = 0; r < rDof; r++) { 10323 PetscInt s; 10324 10325 a = anchors[rOff + r]; 10326 if (a < sStart || a >= sEnd) continue; 10327 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10328 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10329 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10330 } 10331 } 10332 } 10333 } 10334 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10335 PetscCall(PetscFree(i)); 10336 PetscCall(PetscFree(j)); 10337 PetscCall(ISRestoreIndices(aIS, &anchors)); 10338 PetscFunctionReturn(PETSC_SUCCESS); 10339 } 10340 10341 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10342 { 10343 DM_Plex *plex = (DM_Plex *)dm->data; 10344 PetscSection anchorSection, section, cSec; 10345 Mat cMat; 10346 10347 PetscFunctionBegin; 10348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10349 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10350 if (anchorSection) { 10351 PetscInt Nf; 10352 10353 PetscCall(DMGetLocalSection(dm, §ion)); 10354 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10355 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10356 PetscCall(DMGetNumFields(dm, &Nf)); 10357 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10358 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10359 PetscCall(PetscSectionDestroy(&cSec)); 10360 PetscCall(MatDestroy(&cMat)); 10361 } 10362 PetscFunctionReturn(PETSC_SUCCESS); 10363 } 10364 10365 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10366 { 10367 IS subis; 10368 PetscSection section, subsection; 10369 10370 PetscFunctionBegin; 10371 PetscCall(DMGetLocalSection(dm, §ion)); 10372 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10373 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10374 /* Create subdomain */ 10375 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10376 /* Create submodel */ 10377 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10378 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10379 PetscCall(DMSetLocalSection(*subdm, subsection)); 10380 PetscCall(PetscSectionDestroy(&subsection)); 10381 PetscCall(DMCopyDisc(dm, *subdm)); 10382 /* Create map from submodel to global model */ 10383 if (is) { 10384 PetscSection sectionGlobal, subsectionGlobal; 10385 IS spIS; 10386 const PetscInt *spmap; 10387 PetscInt *subIndices; 10388 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10389 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10390 10391 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10392 PetscCall(ISGetIndices(spIS, &spmap)); 10393 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10394 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10395 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10396 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10397 for (p = pStart; p < pEnd; ++p) { 10398 PetscInt gdof, pSubSize = 0; 10399 10400 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10401 if (gdof > 0) { 10402 for (f = 0; f < Nf; ++f) { 10403 PetscInt fdof, fcdof; 10404 10405 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10406 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10407 pSubSize += fdof - fcdof; 10408 } 10409 subSize += pSubSize; 10410 if (pSubSize) { 10411 if (bs < 0) { 10412 bs = pSubSize; 10413 } else if (bs != pSubSize) { 10414 /* Layout does not admit a pointwise block size */ 10415 bs = 1; 10416 } 10417 } 10418 } 10419 } 10420 /* Must have same blocksize on all procs (some might have no points) */ 10421 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10422 bsLocal[1] = bs; 10423 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10424 if (bsMinMax[0] != bsMinMax[1]) { 10425 bs = 1; 10426 } else { 10427 bs = bsMinMax[0]; 10428 } 10429 PetscCall(PetscMalloc1(subSize, &subIndices)); 10430 for (p = pStart; p < pEnd; ++p) { 10431 PetscInt gdof, goff; 10432 10433 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10434 if (gdof > 0) { 10435 const PetscInt point = spmap[p]; 10436 10437 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10438 for (f = 0; f < Nf; ++f) { 10439 PetscInt fdof, fcdof, fc, f2, poff = 0; 10440 10441 /* Can get rid of this loop by storing field information in the global section */ 10442 for (f2 = 0; f2 < f; ++f2) { 10443 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10444 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10445 poff += fdof - fcdof; 10446 } 10447 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10448 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10449 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10450 } 10451 } 10452 } 10453 PetscCall(ISRestoreIndices(spIS, &spmap)); 10454 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10455 if (bs > 1) { 10456 /* We need to check that the block size does not come from non-contiguous fields */ 10457 PetscInt i, j, set = 1; 10458 for (i = 0; i < subSize; i += bs) { 10459 for (j = 0; j < bs; ++j) { 10460 if (subIndices[i + j] != subIndices[i] + j) { 10461 set = 0; 10462 break; 10463 } 10464 } 10465 } 10466 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10467 } 10468 /* Attach nullspace */ 10469 for (f = 0; f < Nf; ++f) { 10470 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10471 if ((*subdm)->nullspaceConstructors[f]) break; 10472 } 10473 if (f < Nf) { 10474 MatNullSpace nullSpace; 10475 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10476 10477 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10478 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10479 } 10480 } 10481 PetscFunctionReturn(PETSC_SUCCESS); 10482 } 10483 10484 /*@ 10485 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10486 10487 Input Parameters: 10488 + dm - The `DM` 10489 - dummy - unused argument 10490 10491 Options Database Key: 10492 . -dm_plex_monitor_throughput - Activate the monitor 10493 10494 Level: developer 10495 10496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10497 @*/ 10498 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10499 { 10500 PetscLogHandler default_handler; 10501 10502 PetscFunctionBegin; 10503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10504 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10505 if (default_handler) { 10506 PetscLogEvent event; 10507 PetscEventPerfInfo eventInfo; 10508 PetscReal cellRate, flopRate; 10509 PetscInt cStart, cEnd, Nf, N; 10510 const char *name; 10511 10512 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10513 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10514 PetscCall(DMGetNumFields(dm, &Nf)); 10515 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10516 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10517 N = (cEnd - cStart) * Nf * eventInfo.count; 10518 flopRate = eventInfo.flops / eventInfo.time; 10519 cellRate = N / eventInfo.time; 10520 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))); 10521 } else { 10522 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."); 10523 } 10524 PetscFunctionReturn(PETSC_SUCCESS); 10525 } 10526