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; 2350 `NULL` if unneeded 2351 2352 Level: advanced 2353 2354 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2355 `PetscViewer`, `PetscSF` 2356 @*/ 2357 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2358 { 2359 PetscBool ishdf5; 2360 2361 PetscFunctionBegin; 2362 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2363 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2364 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2365 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2366 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2367 if (ishdf5) { 2368 #if defined(PETSC_HAVE_HDF5) 2369 PetscViewerFormat format; 2370 PetscCall(PetscViewerGetFormat(viewer, &format)); 2371 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2372 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2373 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2374 #else 2375 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2376 #endif 2377 } 2378 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2379 PetscFunctionReturn(PETSC_SUCCESS); 2380 } 2381 2382 /*@ 2383 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2384 2385 Collective 2386 2387 Input Parameters: 2388 + dm - The `DM` into which the coordinates are loaded 2389 . viewer - The `PetscViewer` for the saved coordinates 2390 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2391 2392 Level: advanced 2393 2394 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2395 `PetscSF`, `PetscViewer` 2396 @*/ 2397 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2398 { 2399 PetscBool ishdf5; 2400 2401 PetscFunctionBegin; 2402 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2403 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2404 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2405 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2406 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2407 if (ishdf5) { 2408 #if defined(PETSC_HAVE_HDF5) 2409 PetscViewerFormat format; 2410 PetscCall(PetscViewerGetFormat(viewer, &format)); 2411 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2412 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2413 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2414 #else 2415 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2416 #endif 2417 } 2418 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2419 PetscFunctionReturn(PETSC_SUCCESS); 2420 } 2421 2422 /*@ 2423 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2424 2425 Collective 2426 2427 Input Parameters: 2428 + dm - The `DM` into which the labels are loaded 2429 . viewer - The `PetscViewer` for the saved labels 2430 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2431 2432 Level: advanced 2433 2434 Note: 2435 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2436 2437 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2438 `PetscSF`, `PetscViewer` 2439 @*/ 2440 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2441 { 2442 PetscBool ishdf5; 2443 2444 PetscFunctionBegin; 2445 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2446 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2447 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2448 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2449 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2450 if (ishdf5) { 2451 #if defined(PETSC_HAVE_HDF5) 2452 PetscViewerFormat format; 2453 2454 PetscCall(PetscViewerGetFormat(viewer, &format)); 2455 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2456 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2457 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2458 #else 2459 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2460 #endif 2461 } 2462 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2463 PetscFunctionReturn(PETSC_SUCCESS); 2464 } 2465 2466 /*@ 2467 DMPlexSectionLoad - Loads section into a `DMPLEX` 2468 2469 Collective 2470 2471 Input Parameters: 2472 + dm - The `DM` that represents the topology 2473 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2474 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2475 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2476 2477 Output Parameters: 2478 + 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) 2479 - 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) 2480 2481 Level: advanced 2482 2483 Notes: 2484 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. 2485 2486 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. 2487 2488 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. 2489 2490 Example using 2 processes: 2491 .vb 2492 NX (number of points on dm): 4 2493 sectionA : the on-disk section 2494 vecA : a vector associated with sectionA 2495 sectionB : sectiondm's local section constructed in this function 2496 vecB (local) : a vector associated with sectiondm's local section 2497 vecB (global) : a vector associated with sectiondm's global section 2498 2499 rank 0 rank 1 2500 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2501 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2502 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2503 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2504 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2505 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2506 sectionB->atlasDof : 1 0 1 | 1 3 2507 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2508 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2509 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2510 .ve 2511 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2512 2513 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2514 @*/ 2515 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2516 { 2517 PetscBool ishdf5; 2518 2519 PetscFunctionBegin; 2520 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2521 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2522 if (!sectiondm) sectiondm = dm; 2523 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2524 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2525 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2526 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2527 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2528 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2529 if (ishdf5) { 2530 #if defined(PETSC_HAVE_HDF5) 2531 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2532 #else 2533 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2534 #endif 2535 } 2536 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2537 PetscFunctionReturn(PETSC_SUCCESS); 2538 } 2539 2540 /*@ 2541 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2542 2543 Collective 2544 2545 Input Parameters: 2546 + dm - The `DM` that represents the topology 2547 . viewer - The `PetscViewer` that represents the on-disk vector data 2548 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2549 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2550 - vec - The global vector to set values of 2551 2552 Level: advanced 2553 2554 Notes: 2555 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. 2556 2557 Calling sequence: 2558 .vb 2559 DMCreate(PETSC_COMM_WORLD, &dm); 2560 DMSetType(dm, DMPLEX); 2561 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2562 DMPlexTopologyLoad(dm, viewer, &sfX); 2563 DMClone(dm, §iondm); 2564 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2565 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2566 DMGetGlobalVector(sectiondm, &vec); 2567 PetscObjectSetName((PetscObject)vec, "vec_name"); 2568 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2569 DMRestoreGlobalVector(sectiondm, &vec); 2570 PetscSFDestroy(&gsf); 2571 PetscSFDestroy(&sfX); 2572 DMDestroy(§iondm); 2573 DMDestroy(&dm); 2574 .ve 2575 2576 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2577 `PetscSF`, `PetscViewer` 2578 @*/ 2579 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2580 { 2581 PetscBool ishdf5; 2582 2583 PetscFunctionBegin; 2584 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2585 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2586 if (!sectiondm) sectiondm = dm; 2587 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2588 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2589 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2590 /* Check consistency */ 2591 { 2592 PetscSection section; 2593 PetscBool includesConstraints; 2594 PetscInt m, m1; 2595 2596 PetscCall(VecGetLocalSize(vec, &m1)); 2597 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2598 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2599 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2600 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2601 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2602 } 2603 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2604 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2605 if (ishdf5) { 2606 #if defined(PETSC_HAVE_HDF5) 2607 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2608 #else 2609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2610 #endif 2611 } 2612 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2613 PetscFunctionReturn(PETSC_SUCCESS); 2614 } 2615 2616 /*@ 2617 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2618 2619 Collective 2620 2621 Input Parameters: 2622 + dm - The `DM` that represents the topology 2623 . viewer - The `PetscViewer` that represents the on-disk vector data 2624 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2625 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2626 - vec - The local vector to set values of 2627 2628 Level: advanced 2629 2630 Notes: 2631 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. 2632 2633 Calling sequence: 2634 .vb 2635 DMCreate(PETSC_COMM_WORLD, &dm); 2636 DMSetType(dm, DMPLEX); 2637 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2638 DMPlexTopologyLoad(dm, viewer, &sfX); 2639 DMClone(dm, §iondm); 2640 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2641 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2642 DMGetLocalVector(sectiondm, &vec); 2643 PetscObjectSetName((PetscObject)vec, "vec_name"); 2644 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2645 DMRestoreLocalVector(sectiondm, &vec); 2646 PetscSFDestroy(&lsf); 2647 PetscSFDestroy(&sfX); 2648 DMDestroy(§iondm); 2649 DMDestroy(&dm); 2650 .ve 2651 2652 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2653 `PetscSF`, `PetscViewer` 2654 @*/ 2655 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2656 { 2657 PetscBool ishdf5; 2658 2659 PetscFunctionBegin; 2660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2661 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2662 if (!sectiondm) sectiondm = dm; 2663 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2664 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2665 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2666 /* Check consistency */ 2667 { 2668 PetscSection section; 2669 PetscBool includesConstraints; 2670 PetscInt m, m1; 2671 2672 PetscCall(VecGetLocalSize(vec, &m1)); 2673 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2674 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2675 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2676 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2677 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2678 } 2679 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2680 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2681 if (ishdf5) { 2682 #if defined(PETSC_HAVE_HDF5) 2683 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2684 #else 2685 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2686 #endif 2687 } 2688 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2689 PetscFunctionReturn(PETSC_SUCCESS); 2690 } 2691 2692 PetscErrorCode DMDestroy_Plex(DM dm) 2693 { 2694 DM_Plex *mesh = (DM_Plex *)dm->data; 2695 2696 PetscFunctionBegin; 2697 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2698 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2699 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2700 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2701 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2702 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2703 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2704 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2705 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2706 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2707 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2708 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2709 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2710 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2711 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2712 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2713 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2714 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2715 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2716 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2717 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2718 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2719 PetscCall(PetscFree(mesh->cones)); 2720 PetscCall(PetscFree(mesh->coneOrientations)); 2721 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2722 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2723 PetscCall(PetscFree(mesh->supports)); 2724 PetscCall(PetscFree(mesh->cellTypes)); 2725 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2726 PetscCall(PetscFree(mesh->tetgenOpts)); 2727 PetscCall(PetscFree(mesh->triangleOpts)); 2728 PetscCall(PetscFree(mesh->transformType)); 2729 PetscCall(PetscFree(mesh->distributionName)); 2730 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2731 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2732 PetscCall(ISDestroy(&mesh->subpointIS)); 2733 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2734 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2735 if (mesh->periodic.face_sfs) { 2736 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2737 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2738 } 2739 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2740 if (mesh->periodic.periodic_points) { 2741 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2742 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2743 } 2744 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2745 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2746 PetscCall(ISDestroy(&mesh->anchorIS)); 2747 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2748 PetscCall(PetscFree(mesh->parents)); 2749 PetscCall(PetscFree(mesh->childIDs)); 2750 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2751 PetscCall(PetscFree(mesh->children)); 2752 PetscCall(DMDestroy(&mesh->referenceTree)); 2753 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2754 PetscCall(PetscFree(mesh->neighbors)); 2755 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2756 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2757 PetscCall(PetscFree(mesh)); 2758 PetscFunctionReturn(PETSC_SUCCESS); 2759 } 2760 2761 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2762 { 2763 PetscSection sectionGlobal, sectionLocal; 2764 PetscInt bs = -1, mbs; 2765 PetscInt localSize, localStart = 0; 2766 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2767 MatType mtype; 2768 ISLocalToGlobalMapping ltog; 2769 2770 PetscFunctionBegin; 2771 PetscCall(MatInitializePackage()); 2772 mtype = dm->mattype; 2773 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2774 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2775 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2776 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2777 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2778 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2779 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2780 PetscCall(MatSetType(*J, mtype)); 2781 PetscCall(MatSetFromOptions(*J)); 2782 PetscCall(MatGetBlockSize(*J, &mbs)); 2783 if (mbs > 1) bs = mbs; 2784 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2785 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2786 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2787 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2788 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2789 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2790 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2791 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2792 if (!isShell) { 2793 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2794 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2795 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2796 2797 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2798 2799 PetscCall(PetscCalloc1(localSize, &pblocks)); 2800 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2801 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2802 for (p = pStart; p < pEnd; ++p) { 2803 switch (dm->blocking_type) { 2804 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2805 PetscInt bdof, offset; 2806 2807 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2808 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2809 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2810 if (dof > 0) { 2811 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2812 // Signal block concatenation 2813 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2814 } 2815 dof = dof < 0 ? -(dof + 1) : dof; 2816 bdof = cdof && (dof - cdof) ? 1 : dof; 2817 if (dof) { 2818 if (bs < 0) { 2819 bs = bdof; 2820 } else if (bs != bdof) { 2821 bs = 1; 2822 } 2823 } 2824 } break; 2825 case DM_BLOCKING_FIELD_NODE: { 2826 for (PetscInt field = 0; field < num_fields; field++) { 2827 PetscInt num_comp, bdof, offset; 2828 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2829 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2830 if (dof < 0) continue; 2831 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2832 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2833 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); 2834 PetscInt num_nodes = dof / num_comp; 2835 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2836 // Handle possibly constant block size (unlikely) 2837 bdof = cdof && (dof - cdof) ? 1 : dof; 2838 if (dof) { 2839 if (bs < 0) { 2840 bs = bdof; 2841 } else if (bs != bdof) { 2842 bs = 1; 2843 } 2844 } 2845 } 2846 } break; 2847 } 2848 } 2849 /* Must have same blocksize on all procs (some might have no points) */ 2850 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2851 bsLocal[1] = bs; 2852 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2853 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2854 else bs = bsMinMax[0]; 2855 bs = PetscMax(1, bs); 2856 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2857 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2858 PetscCall(MatSetBlockSize(*J, bs)); 2859 PetscCall(MatSetUp(*J)); 2860 } else { 2861 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2862 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2863 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2864 } 2865 if (pblocks) { // Consolidate blocks 2866 PetscInt nblocks = 0; 2867 pblocks[0] = PetscAbs(pblocks[0]); 2868 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2869 if (pblocks[i] == 0) continue; 2870 // Negative block size indicates the blocks should be concatenated 2871 if (pblocks[i] < 0) { 2872 pblocks[i] = -pblocks[i]; 2873 pblocks[nblocks - 1] += pblocks[i]; 2874 } else { 2875 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2876 } 2877 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]); 2878 } 2879 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2880 } 2881 PetscCall(PetscFree(pblocks)); 2882 } 2883 PetscCall(MatSetDM(*J, dm)); 2884 PetscFunctionReturn(PETSC_SUCCESS); 2885 } 2886 2887 /*@ 2888 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2889 2890 Not Collective 2891 2892 Input Parameter: 2893 . dm - The `DMPLEX` 2894 2895 Output Parameter: 2896 . subsection - The subdomain section 2897 2898 Level: developer 2899 2900 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2901 @*/ 2902 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2903 { 2904 DM_Plex *mesh = (DM_Plex *)dm->data; 2905 2906 PetscFunctionBegin; 2907 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2908 if (!mesh->subdomainSection) { 2909 PetscSection section; 2910 PetscSF sf; 2911 2912 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2913 PetscCall(DMGetLocalSection(dm, §ion)); 2914 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2915 PetscCall(PetscSFDestroy(&sf)); 2916 } 2917 *subsection = mesh->subdomainSection; 2918 PetscFunctionReturn(PETSC_SUCCESS); 2919 } 2920 2921 /*@ 2922 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2923 2924 Not Collective 2925 2926 Input Parameter: 2927 . dm - The `DMPLEX` 2928 2929 Output Parameters: 2930 + pStart - The first mesh point 2931 - pEnd - The upper bound for mesh points 2932 2933 Level: beginner 2934 2935 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2936 @*/ 2937 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2938 { 2939 DM_Plex *mesh = (DM_Plex *)dm->data; 2940 2941 PetscFunctionBegin; 2942 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2943 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2944 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2945 PetscFunctionReturn(PETSC_SUCCESS); 2946 } 2947 2948 /*@ 2949 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2950 2951 Not Collective 2952 2953 Input Parameters: 2954 + dm - The `DMPLEX` 2955 . pStart - The first mesh point 2956 - pEnd - The upper bound for mesh points 2957 2958 Level: beginner 2959 2960 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2961 @*/ 2962 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2963 { 2964 DM_Plex *mesh = (DM_Plex *)dm->data; 2965 2966 PetscFunctionBegin; 2967 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2968 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2969 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2970 PetscCall(PetscFree(mesh->cellTypes)); 2971 PetscFunctionReturn(PETSC_SUCCESS); 2972 } 2973 2974 /*@ 2975 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2976 2977 Not Collective 2978 2979 Input Parameters: 2980 + dm - The `DMPLEX` 2981 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2982 2983 Output Parameter: 2984 . size - The cone size for point `p` 2985 2986 Level: beginner 2987 2988 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2989 @*/ 2990 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2991 { 2992 DM_Plex *mesh = (DM_Plex *)dm->data; 2993 2994 PetscFunctionBegin; 2995 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2996 PetscAssertPointer(size, 3); 2997 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2998 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2999 PetscFunctionReturn(PETSC_SUCCESS); 3000 } 3001 3002 /*@ 3003 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3004 3005 Not Collective 3006 3007 Input Parameters: 3008 + dm - The `DMPLEX` 3009 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3010 - size - The cone size for point `p` 3011 3012 Level: beginner 3013 3014 Note: 3015 This should be called after `DMPlexSetChart()`. 3016 3017 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3018 @*/ 3019 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3020 { 3021 DM_Plex *mesh = (DM_Plex *)dm->data; 3022 3023 PetscFunctionBegin; 3024 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3025 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3026 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3027 PetscFunctionReturn(PETSC_SUCCESS); 3028 } 3029 3030 /*@C 3031 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3032 3033 Not Collective 3034 3035 Input Parameters: 3036 + dm - The `DMPLEX` 3037 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3038 3039 Output Parameter: 3040 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3041 3042 Level: beginner 3043 3044 Fortran Notes: 3045 `cone` must be declared with 3046 .vb 3047 PetscInt, pointer :: cone(:) 3048 .ve 3049 3050 You must also call `DMPlexRestoreCone()` after you finish using the array. 3051 `DMPlexRestoreCone()` is not needed/available in C. 3052 3053 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3054 @*/ 3055 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3056 { 3057 DM_Plex *mesh = (DM_Plex *)dm->data; 3058 PetscInt off; 3059 3060 PetscFunctionBegin; 3061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3062 PetscAssertPointer(cone, 3); 3063 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3064 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3065 PetscFunctionReturn(PETSC_SUCCESS); 3066 } 3067 3068 /*@C 3069 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3070 3071 Not Collective 3072 3073 Input Parameters: 3074 + dm - The `DMPLEX` 3075 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3076 3077 Output Parameters: 3078 + pConesSection - `PetscSection` describing the layout of `pCones` 3079 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3080 3081 Level: intermediate 3082 3083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3084 @*/ 3085 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3086 { 3087 PetscSection cs, newcs; 3088 PetscInt *cones; 3089 PetscInt *newarr = NULL; 3090 PetscInt n; 3091 3092 PetscFunctionBegin; 3093 PetscCall(DMPlexGetCones(dm, &cones)); 3094 PetscCall(DMPlexGetConeSection(dm, &cs)); 3095 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3096 if (pConesSection) *pConesSection = newcs; 3097 if (pCones) { 3098 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3099 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3100 } 3101 PetscFunctionReturn(PETSC_SUCCESS); 3102 } 3103 3104 /*@ 3105 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3106 3107 Not Collective 3108 3109 Input Parameters: 3110 + dm - The `DMPLEX` 3111 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3112 3113 Output Parameter: 3114 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3115 3116 Level: advanced 3117 3118 Notes: 3119 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3120 3121 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3122 3123 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3124 `DMPlexGetDepth()`, `IS` 3125 @*/ 3126 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3127 { 3128 IS *expandedPointsAll; 3129 PetscInt depth; 3130 3131 PetscFunctionBegin; 3132 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3133 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3134 PetscAssertPointer(expandedPoints, 3); 3135 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3136 *expandedPoints = expandedPointsAll[0]; 3137 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3138 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3139 PetscFunctionReturn(PETSC_SUCCESS); 3140 } 3141 3142 /*@ 3143 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3144 (DAG points of depth 0, i.e., without cones). 3145 3146 Not Collective 3147 3148 Input Parameters: 3149 + dm - The `DMPLEX` 3150 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3151 3152 Output Parameters: 3153 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3154 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3155 - sections - (optional) An array of sections which describe mappings from points to their cone points 3156 3157 Level: advanced 3158 3159 Notes: 3160 Like `DMPlexGetConeTuple()` but recursive. 3161 3162 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. 3163 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3164 3165 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\: 3166 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3167 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3168 3169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3170 `DMPlexGetDepth()`, `PetscSection`, `IS` 3171 @*/ 3172 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3173 { 3174 const PetscInt *arr0 = NULL, *cone = NULL; 3175 PetscInt *arr = NULL, *newarr = NULL; 3176 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3177 IS *expandedPoints_; 3178 PetscSection *sections_; 3179 3180 PetscFunctionBegin; 3181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3182 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3183 if (depth) PetscAssertPointer(depth, 3); 3184 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3185 if (sections) PetscAssertPointer(sections, 5); 3186 PetscCall(ISGetLocalSize(points, &n)); 3187 PetscCall(ISGetIndices(points, &arr0)); 3188 PetscCall(DMPlexGetDepth(dm, &depth_)); 3189 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3190 PetscCall(PetscCalloc1(depth_, §ions_)); 3191 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3192 for (d = depth_ - 1; d >= 0; d--) { 3193 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3194 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3195 for (i = 0; i < n; i++) { 3196 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3197 if (arr[i] >= start && arr[i] < end) { 3198 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3199 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3200 } else { 3201 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3202 } 3203 } 3204 PetscCall(PetscSectionSetUp(sections_[d])); 3205 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3206 PetscCall(PetscMalloc1(newn, &newarr)); 3207 for (i = 0; i < n; i++) { 3208 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3209 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3210 if (cn > 1) { 3211 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3212 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3213 } else { 3214 newarr[co] = arr[i]; 3215 } 3216 } 3217 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3218 arr = newarr; 3219 n = newn; 3220 } 3221 PetscCall(ISRestoreIndices(points, &arr0)); 3222 *depth = depth_; 3223 if (expandedPoints) *expandedPoints = expandedPoints_; 3224 else { 3225 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3226 PetscCall(PetscFree(expandedPoints_)); 3227 } 3228 if (sections) *sections = sections_; 3229 else { 3230 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3231 PetscCall(PetscFree(sections_)); 3232 } 3233 PetscFunctionReturn(PETSC_SUCCESS); 3234 } 3235 3236 /*@ 3237 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3238 3239 Not Collective 3240 3241 Input Parameters: 3242 + dm - The `DMPLEX` 3243 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3244 3245 Output Parameters: 3246 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3247 . expandedPoints - (optional) An array of recursively expanded cones 3248 - sections - (optional) An array of sections which describe mappings from points to their cone points 3249 3250 Level: advanced 3251 3252 Note: 3253 See `DMPlexGetConeRecursive()` 3254 3255 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3256 `DMPlexGetDepth()`, `IS`, `PetscSection` 3257 @*/ 3258 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3259 { 3260 PetscInt d, depth_; 3261 3262 PetscFunctionBegin; 3263 PetscCall(DMPlexGetDepth(dm, &depth_)); 3264 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3265 if (depth) *depth = 0; 3266 if (expandedPoints) { 3267 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3268 PetscCall(PetscFree(*expandedPoints)); 3269 } 3270 if (sections) { 3271 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3272 PetscCall(PetscFree(*sections)); 3273 } 3274 PetscFunctionReturn(PETSC_SUCCESS); 3275 } 3276 3277 /*@ 3278 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 3279 3280 Not Collective 3281 3282 Input Parameters: 3283 + dm - The `DMPLEX` 3284 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3285 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3286 3287 Level: beginner 3288 3289 Note: 3290 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3291 3292 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3293 @*/ 3294 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3295 { 3296 DM_Plex *mesh = (DM_Plex *)dm->data; 3297 PetscInt dof, off, c; 3298 3299 PetscFunctionBegin; 3300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3301 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3302 if (dof) PetscAssertPointer(cone, 3); 3303 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3304 if (PetscDefined(USE_DEBUG)) { 3305 PetscInt pStart, pEnd; 3306 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3307 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); 3308 for (c = 0; c < dof; ++c) { 3309 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); 3310 mesh->cones[off + c] = cone[c]; 3311 } 3312 } else { 3313 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3314 } 3315 PetscFunctionReturn(PETSC_SUCCESS); 3316 } 3317 3318 /*@C 3319 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3320 3321 Not Collective 3322 3323 Input Parameters: 3324 + dm - The `DMPLEX` 3325 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3326 3327 Output Parameter: 3328 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3329 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3330 3331 Level: beginner 3332 3333 Note: 3334 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3335 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3336 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3337 with the identity. 3338 3339 Fortran Notes: 3340 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3341 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3342 3343 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3344 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3345 @*/ 3346 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3347 { 3348 DM_Plex *mesh = (DM_Plex *)dm->data; 3349 PetscInt off; 3350 3351 PetscFunctionBegin; 3352 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3353 if (PetscDefined(USE_DEBUG)) { 3354 PetscInt dof; 3355 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3356 if (dof) PetscAssertPointer(coneOrientation, 3); 3357 } 3358 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3359 3360 *coneOrientation = &mesh->coneOrientations[off]; 3361 PetscFunctionReturn(PETSC_SUCCESS); 3362 } 3363 3364 /*@ 3365 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3366 3367 Not Collective 3368 3369 Input Parameters: 3370 + dm - The `DMPLEX` 3371 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3372 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3373 3374 Level: beginner 3375 3376 Notes: 3377 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3378 3379 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3380 3381 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3382 @*/ 3383 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3384 { 3385 DM_Plex *mesh = (DM_Plex *)dm->data; 3386 PetscInt pStart, pEnd; 3387 PetscInt dof, off, c; 3388 3389 PetscFunctionBegin; 3390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3391 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3392 if (dof) PetscAssertPointer(coneOrientation, 3); 3393 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3394 if (PetscDefined(USE_DEBUG)) { 3395 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3396 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); 3397 for (c = 0; c < dof; ++c) { 3398 PetscInt cdof, o = coneOrientation[c]; 3399 3400 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3401 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); 3402 mesh->coneOrientations[off + c] = o; 3403 } 3404 } else { 3405 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3406 } 3407 PetscFunctionReturn(PETSC_SUCCESS); 3408 } 3409 3410 /*@ 3411 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3412 3413 Not Collective 3414 3415 Input Parameters: 3416 + dm - The `DMPLEX` 3417 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3418 . conePos - The local index in the cone where the point should be put 3419 - conePoint - The mesh point to insert 3420 3421 Level: beginner 3422 3423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3424 @*/ 3425 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3426 { 3427 DM_Plex *mesh = (DM_Plex *)dm->data; 3428 PetscInt pStart, pEnd; 3429 PetscInt dof, off; 3430 3431 PetscFunctionBegin; 3432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3433 if (PetscDefined(USE_DEBUG)) { 3434 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3435 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); 3436 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); 3437 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3438 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); 3439 } 3440 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3441 mesh->cones[off + conePos] = conePoint; 3442 PetscFunctionReturn(PETSC_SUCCESS); 3443 } 3444 3445 /*@ 3446 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3447 3448 Not Collective 3449 3450 Input Parameters: 3451 + dm - The `DMPLEX` 3452 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3453 . conePos - The local index in the cone where the point should be put 3454 - coneOrientation - The point orientation to insert 3455 3456 Level: beginner 3457 3458 Note: 3459 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3460 3461 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3462 @*/ 3463 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3464 { 3465 DM_Plex *mesh = (DM_Plex *)dm->data; 3466 PetscInt pStart, pEnd; 3467 PetscInt dof, off; 3468 3469 PetscFunctionBegin; 3470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3471 if (PetscDefined(USE_DEBUG)) { 3472 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3473 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); 3474 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3475 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); 3476 } 3477 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3478 mesh->coneOrientations[off + conePos] = coneOrientation; 3479 PetscFunctionReturn(PETSC_SUCCESS); 3480 } 3481 3482 /*@C 3483 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3484 3485 Not collective 3486 3487 Input Parameters: 3488 + dm - The DMPlex 3489 - p - The point, which must lie in the chart set with DMPlexSetChart() 3490 3491 Output Parameters: 3492 + cone - An array of points which are on the in-edges for point `p` 3493 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3494 integer giving the prescription for cone traversal. 3495 3496 Level: beginner 3497 3498 Notes: 3499 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3500 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3501 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3502 with the identity. 3503 3504 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3505 3506 Fortran Notes: 3507 `cone` and `ornt` must be declared with 3508 .vb 3509 PetscInt, pointer :: cone(:) 3510 PetscInt, pointer :: ornt(:) 3511 .ve 3512 3513 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3514 @*/ 3515 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3516 { 3517 DM_Plex *mesh = (DM_Plex *)dm->data; 3518 3519 PetscFunctionBegin; 3520 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3521 if (mesh->tr) { 3522 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3523 } else { 3524 PetscInt off; 3525 if (PetscDefined(USE_DEBUG)) { 3526 PetscInt dof; 3527 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3528 if (dof) { 3529 if (cone) PetscAssertPointer(cone, 3); 3530 if (ornt) PetscAssertPointer(ornt, 4); 3531 } 3532 } 3533 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3534 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3535 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3536 } 3537 PetscFunctionReturn(PETSC_SUCCESS); 3538 } 3539 3540 /*@C 3541 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3542 3543 Not Collective 3544 3545 Input Parameters: 3546 + dm - The DMPlex 3547 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3548 . cone - An array of points which are on the in-edges for point p 3549 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3550 integer giving the prescription for cone traversal. 3551 3552 Level: beginner 3553 3554 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3555 @*/ 3556 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3557 { 3558 DM_Plex *mesh = (DM_Plex *)dm->data; 3559 3560 PetscFunctionBegin; 3561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3562 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3563 PetscFunctionReturn(PETSC_SUCCESS); 3564 } 3565 3566 /*@ 3567 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3568 3569 Not Collective 3570 3571 Input Parameters: 3572 + dm - The `DMPLEX` 3573 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3574 3575 Output Parameter: 3576 . size - The support size for point `p` 3577 3578 Level: beginner 3579 3580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3581 @*/ 3582 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3583 { 3584 DM_Plex *mesh = (DM_Plex *)dm->data; 3585 3586 PetscFunctionBegin; 3587 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3588 PetscAssertPointer(size, 3); 3589 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3590 PetscFunctionReturn(PETSC_SUCCESS); 3591 } 3592 3593 /*@ 3594 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3595 3596 Not Collective 3597 3598 Input Parameters: 3599 + dm - The `DMPLEX` 3600 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3601 - size - The support size for point `p` 3602 3603 Level: beginner 3604 3605 Note: 3606 This should be called after `DMPlexSetChart()`. 3607 3608 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3609 @*/ 3610 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3611 { 3612 DM_Plex *mesh = (DM_Plex *)dm->data; 3613 3614 PetscFunctionBegin; 3615 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3616 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3617 PetscFunctionReturn(PETSC_SUCCESS); 3618 } 3619 3620 /*@C 3621 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3622 3623 Not Collective 3624 3625 Input Parameters: 3626 + dm - The `DMPLEX` 3627 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3628 3629 Output Parameter: 3630 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3631 3632 Level: beginner 3633 3634 Fortran Notes: 3635 `support` must be declared with 3636 .vb 3637 PetscInt, pointer :: support(:) 3638 .ve 3639 3640 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3641 `DMPlexRestoreSupport()` is not needed/available in C. 3642 3643 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3644 @*/ 3645 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3646 { 3647 DM_Plex *mesh = (DM_Plex *)dm->data; 3648 PetscInt off; 3649 3650 PetscFunctionBegin; 3651 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3652 PetscAssertPointer(support, 3); 3653 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3654 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3655 PetscFunctionReturn(PETSC_SUCCESS); 3656 } 3657 3658 /*@ 3659 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3660 3661 Not Collective 3662 3663 Input Parameters: 3664 + dm - The `DMPLEX` 3665 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3666 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3667 3668 Level: beginner 3669 3670 Note: 3671 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3672 3673 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3674 @*/ 3675 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3676 { 3677 DM_Plex *mesh = (DM_Plex *)dm->data; 3678 PetscInt pStart, pEnd; 3679 PetscInt dof, off, c; 3680 3681 PetscFunctionBegin; 3682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3683 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3684 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3685 if (dof) PetscAssertPointer(support, 3); 3686 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3687 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); 3688 for (c = 0; c < dof; ++c) { 3689 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); 3690 mesh->supports[off + c] = support[c]; 3691 } 3692 PetscFunctionReturn(PETSC_SUCCESS); 3693 } 3694 3695 /*@ 3696 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3697 3698 Not Collective 3699 3700 Input Parameters: 3701 + dm - The `DMPLEX` 3702 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3703 . supportPos - The local index in the cone where the point should be put 3704 - supportPoint - The mesh point to insert 3705 3706 Level: beginner 3707 3708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3709 @*/ 3710 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3711 { 3712 DM_Plex *mesh = (DM_Plex *)dm->data; 3713 PetscInt pStart, pEnd; 3714 PetscInt dof, off; 3715 3716 PetscFunctionBegin; 3717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3718 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3719 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3720 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3721 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); 3722 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); 3723 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); 3724 mesh->supports[off + supportPos] = supportPoint; 3725 PetscFunctionReturn(PETSC_SUCCESS); 3726 } 3727 3728 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3729 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3730 { 3731 switch (ct) { 3732 case DM_POLYTOPE_SEGMENT: 3733 if (o == -1) return -2; 3734 break; 3735 case DM_POLYTOPE_TRIANGLE: 3736 if (o == -3) return -1; 3737 if (o == -2) return -3; 3738 if (o == -1) return -2; 3739 break; 3740 case DM_POLYTOPE_QUADRILATERAL: 3741 if (o == -4) return -2; 3742 if (o == -3) return -1; 3743 if (o == -2) return -4; 3744 if (o == -1) return -3; 3745 break; 3746 default: 3747 return o; 3748 } 3749 return o; 3750 } 3751 3752 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3753 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3754 { 3755 switch (ct) { 3756 case DM_POLYTOPE_SEGMENT: 3757 if ((o == -2) || (o == 1)) return -1; 3758 if (o == -1) return 0; 3759 break; 3760 case DM_POLYTOPE_TRIANGLE: 3761 if (o == -3) return -2; 3762 if (o == -2) return -1; 3763 if (o == -1) return -3; 3764 break; 3765 case DM_POLYTOPE_QUADRILATERAL: 3766 if (o == -4) return -2; 3767 if (o == -3) return -1; 3768 if (o == -2) return -4; 3769 if (o == -1) return -3; 3770 break; 3771 default: 3772 return o; 3773 } 3774 return o; 3775 } 3776 3777 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3778 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3779 { 3780 PetscInt pStart, pEnd, p; 3781 3782 PetscFunctionBegin; 3783 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3784 for (p = pStart; p < pEnd; ++p) { 3785 const PetscInt *cone, *ornt; 3786 PetscInt coneSize, c; 3787 3788 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3789 PetscCall(DMPlexGetCone(dm, p, &cone)); 3790 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3791 for (c = 0; c < coneSize; ++c) { 3792 DMPolytopeType ct; 3793 const PetscInt o = ornt[c]; 3794 3795 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3796 switch (ct) { 3797 case DM_POLYTOPE_SEGMENT: 3798 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3799 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3800 break; 3801 case DM_POLYTOPE_TRIANGLE: 3802 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3803 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3804 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3805 break; 3806 case DM_POLYTOPE_QUADRILATERAL: 3807 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3808 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3809 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3810 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3811 break; 3812 default: 3813 break; 3814 } 3815 } 3816 } 3817 PetscFunctionReturn(PETSC_SUCCESS); 3818 } 3819 3820 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3821 { 3822 DM_Plex *mesh = (DM_Plex *)dm->data; 3823 3824 PetscFunctionBeginHot; 3825 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3826 if (useCone) { 3827 PetscCall(DMPlexGetConeSize(dm, p, size)); 3828 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3829 } else { 3830 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3831 PetscCall(DMPlexGetSupport(dm, p, arr)); 3832 } 3833 } else { 3834 if (useCone) { 3835 const PetscSection s = mesh->coneSection; 3836 const PetscInt ps = p - s->pStart; 3837 const PetscInt off = s->atlasOff[ps]; 3838 3839 *size = s->atlasDof[ps]; 3840 *arr = mesh->cones + off; 3841 *ornt = mesh->coneOrientations + off; 3842 } else { 3843 const PetscSection s = mesh->supportSection; 3844 const PetscInt ps = p - s->pStart; 3845 const PetscInt off = s->atlasOff[ps]; 3846 3847 *size = s->atlasDof[ps]; 3848 *arr = mesh->supports + off; 3849 } 3850 } 3851 PetscFunctionReturn(PETSC_SUCCESS); 3852 } 3853 3854 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3855 { 3856 DM_Plex *mesh = (DM_Plex *)dm->data; 3857 3858 PetscFunctionBeginHot; 3859 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3860 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3861 } 3862 PetscFunctionReturn(PETSC_SUCCESS); 3863 } 3864 3865 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3866 { 3867 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3868 PetscInt *closure; 3869 const PetscInt *tmp = NULL, *tmpO = NULL; 3870 PetscInt off = 0, tmpSize, t; 3871 3872 PetscFunctionBeginHot; 3873 if (ornt) { 3874 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3875 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; 3876 } 3877 if (*points) { 3878 closure = *points; 3879 } else { 3880 PetscInt maxConeSize, maxSupportSize; 3881 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3882 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3883 } 3884 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3885 if (ct == DM_POLYTOPE_UNKNOWN) { 3886 closure[off++] = p; 3887 closure[off++] = 0; 3888 for (t = 0; t < tmpSize; ++t) { 3889 closure[off++] = tmp[t]; 3890 closure[off++] = tmpO ? tmpO[t] : 0; 3891 } 3892 } else { 3893 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3894 3895 /* We assume that cells with a valid type have faces with a valid type */ 3896 closure[off++] = p; 3897 closure[off++] = ornt; 3898 for (t = 0; t < tmpSize; ++t) { 3899 DMPolytopeType ft; 3900 3901 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3902 closure[off++] = tmp[arr[t]]; 3903 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3904 } 3905 } 3906 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3907 if (numPoints) *numPoints = tmpSize + 1; 3908 if (points) *points = closure; 3909 PetscFunctionReturn(PETSC_SUCCESS); 3910 } 3911 3912 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3913 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3914 { 3915 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3916 const PetscInt *cone, *ornt; 3917 PetscInt *pts, *closure = NULL; 3918 DMPolytopeType ft; 3919 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3920 PetscInt dim, coneSize, c, d, clSize, cl; 3921 3922 PetscFunctionBeginHot; 3923 PetscCall(DMGetDimension(dm, &dim)); 3924 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3925 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3926 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3927 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3928 maxSize = PetscMax(coneSeries, supportSeries); 3929 if (*points) { 3930 pts = *points; 3931 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3932 c = 0; 3933 pts[c++] = point; 3934 pts[c++] = o; 3935 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3936 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3937 for (cl = 0; cl < clSize * 2; cl += 2) { 3938 pts[c++] = closure[cl]; 3939 pts[c++] = closure[cl + 1]; 3940 } 3941 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3942 for (cl = 0; cl < clSize * 2; cl += 2) { 3943 pts[c++] = closure[cl]; 3944 pts[c++] = closure[cl + 1]; 3945 } 3946 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3947 for (d = 2; d < coneSize; ++d) { 3948 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3949 pts[c++] = cone[arr[d * 2 + 0]]; 3950 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3951 } 3952 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3953 if (dim >= 3) { 3954 for (d = 2; d < coneSize; ++d) { 3955 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3956 const PetscInt *fcone, *fornt; 3957 PetscInt fconeSize, fc, i; 3958 3959 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3960 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3961 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3962 for (fc = 0; fc < fconeSize; ++fc) { 3963 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3964 const PetscInt co = farr[fc * 2 + 1]; 3965 3966 for (i = 0; i < c; i += 2) 3967 if (pts[i] == cp) break; 3968 if (i == c) { 3969 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3970 pts[c++] = cp; 3971 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3972 } 3973 } 3974 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3975 } 3976 } 3977 *numPoints = c / 2; 3978 *points = pts; 3979 PetscFunctionReturn(PETSC_SUCCESS); 3980 } 3981 3982 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3983 { 3984 DMPolytopeType ct; 3985 PetscInt *closure, *fifo; 3986 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3987 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3988 PetscInt depth, maxSize; 3989 3990 PetscFunctionBeginHot; 3991 PetscCall(DMPlexGetDepth(dm, &depth)); 3992 if (depth == 1) { 3993 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3994 PetscFunctionReturn(PETSC_SUCCESS); 3995 } 3996 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3997 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; 3998 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3999 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4000 PetscFunctionReturn(PETSC_SUCCESS); 4001 } 4002 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4003 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4004 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4005 maxSize = PetscMax(coneSeries, supportSeries); 4006 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4007 if (*points) { 4008 closure = *points; 4009 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4010 closure[closureSize++] = p; 4011 closure[closureSize++] = ornt; 4012 fifo[fifoSize++] = p; 4013 fifo[fifoSize++] = ornt; 4014 fifo[fifoSize++] = ct; 4015 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4016 while (fifoSize - fifoStart) { 4017 const PetscInt q = fifo[fifoStart++]; 4018 const PetscInt o = fifo[fifoStart++]; 4019 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4020 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4021 const PetscInt *tmp, *tmpO = NULL; 4022 PetscInt tmpSize, t; 4023 4024 if (PetscDefined(USE_DEBUG)) { 4025 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4026 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); 4027 } 4028 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4029 for (t = 0; t < tmpSize; ++t) { 4030 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4031 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4032 const PetscInt cp = tmp[ip]; 4033 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4034 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4035 PetscInt c; 4036 4037 /* Check for duplicate */ 4038 for (c = 0; c < closureSize; c += 2) { 4039 if (closure[c] == cp) break; 4040 } 4041 if (c == closureSize) { 4042 closure[closureSize++] = cp; 4043 closure[closureSize++] = co; 4044 fifo[fifoSize++] = cp; 4045 fifo[fifoSize++] = co; 4046 fifo[fifoSize++] = ct; 4047 } 4048 } 4049 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4050 } 4051 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4052 if (numPoints) *numPoints = closureSize / 2; 4053 if (points) *points = closure; 4054 PetscFunctionReturn(PETSC_SUCCESS); 4055 } 4056 4057 /*@C 4058 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4059 4060 Not Collective 4061 4062 Input Parameters: 4063 + dm - The `DMPLEX` 4064 . p - The mesh point 4065 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4066 4067 Input/Output Parameter: 4068 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4069 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4070 otherwise the provided array is used to hold the values 4071 4072 Output Parameter: 4073 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4074 4075 Level: beginner 4076 4077 Note: 4078 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4079 4080 Fortran Notes: 4081 `points` must be declared with 4082 .vb 4083 PetscInt, pointer :: points(:) 4084 .ve 4085 and is always allocated by the function. 4086 4087 The `numPoints` argument is not present in the Fortran binding. 4088 4089 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4090 @*/ 4091 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4092 { 4093 PetscFunctionBeginHot; 4094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4095 if (numPoints) PetscAssertPointer(numPoints, 4); 4096 if (points) PetscAssertPointer(points, 5); 4097 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4098 PetscFunctionReturn(PETSC_SUCCESS); 4099 } 4100 4101 /*@C 4102 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4103 4104 Not Collective 4105 4106 Input Parameters: 4107 + dm - The `DMPLEX` 4108 . p - The mesh point 4109 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4110 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4111 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4112 4113 Level: beginner 4114 4115 Note: 4116 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4117 4118 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4119 @*/ 4120 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4121 { 4122 PetscFunctionBeginHot; 4123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4124 if (numPoints) *numPoints = 0; 4125 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4126 PetscFunctionReturn(PETSC_SUCCESS); 4127 } 4128 4129 /*@ 4130 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4131 4132 Not Collective 4133 4134 Input Parameter: 4135 . dm - The `DMPLEX` 4136 4137 Output Parameters: 4138 + maxConeSize - The maximum number of in-edges 4139 - maxSupportSize - The maximum number of out-edges 4140 4141 Level: beginner 4142 4143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4144 @*/ 4145 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4146 { 4147 DM_Plex *mesh = (DM_Plex *)dm->data; 4148 4149 PetscFunctionBegin; 4150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4151 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4152 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4153 PetscFunctionReturn(PETSC_SUCCESS); 4154 } 4155 4156 PetscErrorCode DMSetUp_Plex(DM dm) 4157 { 4158 DM_Plex *mesh = (DM_Plex *)dm->data; 4159 PetscInt size, maxSupportSize; 4160 4161 PetscFunctionBegin; 4162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4163 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4164 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4165 PetscCall(PetscMalloc1(size, &mesh->cones)); 4166 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4167 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4168 if (maxSupportSize) { 4169 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4170 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4171 PetscCall(PetscMalloc1(size, &mesh->supports)); 4172 } 4173 PetscFunctionReturn(PETSC_SUCCESS); 4174 } 4175 4176 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4177 { 4178 PetscFunctionBegin; 4179 if (subdm) PetscCall(DMClone(dm, subdm)); 4180 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4181 if (subdm) (*subdm)->useNatural = dm->useNatural; 4182 if (dm->useNatural && dm->sfMigration) { 4183 PetscSF sfNatural; 4184 4185 (*subdm)->sfMigration = dm->sfMigration; 4186 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4187 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4188 (*subdm)->sfNatural = sfNatural; 4189 } 4190 PetscFunctionReturn(PETSC_SUCCESS); 4191 } 4192 4193 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4194 { 4195 PetscInt i = 0; 4196 4197 PetscFunctionBegin; 4198 PetscCall(DMClone(dms[0], superdm)); 4199 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4200 (*superdm)->useNatural = PETSC_FALSE; 4201 for (i = 0; i < len; i++) { 4202 if (dms[i]->useNatural && dms[i]->sfMigration) { 4203 PetscSF sfNatural; 4204 4205 (*superdm)->sfMigration = dms[i]->sfMigration; 4206 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4207 (*superdm)->useNatural = PETSC_TRUE; 4208 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4209 (*superdm)->sfNatural = sfNatural; 4210 break; 4211 } 4212 } 4213 PetscFunctionReturn(PETSC_SUCCESS); 4214 } 4215 4216 /*@ 4217 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4218 4219 Not Collective 4220 4221 Input Parameter: 4222 . dm - The `DMPLEX` 4223 4224 Level: beginner 4225 4226 Note: 4227 This should be called after all calls to `DMPlexSetCone()` 4228 4229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4230 @*/ 4231 PetscErrorCode DMPlexSymmetrize(DM dm) 4232 { 4233 DM_Plex *mesh = (DM_Plex *)dm->data; 4234 PetscInt *offsets; 4235 PetscInt supportSize; 4236 PetscInt pStart, pEnd, p; 4237 4238 PetscFunctionBegin; 4239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4240 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4241 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4242 /* Calculate support sizes */ 4243 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4244 for (p = pStart; p < pEnd; ++p) { 4245 PetscInt dof, off, c; 4246 4247 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4248 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4249 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4250 } 4251 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4252 /* Calculate supports */ 4253 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4254 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4255 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4256 for (p = pStart; p < pEnd; ++p) { 4257 PetscInt dof, off, c; 4258 4259 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4260 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4261 for (c = off; c < off + dof; ++c) { 4262 const PetscInt q = mesh->cones[c]; 4263 PetscInt offS; 4264 4265 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4266 4267 mesh->supports[offS + offsets[q]] = p; 4268 ++offsets[q]; 4269 } 4270 } 4271 PetscCall(PetscFree(offsets)); 4272 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4273 PetscFunctionReturn(PETSC_SUCCESS); 4274 } 4275 4276 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4277 { 4278 IS stratumIS; 4279 4280 PetscFunctionBegin; 4281 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4282 if (PetscDefined(USE_DEBUG)) { 4283 PetscInt qStart, qEnd, numLevels, level; 4284 PetscBool overlap = PETSC_FALSE; 4285 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4286 for (level = 0; level < numLevels; level++) { 4287 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4288 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4289 overlap = PETSC_TRUE; 4290 break; 4291 } 4292 } 4293 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); 4294 } 4295 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4296 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4297 PetscCall(ISDestroy(&stratumIS)); 4298 PetscFunctionReturn(PETSC_SUCCESS); 4299 } 4300 4301 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4302 { 4303 PetscInt *pMin, *pMax; 4304 PetscInt pStart, pEnd; 4305 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4306 4307 PetscFunctionBegin; 4308 { 4309 DMLabel label2; 4310 4311 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4312 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4313 } 4314 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4315 for (PetscInt p = pStart; p < pEnd; ++p) { 4316 DMPolytopeType ct; 4317 4318 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4319 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4320 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4321 } 4322 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4323 for (PetscInt d = dmin; d <= dmax; ++d) { 4324 pMin[d] = PETSC_MAX_INT; 4325 pMax[d] = PETSC_MIN_INT; 4326 } 4327 for (PetscInt p = pStart; p < pEnd; ++p) { 4328 DMPolytopeType ct; 4329 PetscInt d; 4330 4331 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4332 d = DMPolytopeTypeGetDim(ct); 4333 pMin[d] = PetscMin(p, pMin[d]); 4334 pMax[d] = PetscMax(p, pMax[d]); 4335 } 4336 for (PetscInt d = dmin; d <= dmax; ++d) { 4337 if (pMin[d] > pMax[d]) continue; 4338 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4339 } 4340 PetscCall(PetscFree2(pMin, pMax)); 4341 PetscFunctionReturn(PETSC_SUCCESS); 4342 } 4343 4344 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4345 { 4346 PetscInt pStart, pEnd; 4347 PetscInt numRoots = 0, numLeaves = 0; 4348 4349 PetscFunctionBegin; 4350 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4351 { 4352 /* Initialize roots and count leaves */ 4353 PetscInt sMin = PETSC_MAX_INT; 4354 PetscInt sMax = PETSC_MIN_INT; 4355 PetscInt coneSize, supportSize; 4356 4357 for (PetscInt p = pStart; p < pEnd; ++p) { 4358 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4359 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4360 if (!coneSize && supportSize) { 4361 sMin = PetscMin(p, sMin); 4362 sMax = PetscMax(p, sMax); 4363 ++numRoots; 4364 } else if (!supportSize && coneSize) { 4365 ++numLeaves; 4366 } else if (!supportSize && !coneSize) { 4367 /* Isolated points */ 4368 sMin = PetscMin(p, sMin); 4369 sMax = PetscMax(p, sMax); 4370 } 4371 } 4372 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4373 } 4374 4375 if (numRoots + numLeaves == (pEnd - pStart)) { 4376 PetscInt sMin = PETSC_MAX_INT; 4377 PetscInt sMax = PETSC_MIN_INT; 4378 PetscInt coneSize, supportSize; 4379 4380 for (PetscInt p = pStart; p < pEnd; ++p) { 4381 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4382 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4383 if (!supportSize && coneSize) { 4384 sMin = PetscMin(p, sMin); 4385 sMax = PetscMax(p, sMax); 4386 } 4387 } 4388 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4389 } else { 4390 PetscInt level = 0; 4391 PetscInt qStart, qEnd; 4392 4393 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4394 while (qEnd > qStart) { 4395 PetscInt sMin = PETSC_MAX_INT; 4396 PetscInt sMax = PETSC_MIN_INT; 4397 4398 for (PetscInt q = qStart; q < qEnd; ++q) { 4399 const PetscInt *support; 4400 PetscInt supportSize; 4401 4402 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4403 PetscCall(DMPlexGetSupport(dm, q, &support)); 4404 for (PetscInt s = 0; s < supportSize; ++s) { 4405 sMin = PetscMin(support[s], sMin); 4406 sMax = PetscMax(support[s], sMax); 4407 } 4408 } 4409 PetscCall(DMLabelGetNumValues(label, &level)); 4410 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4411 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4412 } 4413 } 4414 PetscFunctionReturn(PETSC_SUCCESS); 4415 } 4416 4417 /*@ 4418 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4419 4420 Collective 4421 4422 Input Parameter: 4423 . dm - The `DMPLEX` 4424 4425 Level: beginner 4426 4427 Notes: 4428 The strata group all points of the same grade, and this function calculates the strata. This 4429 grade can be seen as the height (or depth) of the point in the DAG. 4430 4431 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4432 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4433 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4434 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4435 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4436 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4437 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4438 4439 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4440 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4441 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 4442 to interpolate only that one (e0), so that 4443 .vb 4444 cone(c0) = {e0, v2} 4445 cone(e0) = {v0, v1} 4446 .ve 4447 If `DMPlexStratify()` is run on this mesh, it will give depths 4448 .vb 4449 depth 0 = {v0, v1, v2} 4450 depth 1 = {e0, c0} 4451 .ve 4452 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4453 4454 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4455 4456 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4457 @*/ 4458 PetscErrorCode DMPlexStratify(DM dm) 4459 { 4460 DM_Plex *mesh = (DM_Plex *)dm->data; 4461 DMLabel label; 4462 PetscBool flg = PETSC_FALSE; 4463 4464 PetscFunctionBegin; 4465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4466 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4467 4468 // Create depth label 4469 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4470 PetscCall(DMCreateLabel(dm, "depth")); 4471 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4472 4473 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4474 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4475 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4476 4477 { /* just in case there is an empty process */ 4478 PetscInt numValues, maxValues = 0, v; 4479 4480 PetscCall(DMLabelGetNumValues(label, &numValues)); 4481 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4482 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4483 } 4484 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4485 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4486 PetscFunctionReturn(PETSC_SUCCESS); 4487 } 4488 4489 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4490 { 4491 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4492 PetscInt dim, depth, pheight, coneSize; 4493 4494 PetscFunctionBeginHot; 4495 PetscCall(DMGetDimension(dm, &dim)); 4496 PetscCall(DMPlexGetDepth(dm, &depth)); 4497 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4498 pheight = depth - pdepth; 4499 if (depth <= 1) { 4500 switch (pdepth) { 4501 case 0: 4502 ct = DM_POLYTOPE_POINT; 4503 break; 4504 case 1: 4505 switch (coneSize) { 4506 case 2: 4507 ct = DM_POLYTOPE_SEGMENT; 4508 break; 4509 case 3: 4510 ct = DM_POLYTOPE_TRIANGLE; 4511 break; 4512 case 4: 4513 switch (dim) { 4514 case 2: 4515 ct = DM_POLYTOPE_QUADRILATERAL; 4516 break; 4517 case 3: 4518 ct = DM_POLYTOPE_TETRAHEDRON; 4519 break; 4520 default: 4521 break; 4522 } 4523 break; 4524 case 5: 4525 ct = DM_POLYTOPE_PYRAMID; 4526 break; 4527 case 6: 4528 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4529 break; 4530 case 8: 4531 ct = DM_POLYTOPE_HEXAHEDRON; 4532 break; 4533 default: 4534 break; 4535 } 4536 } 4537 } else { 4538 if (pdepth == 0) { 4539 ct = DM_POLYTOPE_POINT; 4540 } else if (pheight == 0) { 4541 switch (dim) { 4542 case 1: 4543 switch (coneSize) { 4544 case 2: 4545 ct = DM_POLYTOPE_SEGMENT; 4546 break; 4547 default: 4548 break; 4549 } 4550 break; 4551 case 2: 4552 switch (coneSize) { 4553 case 3: 4554 ct = DM_POLYTOPE_TRIANGLE; 4555 break; 4556 case 4: 4557 ct = DM_POLYTOPE_QUADRILATERAL; 4558 break; 4559 default: 4560 break; 4561 } 4562 break; 4563 case 3: 4564 switch (coneSize) { 4565 case 4: 4566 ct = DM_POLYTOPE_TETRAHEDRON; 4567 break; 4568 case 5: { 4569 const PetscInt *cone; 4570 PetscInt faceConeSize; 4571 4572 PetscCall(DMPlexGetCone(dm, p, &cone)); 4573 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4574 switch (faceConeSize) { 4575 case 3: 4576 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4577 break; 4578 case 4: 4579 ct = DM_POLYTOPE_PYRAMID; 4580 break; 4581 } 4582 } break; 4583 case 6: 4584 ct = DM_POLYTOPE_HEXAHEDRON; 4585 break; 4586 default: 4587 break; 4588 } 4589 break; 4590 default: 4591 break; 4592 } 4593 } else if (pheight > 0) { 4594 switch (coneSize) { 4595 case 2: 4596 ct = DM_POLYTOPE_SEGMENT; 4597 break; 4598 case 3: 4599 ct = DM_POLYTOPE_TRIANGLE; 4600 break; 4601 case 4: 4602 ct = DM_POLYTOPE_QUADRILATERAL; 4603 break; 4604 default: 4605 break; 4606 } 4607 } 4608 } 4609 *pt = ct; 4610 PetscFunctionReturn(PETSC_SUCCESS); 4611 } 4612 4613 /*@ 4614 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4615 4616 Collective 4617 4618 Input Parameter: 4619 . dm - The `DMPLEX` 4620 4621 Level: developer 4622 4623 Note: 4624 This function is normally called automatically when a cell type is requested. It creates an 4625 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4626 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4627 4628 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4629 4630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4631 @*/ 4632 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4633 { 4634 DM_Plex *mesh; 4635 DMLabel ctLabel; 4636 PetscInt pStart, pEnd, p; 4637 4638 PetscFunctionBegin; 4639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4640 mesh = (DM_Plex *)dm->data; 4641 PetscCall(DMCreateLabel(dm, "celltype")); 4642 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4643 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4644 PetscCall(PetscFree(mesh->cellTypes)); 4645 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4646 for (p = pStart; p < pEnd; ++p) { 4647 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4648 PetscInt pdepth; 4649 4650 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4651 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4652 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]); 4653 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4654 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4655 } 4656 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4657 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4658 PetscFunctionReturn(PETSC_SUCCESS); 4659 } 4660 4661 /*@C 4662 DMPlexGetJoin - Get an array for the join of the set of points 4663 4664 Not Collective 4665 4666 Input Parameters: 4667 + dm - The `DMPLEX` object 4668 . numPoints - The number of input points for the join 4669 - points - The input points 4670 4671 Output Parameters: 4672 + numCoveredPoints - The number of points in the join 4673 - coveredPoints - The points in the join 4674 4675 Level: intermediate 4676 4677 Note: 4678 Currently, this is restricted to a single level join 4679 4680 Fortran Notes: 4681 `converedPoints` must be declared with 4682 .vb 4683 PetscInt, pointer :: coveredPints(:) 4684 .ve 4685 4686 The `numCoveredPoints` argument is not present in the Fortran binding. 4687 4688 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4689 @*/ 4690 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4691 { 4692 DM_Plex *mesh = (DM_Plex *)dm->data; 4693 PetscInt *join[2]; 4694 PetscInt joinSize, i = 0; 4695 PetscInt dof, off, p, c, m; 4696 PetscInt maxSupportSize; 4697 4698 PetscFunctionBegin; 4699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4700 PetscAssertPointer(points, 3); 4701 PetscAssertPointer(numCoveredPoints, 4); 4702 PetscAssertPointer(coveredPoints, 5); 4703 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4704 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4705 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4706 /* Copy in support of first point */ 4707 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4708 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4709 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4710 /* Check each successive support */ 4711 for (p = 1; p < numPoints; ++p) { 4712 PetscInt newJoinSize = 0; 4713 4714 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4715 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4716 for (c = 0; c < dof; ++c) { 4717 const PetscInt point = mesh->supports[off + c]; 4718 4719 for (m = 0; m < joinSize; ++m) { 4720 if (point == join[i][m]) { 4721 join[1 - i][newJoinSize++] = point; 4722 break; 4723 } 4724 } 4725 } 4726 joinSize = newJoinSize; 4727 i = 1 - i; 4728 } 4729 *numCoveredPoints = joinSize; 4730 *coveredPoints = join[i]; 4731 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4732 PetscFunctionReturn(PETSC_SUCCESS); 4733 } 4734 4735 /*@C 4736 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4737 4738 Not Collective 4739 4740 Input Parameters: 4741 + dm - The `DMPLEX` object 4742 . numPoints - The number of input points for the join 4743 - points - The input points 4744 4745 Output Parameters: 4746 + numCoveredPoints - The number of points in the join 4747 - coveredPoints - The points in the join 4748 4749 Level: intermediate 4750 4751 Fortran Notes: 4752 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4753 4754 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4755 @*/ 4756 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4757 { 4758 PetscFunctionBegin; 4759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4760 if (points) PetscAssertPointer(points, 3); 4761 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4762 PetscAssertPointer(coveredPoints, 5); 4763 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4764 if (numCoveredPoints) *numCoveredPoints = 0; 4765 PetscFunctionReturn(PETSC_SUCCESS); 4766 } 4767 4768 /*@C 4769 DMPlexGetFullJoin - Get an array for the join of the set of points 4770 4771 Not Collective 4772 4773 Input Parameters: 4774 + dm - The `DMPLEX` object 4775 . numPoints - The number of input points for the join 4776 - points - The input points, its length is `numPoints` 4777 4778 Output Parameters: 4779 + numCoveredPoints - The number of points in the join 4780 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4781 4782 Level: intermediate 4783 4784 Fortran Notes: 4785 `points` and `converedPoints` must be declared with 4786 .vb 4787 PetscInt, pointer :: points(:) 4788 PetscInt, pointer :: coveredPints(:) 4789 .ve 4790 4791 The `numCoveredPoints` argument is not present in the Fortran binding. 4792 4793 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4794 @*/ 4795 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4796 { 4797 PetscInt *offsets, **closures; 4798 PetscInt *join[2]; 4799 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4800 PetscInt p, d, c, m, ms; 4801 4802 PetscFunctionBegin; 4803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4804 PetscAssertPointer(points, 3); 4805 PetscAssertPointer(numCoveredPoints, 4); 4806 PetscAssertPointer(coveredPoints, 5); 4807 4808 PetscCall(DMPlexGetDepth(dm, &depth)); 4809 PetscCall(PetscCalloc1(numPoints, &closures)); 4810 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4811 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4812 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4813 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4814 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4815 4816 for (p = 0; p < numPoints; ++p) { 4817 PetscInt closureSize; 4818 4819 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4820 4821 offsets[p * (depth + 2) + 0] = 0; 4822 for (d = 0; d < depth + 1; ++d) { 4823 PetscInt pStart, pEnd, i; 4824 4825 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4826 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4827 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4828 offsets[p * (depth + 2) + d + 1] = i; 4829 break; 4830 } 4831 } 4832 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4833 } 4834 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); 4835 } 4836 for (d = 0; d < depth + 1; ++d) { 4837 PetscInt dof; 4838 4839 /* Copy in support of first point */ 4840 dof = offsets[d + 1] - offsets[d]; 4841 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4842 /* Check each successive cone */ 4843 for (p = 1; p < numPoints && joinSize; ++p) { 4844 PetscInt newJoinSize = 0; 4845 4846 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4847 for (c = 0; c < dof; ++c) { 4848 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4849 4850 for (m = 0; m < joinSize; ++m) { 4851 if (point == join[i][m]) { 4852 join[1 - i][newJoinSize++] = point; 4853 break; 4854 } 4855 } 4856 } 4857 joinSize = newJoinSize; 4858 i = 1 - i; 4859 } 4860 if (joinSize) break; 4861 } 4862 *numCoveredPoints = joinSize; 4863 *coveredPoints = join[i]; 4864 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4865 PetscCall(PetscFree(closures)); 4866 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4867 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4868 PetscFunctionReturn(PETSC_SUCCESS); 4869 } 4870 4871 /*@C 4872 DMPlexGetMeet - Get an array for the meet of the set of points 4873 4874 Not Collective 4875 4876 Input Parameters: 4877 + dm - The `DMPLEX` object 4878 . numPoints - The number of input points for the meet 4879 - points - The input points, of length `numPoints` 4880 4881 Output Parameters: 4882 + numCoveringPoints - The number of points in the meet 4883 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4884 4885 Level: intermediate 4886 4887 Note: 4888 Currently, this is restricted to a single level meet 4889 4890 Fortran Notes: 4891 `coveringPoints` must be declared with 4892 .vb 4893 PetscInt, pointer :: coveringPoints(:) 4894 .ve 4895 4896 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4897 4898 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4899 @*/ 4900 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4901 { 4902 DM_Plex *mesh = (DM_Plex *)dm->data; 4903 PetscInt *meet[2]; 4904 PetscInt meetSize, i = 0; 4905 PetscInt dof, off, p, c, m; 4906 PetscInt maxConeSize; 4907 4908 PetscFunctionBegin; 4909 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4910 PetscAssertPointer(points, 3); 4911 PetscAssertPointer(numCoveringPoints, 4); 4912 PetscAssertPointer(coveringPoints, 5); 4913 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4914 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4915 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4916 /* Copy in cone of first point */ 4917 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4918 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4919 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4920 /* Check each successive cone */ 4921 for (p = 1; p < numPoints; ++p) { 4922 PetscInt newMeetSize = 0; 4923 4924 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4925 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4926 for (c = 0; c < dof; ++c) { 4927 const PetscInt point = mesh->cones[off + c]; 4928 4929 for (m = 0; m < meetSize; ++m) { 4930 if (point == meet[i][m]) { 4931 meet[1 - i][newMeetSize++] = point; 4932 break; 4933 } 4934 } 4935 } 4936 meetSize = newMeetSize; 4937 i = 1 - i; 4938 } 4939 *numCoveringPoints = meetSize; 4940 *coveringPoints = meet[i]; 4941 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4942 PetscFunctionReturn(PETSC_SUCCESS); 4943 } 4944 4945 /*@C 4946 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 4947 4948 Not Collective 4949 4950 Input Parameters: 4951 + dm - The `DMPLEX` object 4952 . numPoints - The number of input points for the meet 4953 - points - The input points 4954 4955 Output Parameters: 4956 + numCoveredPoints - The number of points in the meet 4957 - coveredPoints - The points in the meet 4958 4959 Level: intermediate 4960 4961 Fortran Notes: 4962 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4963 4964 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4965 @*/ 4966 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4967 { 4968 PetscFunctionBegin; 4969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4970 if (points) PetscAssertPointer(points, 3); 4971 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4972 PetscAssertPointer(coveredPoints, 5); 4973 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4974 if (numCoveredPoints) *numCoveredPoints = 0; 4975 PetscFunctionReturn(PETSC_SUCCESS); 4976 } 4977 4978 /*@C 4979 DMPlexGetFullMeet - Get an array for the meet of the set of points 4980 4981 Not Collective 4982 4983 Input Parameters: 4984 + dm - The `DMPLEX` object 4985 . numPoints - The number of input points for the meet 4986 - points - The input points, of length `numPoints` 4987 4988 Output Parameters: 4989 + numCoveredPoints - The number of points in the meet 4990 - coveredPoints - The points in the meet, of length `numCoveredPoints` 4991 4992 Level: intermediate 4993 4994 Fortran Notes: 4995 `points` and `coveredPoints` must be declared with 4996 .vb 4997 PetscInt, pointer :: points(:) 4998 PetscInt, pointer :: coveredPoints(:) 4999 .ve 5000 5001 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5002 5003 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5004 @*/ 5005 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 5006 { 5007 PetscInt *offsets, **closures; 5008 PetscInt *meet[2]; 5009 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5010 PetscInt p, h, c, m, mc; 5011 5012 PetscFunctionBegin; 5013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5014 PetscAssertPointer(points, 3); 5015 PetscAssertPointer(numCoveredPoints, 4); 5016 PetscAssertPointer(coveredPoints, 5); 5017 5018 PetscCall(DMPlexGetDepth(dm, &height)); 5019 PetscCall(PetscMalloc1(numPoints, &closures)); 5020 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5021 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5022 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5023 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5024 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5025 5026 for (p = 0; p < numPoints; ++p) { 5027 PetscInt closureSize; 5028 5029 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5030 5031 offsets[p * (height + 2) + 0] = 0; 5032 for (h = 0; h < height + 1; ++h) { 5033 PetscInt pStart, pEnd, i; 5034 5035 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5036 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5037 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5038 offsets[p * (height + 2) + h + 1] = i; 5039 break; 5040 } 5041 } 5042 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5043 } 5044 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); 5045 } 5046 for (h = 0; h < height + 1; ++h) { 5047 PetscInt dof; 5048 5049 /* Copy in cone of first point */ 5050 dof = offsets[h + 1] - offsets[h]; 5051 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5052 /* Check each successive cone */ 5053 for (p = 1; p < numPoints && meetSize; ++p) { 5054 PetscInt newMeetSize = 0; 5055 5056 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5057 for (c = 0; c < dof; ++c) { 5058 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5059 5060 for (m = 0; m < meetSize; ++m) { 5061 if (point == meet[i][m]) { 5062 meet[1 - i][newMeetSize++] = point; 5063 break; 5064 } 5065 } 5066 } 5067 meetSize = newMeetSize; 5068 i = 1 - i; 5069 } 5070 if (meetSize) break; 5071 } 5072 *numCoveredPoints = meetSize; 5073 *coveredPoints = meet[i]; 5074 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5075 PetscCall(PetscFree(closures)); 5076 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5077 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5078 PetscFunctionReturn(PETSC_SUCCESS); 5079 } 5080 5081 /*@C 5082 DMPlexEqual - Determine if two `DM` have the same topology 5083 5084 Not Collective 5085 5086 Input Parameters: 5087 + dmA - A `DMPLEX` object 5088 - dmB - A `DMPLEX` object 5089 5090 Output Parameter: 5091 . equal - `PETSC_TRUE` if the topologies are identical 5092 5093 Level: intermediate 5094 5095 Note: 5096 We are not solving graph isomorphism, so we do not permute. 5097 5098 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5099 @*/ 5100 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5101 { 5102 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5103 5104 PetscFunctionBegin; 5105 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5106 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5107 PetscAssertPointer(equal, 3); 5108 5109 *equal = PETSC_FALSE; 5110 PetscCall(DMPlexGetDepth(dmA, &depth)); 5111 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5112 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5113 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5114 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5115 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5116 for (p = pStart; p < pEnd; ++p) { 5117 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5118 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5119 5120 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5121 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5122 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5123 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5124 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5125 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5126 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5127 for (c = 0; c < coneSize; ++c) { 5128 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5129 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5130 } 5131 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5132 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5133 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5134 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5135 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5136 for (s = 0; s < supportSize; ++s) { 5137 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5138 } 5139 } 5140 *equal = PETSC_TRUE; 5141 PetscFunctionReturn(PETSC_SUCCESS); 5142 } 5143 5144 /*@C 5145 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5146 5147 Not Collective 5148 5149 Input Parameters: 5150 + dm - The `DMPLEX` 5151 . cellDim - The cell dimension 5152 - numCorners - The number of vertices on a cell 5153 5154 Output Parameter: 5155 . numFaceVertices - The number of vertices on a face 5156 5157 Level: developer 5158 5159 Note: 5160 Of course this can only work for a restricted set of symmetric shapes 5161 5162 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5163 @*/ 5164 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5165 { 5166 MPI_Comm comm; 5167 5168 PetscFunctionBegin; 5169 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5170 PetscAssertPointer(numFaceVertices, 4); 5171 switch (cellDim) { 5172 case 0: 5173 *numFaceVertices = 0; 5174 break; 5175 case 1: 5176 *numFaceVertices = 1; 5177 break; 5178 case 2: 5179 switch (numCorners) { 5180 case 3: /* triangle */ 5181 *numFaceVertices = 2; /* Edge has 2 vertices */ 5182 break; 5183 case 4: /* quadrilateral */ 5184 *numFaceVertices = 2; /* Edge has 2 vertices */ 5185 break; 5186 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5187 *numFaceVertices = 3; /* Edge has 3 vertices */ 5188 break; 5189 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5190 *numFaceVertices = 3; /* Edge has 3 vertices */ 5191 break; 5192 default: 5193 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5194 } 5195 break; 5196 case 3: 5197 switch (numCorners) { 5198 case 4: /* tetradehdron */ 5199 *numFaceVertices = 3; /* Face has 3 vertices */ 5200 break; 5201 case 6: /* tet cohesive cells */ 5202 *numFaceVertices = 4; /* Face has 4 vertices */ 5203 break; 5204 case 8: /* hexahedron */ 5205 *numFaceVertices = 4; /* Face has 4 vertices */ 5206 break; 5207 case 9: /* tet cohesive Lagrange cells */ 5208 *numFaceVertices = 6; /* Face has 6 vertices */ 5209 break; 5210 case 10: /* quadratic tetrahedron */ 5211 *numFaceVertices = 6; /* Face has 6 vertices */ 5212 break; 5213 case 12: /* hex cohesive Lagrange cells */ 5214 *numFaceVertices = 6; /* Face has 6 vertices */ 5215 break; 5216 case 18: /* quadratic tet cohesive Lagrange cells */ 5217 *numFaceVertices = 6; /* Face has 6 vertices */ 5218 break; 5219 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5220 *numFaceVertices = 9; /* Face has 9 vertices */ 5221 break; 5222 default: 5223 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5224 } 5225 break; 5226 default: 5227 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5228 } 5229 PetscFunctionReturn(PETSC_SUCCESS); 5230 } 5231 5232 /*@ 5233 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5234 5235 Not Collective 5236 5237 Input Parameter: 5238 . dm - The `DMPLEX` object 5239 5240 Output Parameter: 5241 . depthLabel - The `DMLabel` recording point depth 5242 5243 Level: developer 5244 5245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5246 @*/ 5247 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5248 { 5249 PetscFunctionBegin; 5250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5251 PetscAssertPointer(depthLabel, 2); 5252 *depthLabel = dm->depthLabel; 5253 PetscFunctionReturn(PETSC_SUCCESS); 5254 } 5255 5256 /*@ 5257 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5258 5259 Not Collective 5260 5261 Input Parameter: 5262 . dm - The `DMPLEX` object 5263 5264 Output Parameter: 5265 . depth - The number of strata (breadth first levels) in the DAG 5266 5267 Level: developer 5268 5269 Notes: 5270 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5271 5272 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5273 5274 An empty mesh gives -1. 5275 5276 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5277 @*/ 5278 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5279 { 5280 DM_Plex *mesh = (DM_Plex *)dm->data; 5281 DMLabel label; 5282 PetscInt d = 0; 5283 5284 PetscFunctionBegin; 5285 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5286 PetscAssertPointer(depth, 2); 5287 if (mesh->tr) { 5288 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5289 } else { 5290 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5291 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5292 *depth = d - 1; 5293 } 5294 PetscFunctionReturn(PETSC_SUCCESS); 5295 } 5296 5297 /*@ 5298 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5299 5300 Not Collective 5301 5302 Input Parameters: 5303 + dm - The `DMPLEX` object 5304 - depth - The requested depth 5305 5306 Output Parameters: 5307 + start - The first point at this `depth` 5308 - end - One beyond the last point at this `depth` 5309 5310 Level: developer 5311 5312 Notes: 5313 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5314 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5315 higher dimension, e.g., "edges". 5316 5317 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5318 @*/ 5319 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5320 { 5321 DM_Plex *mesh = (DM_Plex *)dm->data; 5322 DMLabel label; 5323 PetscInt pStart, pEnd; 5324 5325 PetscFunctionBegin; 5326 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5327 if (start) { 5328 PetscAssertPointer(start, 3); 5329 *start = 0; 5330 } 5331 if (end) { 5332 PetscAssertPointer(end, 4); 5333 *end = 0; 5334 } 5335 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5336 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5337 if (depth < 0) { 5338 if (start) *start = pStart; 5339 if (end) *end = pEnd; 5340 PetscFunctionReturn(PETSC_SUCCESS); 5341 } 5342 if (mesh->tr) { 5343 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5344 } else { 5345 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5346 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5347 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5348 } 5349 PetscFunctionReturn(PETSC_SUCCESS); 5350 } 5351 5352 /*@ 5353 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5354 5355 Not Collective 5356 5357 Input Parameters: 5358 + dm - The `DMPLEX` object 5359 - height - The requested height 5360 5361 Output Parameters: 5362 + start - The first point at this `height` 5363 - end - One beyond the last point at this `height` 5364 5365 Level: developer 5366 5367 Notes: 5368 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5369 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5370 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5371 5372 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5373 @*/ 5374 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5375 { 5376 DMLabel label; 5377 PetscInt depth, pStart, pEnd; 5378 5379 PetscFunctionBegin; 5380 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5381 if (start) { 5382 PetscAssertPointer(start, 3); 5383 *start = 0; 5384 } 5385 if (end) { 5386 PetscAssertPointer(end, 4); 5387 *end = 0; 5388 } 5389 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5390 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5391 if (height < 0) { 5392 if (start) *start = pStart; 5393 if (end) *end = pEnd; 5394 PetscFunctionReturn(PETSC_SUCCESS); 5395 } 5396 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5397 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5398 else PetscCall(DMGetDimension(dm, &depth)); 5399 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5400 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5401 PetscFunctionReturn(PETSC_SUCCESS); 5402 } 5403 5404 /*@ 5405 DMPlexGetPointDepth - Get the `depth` of a given point 5406 5407 Not Collective 5408 5409 Input Parameters: 5410 + dm - The `DMPLEX` object 5411 - point - The point 5412 5413 Output Parameter: 5414 . depth - The depth of the `point` 5415 5416 Level: intermediate 5417 5418 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5419 @*/ 5420 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5421 { 5422 PetscFunctionBegin; 5423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5424 PetscAssertPointer(depth, 3); 5425 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5426 PetscFunctionReturn(PETSC_SUCCESS); 5427 } 5428 5429 /*@ 5430 DMPlexGetPointHeight - Get the `height` of a given point 5431 5432 Not Collective 5433 5434 Input Parameters: 5435 + dm - The `DMPLEX` object 5436 - point - The point 5437 5438 Output Parameter: 5439 . height - The height of the `point` 5440 5441 Level: intermediate 5442 5443 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5444 @*/ 5445 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5446 { 5447 PetscInt n, pDepth; 5448 5449 PetscFunctionBegin; 5450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5451 PetscAssertPointer(height, 3); 5452 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5453 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5454 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5455 PetscFunctionReturn(PETSC_SUCCESS); 5456 } 5457 5458 /*@ 5459 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5460 5461 Not Collective 5462 5463 Input Parameter: 5464 . dm - The `DMPLEX` object 5465 5466 Output Parameter: 5467 . celltypeLabel - The `DMLabel` recording cell polytope type 5468 5469 Level: developer 5470 5471 Note: 5472 This function will trigger automatica computation of cell types. This can be disabled by calling 5473 `DMCreateLabel`(dm, "celltype") beforehand. 5474 5475 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5476 @*/ 5477 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5478 { 5479 PetscFunctionBegin; 5480 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5481 PetscAssertPointer(celltypeLabel, 2); 5482 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5483 *celltypeLabel = dm->celltypeLabel; 5484 PetscFunctionReturn(PETSC_SUCCESS); 5485 } 5486 5487 /*@ 5488 DMPlexGetCellType - Get the polytope type of a given cell 5489 5490 Not Collective 5491 5492 Input Parameters: 5493 + dm - The `DMPLEX` object 5494 - cell - The cell 5495 5496 Output Parameter: 5497 . celltype - The polytope type of the cell 5498 5499 Level: intermediate 5500 5501 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5502 @*/ 5503 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5504 { 5505 DM_Plex *mesh = (DM_Plex *)dm->data; 5506 DMLabel label; 5507 PetscInt ct; 5508 5509 PetscFunctionBegin; 5510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5511 PetscAssertPointer(celltype, 3); 5512 if (mesh->tr) { 5513 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5514 } else { 5515 PetscInt pStart, pEnd; 5516 5517 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5518 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5519 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5520 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5521 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5522 for (PetscInt p = pStart; p < pEnd; p++) { 5523 PetscCall(DMLabelGetValue(label, p, &ct)); 5524 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5525 } 5526 } 5527 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5528 if (PetscDefined(USE_DEBUG)) { 5529 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5530 PetscCall(DMLabelGetValue(label, cell, &ct)); 5531 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5532 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5533 } 5534 } 5535 PetscFunctionReturn(PETSC_SUCCESS); 5536 } 5537 5538 /*@ 5539 DMPlexSetCellType - Set the polytope type of a given cell 5540 5541 Not Collective 5542 5543 Input Parameters: 5544 + dm - The `DMPLEX` object 5545 . cell - The cell 5546 - celltype - The polytope type of the cell 5547 5548 Level: advanced 5549 5550 Note: 5551 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5552 is executed. This function will override the computed type. However, if automatic classification will not succeed 5553 and a user wants to manually specify all types, the classification must be disabled by calling 5554 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5555 5556 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5557 @*/ 5558 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5559 { 5560 DM_Plex *mesh = (DM_Plex *)dm->data; 5561 DMLabel label; 5562 PetscInt pStart, pEnd; 5563 5564 PetscFunctionBegin; 5565 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5566 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5567 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5568 PetscCall(DMLabelSetValue(label, cell, celltype)); 5569 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5570 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5571 PetscFunctionReturn(PETSC_SUCCESS); 5572 } 5573 5574 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5575 { 5576 PetscSection section; 5577 PetscInt maxHeight; 5578 const char *prefix; 5579 5580 PetscFunctionBegin; 5581 PetscCall(DMClone(dm, cdm)); 5582 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5583 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5584 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5585 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5586 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5587 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5588 PetscCall(DMSetLocalSection(*cdm, section)); 5589 PetscCall(PetscSectionDestroy(§ion)); 5590 5591 PetscCall(DMSetNumFields(*cdm, 1)); 5592 PetscCall(DMCreateDS(*cdm)); 5593 (*cdm)->cloneOpts = PETSC_TRUE; 5594 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5595 PetscFunctionReturn(PETSC_SUCCESS); 5596 } 5597 5598 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5599 { 5600 Vec coordsLocal, cellCoordsLocal; 5601 DM coordsDM, cellCoordsDM; 5602 5603 PetscFunctionBegin; 5604 *field = NULL; 5605 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5606 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5607 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5608 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5609 if (coordsLocal && coordsDM) { 5610 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5611 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5612 } 5613 PetscFunctionReturn(PETSC_SUCCESS); 5614 } 5615 5616 /*@C 5617 DMPlexGetConeSection - Return a section which describes the layout of cone data 5618 5619 Not Collective 5620 5621 Input Parameter: 5622 . dm - The `DMPLEX` object 5623 5624 Output Parameter: 5625 . section - The `PetscSection` object 5626 5627 Level: developer 5628 5629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5630 @*/ 5631 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5632 { 5633 DM_Plex *mesh = (DM_Plex *)dm->data; 5634 5635 PetscFunctionBegin; 5636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5637 if (section) *section = mesh->coneSection; 5638 PetscFunctionReturn(PETSC_SUCCESS); 5639 } 5640 5641 /*@C 5642 DMPlexGetSupportSection - Return a section which describes the layout of support data 5643 5644 Not Collective 5645 5646 Input Parameter: 5647 . dm - The `DMPLEX` object 5648 5649 Output Parameter: 5650 . section - The `PetscSection` object 5651 5652 Level: developer 5653 5654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5655 @*/ 5656 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5657 { 5658 DM_Plex *mesh = (DM_Plex *)dm->data; 5659 5660 PetscFunctionBegin; 5661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5662 if (section) *section = mesh->supportSection; 5663 PetscFunctionReturn(PETSC_SUCCESS); 5664 } 5665 5666 /*@C 5667 DMPlexGetCones - Return cone data 5668 5669 Not Collective 5670 5671 Input Parameter: 5672 . dm - The `DMPLEX` object 5673 5674 Output Parameter: 5675 . cones - The cone for each point 5676 5677 Level: developer 5678 5679 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5680 @*/ 5681 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5682 { 5683 DM_Plex *mesh = (DM_Plex *)dm->data; 5684 5685 PetscFunctionBegin; 5686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5687 if (cones) *cones = mesh->cones; 5688 PetscFunctionReturn(PETSC_SUCCESS); 5689 } 5690 5691 /*@C 5692 DMPlexGetConeOrientations - Return cone orientation data 5693 5694 Not Collective 5695 5696 Input Parameter: 5697 . dm - The `DMPLEX` object 5698 5699 Output Parameter: 5700 . coneOrientations - The array of cone orientations for all points 5701 5702 Level: developer 5703 5704 Notes: 5705 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5706 as returned by `DMPlexGetConeOrientation()`. 5707 5708 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5709 5710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5711 @*/ 5712 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5713 { 5714 DM_Plex *mesh = (DM_Plex *)dm->data; 5715 5716 PetscFunctionBegin; 5717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5718 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5719 PetscFunctionReturn(PETSC_SUCCESS); 5720 } 5721 5722 /******************************** FEM Support **********************************/ 5723 5724 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5725 { 5726 PetscInt depth; 5727 5728 PetscFunctionBegin; 5729 PetscCall(DMPlexGetDepth(plex, &depth)); 5730 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5731 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5732 PetscFunctionReturn(PETSC_SUCCESS); 5733 } 5734 5735 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5736 { 5737 PetscInt depth; 5738 5739 PetscFunctionBegin; 5740 PetscCall(DMPlexGetDepth(plex, &depth)); 5741 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5742 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5743 PetscFunctionReturn(PETSC_SUCCESS); 5744 } 5745 5746 /* 5747 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5748 representing a line in the section. 5749 */ 5750 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5751 { 5752 PetscObject obj; 5753 PetscClassId id; 5754 PetscFE fe = NULL; 5755 5756 PetscFunctionBeginHot; 5757 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5758 PetscCall(DMGetField(dm, field, NULL, &obj)); 5759 PetscCall(PetscObjectGetClassId(obj, &id)); 5760 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5761 5762 if (!fe) { 5763 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5764 /* An order k SEM disc has k-1 dofs on an edge */ 5765 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5766 *k = *k / *Nc + 1; 5767 } else { 5768 PetscInt dual_space_size, dim; 5769 PetscDualSpace dsp; 5770 5771 PetscCall(DMGetDimension(dm, &dim)); 5772 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5773 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5774 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5775 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5776 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5777 } 5778 PetscFunctionReturn(PETSC_SUCCESS); 5779 } 5780 5781 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5782 { 5783 PetscFunctionBeginHot; 5784 if (tensor) { 5785 *dof = PetscPowInt(k + 1, dim); 5786 } else { 5787 switch (dim) { 5788 case 1: 5789 *dof = k + 1; 5790 break; 5791 case 2: 5792 *dof = ((k + 1) * (k + 2)) / 2; 5793 break; 5794 case 3: 5795 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5796 break; 5797 default: 5798 *dof = 0; 5799 } 5800 } 5801 PetscFunctionReturn(PETSC_SUCCESS); 5802 } 5803 5804 /*@ 5805 5806 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5807 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5808 section provided (or the section of the `DM`). 5809 5810 Input Parameters: 5811 + dm - The `DM` 5812 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5813 - section - The `PetscSection` to reorder, or `NULL` for the default section 5814 5815 Example: 5816 A typical interpolated single-quad mesh might order points as 5817 .vb 5818 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5819 5820 v4 -- e6 -- v3 5821 | | 5822 e7 c0 e8 5823 | | 5824 v1 -- e5 -- v2 5825 .ve 5826 5827 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5828 dofs in the order of points, e.g., 5829 .vb 5830 c0 -> [0,1,2,3] 5831 v1 -> [4] 5832 ... 5833 e5 -> [8, 9] 5834 .ve 5835 5836 which corresponds to the dofs 5837 .vb 5838 6 10 11 7 5839 13 2 3 15 5840 12 0 1 14 5841 4 8 9 5 5842 .ve 5843 5844 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5845 .vb 5846 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5847 .ve 5848 5849 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5850 .vb 5851 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5852 .ve 5853 5854 Level: developer 5855 5856 Notes: 5857 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5858 degree of the basis. 5859 5860 This is required to run with libCEED. 5861 5862 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5863 @*/ 5864 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5865 { 5866 DMLabel label; 5867 PetscInt dim, depth = -1, eStart = -1, Nf; 5868 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5869 5870 PetscFunctionBegin; 5871 PetscCall(DMGetDimension(dm, &dim)); 5872 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5873 if (point < 0) { 5874 PetscInt sStart, sEnd; 5875 5876 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5877 point = sEnd - sStart ? sStart : point; 5878 } 5879 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5880 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5881 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5882 if (depth == 1) { 5883 eStart = point; 5884 } else if (depth == dim) { 5885 const PetscInt *cone; 5886 5887 PetscCall(DMPlexGetCone(dm, point, &cone)); 5888 if (dim == 2) eStart = cone[0]; 5889 else if (dim == 3) { 5890 const PetscInt *cone2; 5891 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5892 eStart = cone2[0]; 5893 } 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); 5894 } 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); 5895 5896 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5897 for (PetscInt d = 1; d <= dim; d++) { 5898 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5899 PetscInt *perm; 5900 5901 for (f = 0; f < Nf; ++f) { 5902 PetscInt dof; 5903 5904 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5905 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5906 if (!continuous && d < dim) continue; 5907 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5908 size += dof * Nc; 5909 } 5910 PetscCall(PetscMalloc1(size, &perm)); 5911 for (f = 0; f < Nf; ++f) { 5912 switch (d) { 5913 case 1: 5914 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5915 if (!continuous && d < dim) continue; 5916 /* 5917 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5918 We want [ vtx0; edge of length k-1; vtx1 ] 5919 */ 5920 if (continuous) { 5921 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5922 for (i = 0; i < k - 1; i++) 5923 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5924 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5925 foffset = offset; 5926 } else { 5927 PetscInt dof; 5928 5929 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5930 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5931 foffset = offset; 5932 } 5933 break; 5934 case 2: 5935 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5936 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5937 if (!continuous && d < dim) continue; 5938 /* The SEM order is 5939 5940 v_lb, {e_b}, v_rb, 5941 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5942 v_lt, reverse {e_t}, v_rt 5943 */ 5944 if (continuous) { 5945 const PetscInt of = 0; 5946 const PetscInt oeb = of + PetscSqr(k - 1); 5947 const PetscInt oer = oeb + (k - 1); 5948 const PetscInt oet = oer + (k - 1); 5949 const PetscInt oel = oet + (k - 1); 5950 const PetscInt ovlb = oel + (k - 1); 5951 const PetscInt ovrb = ovlb + 1; 5952 const PetscInt ovrt = ovrb + 1; 5953 const PetscInt ovlt = ovrt + 1; 5954 PetscInt o; 5955 5956 /* bottom */ 5957 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5958 for (o = oeb; o < oer; ++o) 5959 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5960 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5961 /* middle */ 5962 for (i = 0; i < k - 1; ++i) { 5963 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5964 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5965 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5966 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5967 } 5968 /* top */ 5969 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5970 for (o = oel - 1; o >= oet; --o) 5971 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5972 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5973 foffset = offset; 5974 } else { 5975 PetscInt dof; 5976 5977 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5978 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5979 foffset = offset; 5980 } 5981 break; 5982 case 3: 5983 /* The original hex closure is 5984 5985 {c, 5986 f_b, f_t, f_f, f_b, f_r, f_l, 5987 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5988 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5989 */ 5990 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5991 if (!continuous && d < dim) continue; 5992 /* The SEM order is 5993 Bottom Slice 5994 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5995 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5996 v_blb, {e_bb}, v_brb, 5997 5998 Middle Slice (j) 5999 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6000 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6001 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6002 6003 Top Slice 6004 v_tlf, {e_tf}, v_trf, 6005 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6006 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6007 */ 6008 if (continuous) { 6009 const PetscInt oc = 0; 6010 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6011 const PetscInt oft = ofb + PetscSqr(k - 1); 6012 const PetscInt off = oft + PetscSqr(k - 1); 6013 const PetscInt ofk = off + PetscSqr(k - 1); 6014 const PetscInt ofr = ofk + PetscSqr(k - 1); 6015 const PetscInt ofl = ofr + PetscSqr(k - 1); 6016 const PetscInt oebl = ofl + PetscSqr(k - 1); 6017 const PetscInt oebb = oebl + (k - 1); 6018 const PetscInt oebr = oebb + (k - 1); 6019 const PetscInt oebf = oebr + (k - 1); 6020 const PetscInt oetf = oebf + (k - 1); 6021 const PetscInt oetr = oetf + (k - 1); 6022 const PetscInt oetb = oetr + (k - 1); 6023 const PetscInt oetl = oetb + (k - 1); 6024 const PetscInt oerf = oetl + (k - 1); 6025 const PetscInt oelf = oerf + (k - 1); 6026 const PetscInt oelb = oelf + (k - 1); 6027 const PetscInt oerb = oelb + (k - 1); 6028 const PetscInt ovblf = oerb + (k - 1); 6029 const PetscInt ovblb = ovblf + 1; 6030 const PetscInt ovbrb = ovblb + 1; 6031 const PetscInt ovbrf = ovbrb + 1; 6032 const PetscInt ovtlf = ovbrf + 1; 6033 const PetscInt ovtrf = ovtlf + 1; 6034 const PetscInt ovtrb = ovtrf + 1; 6035 const PetscInt ovtlb = ovtrb + 1; 6036 PetscInt o, n; 6037 6038 /* Bottom Slice */ 6039 /* bottom */ 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6041 for (o = oetf - 1; o >= oebf; --o) 6042 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6044 /* middle */ 6045 for (i = 0; i < k - 1; ++i) { 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6047 for (n = 0; n < k - 1; ++n) { 6048 o = ofb + n * (k - 1) + i; 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6050 } 6051 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6052 } 6053 /* top */ 6054 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6055 for (o = oebb; o < oebr; ++o) 6056 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6057 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6058 6059 /* Middle Slice */ 6060 for (j = 0; j < k - 1; ++j) { 6061 /* bottom */ 6062 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6063 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++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] = (oerf + j) * Nc + c + foffset; 6066 /* middle */ 6067 for (i = 0; i < k - 1; ++i) { 6068 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6069 for (n = 0; n < k - 1; ++n) 6070 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6071 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6072 } 6073 /* top */ 6074 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6075 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6076 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6077 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6078 } 6079 6080 /* Top Slice */ 6081 /* bottom */ 6082 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6083 for (o = oetf; o < oetr; ++o) 6084 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6085 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6086 /* middle */ 6087 for (i = 0; i < k - 1; ++i) { 6088 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6089 for (n = 0; n < k - 1; ++n) 6090 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6091 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6092 } 6093 /* top */ 6094 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6095 for (o = oetl - 1; o >= oetb; --o) 6096 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6097 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6098 6099 foffset = offset; 6100 } else { 6101 PetscInt dof; 6102 6103 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6104 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6105 foffset = offset; 6106 } 6107 break; 6108 default: 6109 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6110 } 6111 } 6112 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6113 /* Check permutation */ 6114 { 6115 PetscInt *check; 6116 6117 PetscCall(PetscMalloc1(size, &check)); 6118 for (i = 0; i < size; ++i) { 6119 check[i] = -1; 6120 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6121 } 6122 for (i = 0; i < size; ++i) check[perm[i]] = i; 6123 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6124 PetscCall(PetscFree(check)); 6125 } 6126 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6127 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6128 PetscInt *loc_perm; 6129 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6130 for (PetscInt i = 0; i < size; i++) { 6131 loc_perm[i] = perm[i]; 6132 loc_perm[size + i] = size + perm[i]; 6133 } 6134 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6135 } 6136 } 6137 PetscFunctionReturn(PETSC_SUCCESS); 6138 } 6139 6140 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6141 { 6142 PetscDS prob; 6143 PetscInt depth, Nf, h; 6144 DMLabel label; 6145 6146 PetscFunctionBeginHot; 6147 PetscCall(DMGetDS(dm, &prob)); 6148 Nf = prob->Nf; 6149 label = dm->depthLabel; 6150 *dspace = NULL; 6151 if (field < Nf) { 6152 PetscObject disc = prob->disc[field]; 6153 6154 if (disc->classid == PETSCFE_CLASSID) { 6155 PetscDualSpace dsp; 6156 6157 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6158 PetscCall(DMLabelGetNumValues(label, &depth)); 6159 PetscCall(DMLabelGetValue(label, point, &h)); 6160 h = depth - 1 - h; 6161 if (h) { 6162 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6163 } else { 6164 *dspace = dsp; 6165 } 6166 } 6167 } 6168 PetscFunctionReturn(PETSC_SUCCESS); 6169 } 6170 6171 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6172 { 6173 PetscScalar *array; 6174 const PetscScalar *vArray; 6175 const PetscInt *cone, *coneO; 6176 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6177 6178 PetscFunctionBeginHot; 6179 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6180 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6181 PetscCall(DMPlexGetCone(dm, point, &cone)); 6182 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6183 if (!values || !*values) { 6184 if ((point >= pStart) && (point < pEnd)) { 6185 PetscInt dof; 6186 6187 PetscCall(PetscSectionGetDof(section, point, &dof)); 6188 size += dof; 6189 } 6190 for (p = 0; p < numPoints; ++p) { 6191 const PetscInt cp = cone[p]; 6192 PetscInt dof; 6193 6194 if ((cp < pStart) || (cp >= pEnd)) continue; 6195 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6196 size += dof; 6197 } 6198 if (!values) { 6199 if (csize) *csize = size; 6200 PetscFunctionReturn(PETSC_SUCCESS); 6201 } 6202 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6203 } else { 6204 array = *values; 6205 } 6206 size = 0; 6207 PetscCall(VecGetArrayRead(v, &vArray)); 6208 if ((point >= pStart) && (point < pEnd)) { 6209 PetscInt dof, off, d; 6210 const PetscScalar *varr; 6211 6212 PetscCall(PetscSectionGetDof(section, point, &dof)); 6213 PetscCall(PetscSectionGetOffset(section, point, &off)); 6214 varr = PetscSafePointerPlusOffset(vArray, off); 6215 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6216 size += dof; 6217 } 6218 for (p = 0; p < numPoints; ++p) { 6219 const PetscInt cp = cone[p]; 6220 PetscInt o = coneO[p]; 6221 PetscInt dof, off, d; 6222 const PetscScalar *varr; 6223 6224 if ((cp < pStart) || (cp >= pEnd)) continue; 6225 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6226 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6227 varr = PetscSafePointerPlusOffset(vArray, off); 6228 if (o >= 0) { 6229 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6230 } else { 6231 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6232 } 6233 size += dof; 6234 } 6235 PetscCall(VecRestoreArrayRead(v, &vArray)); 6236 if (!*values) { 6237 if (csize) *csize = size; 6238 *values = array; 6239 } else { 6240 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6241 *csize = size; 6242 } 6243 PetscFunctionReturn(PETSC_SUCCESS); 6244 } 6245 6246 /* Compress out points not in the section */ 6247 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6248 { 6249 const PetscInt np = *numPoints; 6250 PetscInt pStart, pEnd, p, q; 6251 6252 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6253 for (p = 0, q = 0; p < np; ++p) { 6254 const PetscInt r = points[p * 2]; 6255 if ((r >= pStart) && (r < pEnd)) { 6256 points[q * 2] = r; 6257 points[q * 2 + 1] = points[p * 2 + 1]; 6258 ++q; 6259 } 6260 } 6261 *numPoints = q; 6262 return PETSC_SUCCESS; 6263 } 6264 6265 /* Compressed closure does not apply closure permutation */ 6266 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6267 { 6268 const PetscInt *cla = NULL; 6269 PetscInt np, *pts = NULL; 6270 6271 PetscFunctionBeginHot; 6272 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6273 if (!ornt && *clPoints) { 6274 PetscInt dof, off; 6275 6276 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6277 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6278 PetscCall(ISGetIndices(*clPoints, &cla)); 6279 np = dof / 2; 6280 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6281 } else { 6282 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6283 PetscCall(CompressPoints_Private(section, &np, pts)); 6284 } 6285 *numPoints = np; 6286 *points = pts; 6287 *clp = cla; 6288 PetscFunctionReturn(PETSC_SUCCESS); 6289 } 6290 6291 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6292 { 6293 PetscFunctionBeginHot; 6294 if (!*clPoints) { 6295 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6296 } else { 6297 PetscCall(ISRestoreIndices(*clPoints, clp)); 6298 } 6299 *numPoints = 0; 6300 *points = NULL; 6301 *clSec = NULL; 6302 *clPoints = NULL; 6303 *clp = NULL; 6304 PetscFunctionReturn(PETSC_SUCCESS); 6305 } 6306 6307 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6308 { 6309 PetscInt offset = 0, p; 6310 const PetscInt **perms = NULL; 6311 const PetscScalar **flips = NULL; 6312 6313 PetscFunctionBeginHot; 6314 *size = 0; 6315 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6316 for (p = 0; p < numPoints; p++) { 6317 const PetscInt point = points[2 * p]; 6318 const PetscInt *perm = perms ? perms[p] : NULL; 6319 const PetscScalar *flip = flips ? flips[p] : NULL; 6320 PetscInt dof, off, d; 6321 const PetscScalar *varr; 6322 6323 PetscCall(PetscSectionGetDof(section, point, &dof)); 6324 PetscCall(PetscSectionGetOffset(section, point, &off)); 6325 varr = PetscSafePointerPlusOffset(vArray, off); 6326 if (clperm) { 6327 if (perm) { 6328 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6329 } else { 6330 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6331 } 6332 if (flip) { 6333 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6334 } 6335 } else { 6336 if (perm) { 6337 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6338 } else { 6339 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6340 } 6341 if (flip) { 6342 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6343 } 6344 } 6345 offset += dof; 6346 } 6347 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6348 *size = offset; 6349 PetscFunctionReturn(PETSC_SUCCESS); 6350 } 6351 6352 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[]) 6353 { 6354 PetscInt offset = 0, f; 6355 6356 PetscFunctionBeginHot; 6357 *size = 0; 6358 for (f = 0; f < numFields; ++f) { 6359 PetscInt p; 6360 const PetscInt **perms = NULL; 6361 const PetscScalar **flips = NULL; 6362 6363 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6364 for (p = 0; p < numPoints; p++) { 6365 const PetscInt point = points[2 * p]; 6366 PetscInt fdof, foff, b; 6367 const PetscScalar *varr; 6368 const PetscInt *perm = perms ? perms[p] : NULL; 6369 const PetscScalar *flip = flips ? flips[p] : NULL; 6370 6371 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6372 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6373 varr = &vArray[foff]; 6374 if (clperm) { 6375 if (perm) { 6376 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6377 } else { 6378 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6379 } 6380 if (flip) { 6381 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6382 } 6383 } else { 6384 if (perm) { 6385 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6386 } else { 6387 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6388 } 6389 if (flip) { 6390 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6391 } 6392 } 6393 offset += fdof; 6394 } 6395 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6396 } 6397 *size = offset; 6398 PetscFunctionReturn(PETSC_SUCCESS); 6399 } 6400 6401 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6402 { 6403 PetscSection clSection; 6404 IS clPoints; 6405 PetscInt *points = NULL; 6406 const PetscInt *clp, *perm = NULL; 6407 PetscInt depth, numFields, numPoints, asize; 6408 6409 PetscFunctionBeginHot; 6410 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6411 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6412 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6413 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6414 PetscCall(DMPlexGetDepth(dm, &depth)); 6415 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6416 if (depth == 1 && numFields < 2) { 6417 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6418 PetscFunctionReturn(PETSC_SUCCESS); 6419 } 6420 /* Get points */ 6421 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6422 /* Get sizes */ 6423 asize = 0; 6424 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6425 PetscInt dof; 6426 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6427 asize += dof; 6428 } 6429 if (values) { 6430 const PetscScalar *vArray; 6431 PetscInt size; 6432 6433 if (*values) { 6434 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); 6435 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6436 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6437 PetscCall(VecGetArrayRead(v, &vArray)); 6438 /* Get values */ 6439 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6440 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6441 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6442 /* Cleanup array */ 6443 PetscCall(VecRestoreArrayRead(v, &vArray)); 6444 } 6445 if (csize) *csize = asize; 6446 /* Cleanup points */ 6447 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6448 PetscFunctionReturn(PETSC_SUCCESS); 6449 } 6450 6451 /*@C 6452 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6453 6454 Not collective 6455 6456 Input Parameters: 6457 + dm - The `DM` 6458 . section - The section describing the layout in `v`, or `NULL` to use the default section 6459 . v - The local vector 6460 - point - The point in the `DM` 6461 6462 Input/Output Parameters: 6463 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6464 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6465 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6466 6467 Level: intermediate 6468 6469 Notes: 6470 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6471 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6472 assembly function, and a user may already have allocated storage for this operation. 6473 6474 A typical use could be 6475 .vb 6476 values = NULL; 6477 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6478 for (cl = 0; cl < clSize; ++cl) { 6479 <Compute on closure> 6480 } 6481 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6482 .ve 6483 or 6484 .vb 6485 PetscMalloc1(clMaxSize, &values); 6486 for (p = pStart; p < pEnd; ++p) { 6487 clSize = clMaxSize; 6488 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6489 for (cl = 0; cl < clSize; ++cl) { 6490 <Compute on closure> 6491 } 6492 } 6493 PetscFree(values); 6494 .ve 6495 6496 Fortran Notes: 6497 The `csize` argument is not present in the Fortran binding. 6498 6499 `values` must be declared with 6500 .vb 6501 PetscScalar,dimension(:),pointer :: values 6502 .ve 6503 and it will be allocated internally by PETSc to hold the values returned 6504 6505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6506 @*/ 6507 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6508 { 6509 PetscFunctionBeginHot; 6510 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6511 PetscFunctionReturn(PETSC_SUCCESS); 6512 } 6513 6514 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6515 { 6516 DMLabel depthLabel; 6517 PetscSection clSection; 6518 IS clPoints; 6519 PetscScalar *array; 6520 const PetscScalar *vArray; 6521 PetscInt *points = NULL; 6522 const PetscInt *clp, *perm = NULL; 6523 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6524 6525 PetscFunctionBeginHot; 6526 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6527 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6528 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6529 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6530 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6531 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6532 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6533 if (mdepth == 1 && numFields < 2) { 6534 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6535 PetscFunctionReturn(PETSC_SUCCESS); 6536 } 6537 /* Get points */ 6538 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6539 for (clsize = 0, p = 0; p < Np; p++) { 6540 PetscInt dof; 6541 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6542 clsize += dof; 6543 } 6544 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6545 /* Filter points */ 6546 for (p = 0; p < numPoints * 2; p += 2) { 6547 PetscInt dep; 6548 6549 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6550 if (dep != depth) continue; 6551 points[Np * 2 + 0] = points[p]; 6552 points[Np * 2 + 1] = points[p + 1]; 6553 ++Np; 6554 } 6555 /* Get array */ 6556 if (!values || !*values) { 6557 PetscInt asize = 0, dof; 6558 6559 for (p = 0; p < Np * 2; p += 2) { 6560 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6561 asize += dof; 6562 } 6563 if (!values) { 6564 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6565 if (csize) *csize = asize; 6566 PetscFunctionReturn(PETSC_SUCCESS); 6567 } 6568 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6569 } else { 6570 array = *values; 6571 } 6572 PetscCall(VecGetArrayRead(v, &vArray)); 6573 /* Get values */ 6574 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6575 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6576 /* Cleanup points */ 6577 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6578 /* Cleanup array */ 6579 PetscCall(VecRestoreArrayRead(v, &vArray)); 6580 if (!*values) { 6581 if (csize) *csize = size; 6582 *values = array; 6583 } else { 6584 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6585 *csize = size; 6586 } 6587 PetscFunctionReturn(PETSC_SUCCESS); 6588 } 6589 6590 /*@C 6591 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6592 6593 Not collective 6594 6595 Input Parameters: 6596 + dm - The `DM` 6597 . section - The section describing the layout in `v`, or `NULL` to use the default section 6598 . v - The local vector 6599 . point - The point in the `DM` 6600 . csize - The number of values in the closure, or `NULL` 6601 - values - The array of values 6602 6603 Level: intermediate 6604 6605 Note: 6606 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6607 6608 Fortran Note: 6609 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6610 6611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6612 @*/ 6613 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6614 { 6615 PetscInt size = 0; 6616 6617 PetscFunctionBegin; 6618 /* Should work without recalculating size */ 6619 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6620 *values = NULL; 6621 PetscFunctionReturn(PETSC_SUCCESS); 6622 } 6623 6624 static inline void add(PetscScalar *x, PetscScalar y) 6625 { 6626 *x += y; 6627 } 6628 static inline void insert(PetscScalar *x, PetscScalar y) 6629 { 6630 *x = y; 6631 } 6632 6633 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[]) 6634 { 6635 PetscInt cdof; /* The number of constraints on this point */ 6636 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6637 PetscScalar *a; 6638 PetscInt off, cind = 0, k; 6639 6640 PetscFunctionBegin; 6641 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6642 PetscCall(PetscSectionGetOffset(section, point, &off)); 6643 a = &array[off]; 6644 if (!cdof || setBC) { 6645 if (clperm) { 6646 if (perm) { 6647 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6648 } else { 6649 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6650 } 6651 } else { 6652 if (perm) { 6653 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6654 } else { 6655 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6656 } 6657 } 6658 } else { 6659 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6660 if (clperm) { 6661 if (perm) { 6662 for (k = 0; k < dof; ++k) { 6663 if ((cind < cdof) && (k == cdofs[cind])) { 6664 ++cind; 6665 continue; 6666 } 6667 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6668 } 6669 } else { 6670 for (k = 0; k < dof; ++k) { 6671 if ((cind < cdof) && (k == cdofs[cind])) { 6672 ++cind; 6673 continue; 6674 } 6675 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6676 } 6677 } 6678 } else { 6679 if (perm) { 6680 for (k = 0; k < dof; ++k) { 6681 if ((cind < cdof) && (k == cdofs[cind])) { 6682 ++cind; 6683 continue; 6684 } 6685 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6686 } 6687 } else { 6688 for (k = 0; k < dof; ++k) { 6689 if ((cind < cdof) && (k == cdofs[cind])) { 6690 ++cind; 6691 continue; 6692 } 6693 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6694 } 6695 } 6696 } 6697 } 6698 PetscFunctionReturn(PETSC_SUCCESS); 6699 } 6700 6701 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[]) 6702 { 6703 PetscInt cdof; /* The number of constraints on this point */ 6704 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6705 PetscScalar *a; 6706 PetscInt off, cind = 0, k; 6707 6708 PetscFunctionBegin; 6709 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6710 PetscCall(PetscSectionGetOffset(section, point, &off)); 6711 a = &array[off]; 6712 if (cdof) { 6713 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6714 if (clperm) { 6715 if (perm) { 6716 for (k = 0; k < dof; ++k) { 6717 if ((cind < cdof) && (k == cdofs[cind])) { 6718 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6719 cind++; 6720 } 6721 } 6722 } else { 6723 for (k = 0; k < dof; ++k) { 6724 if ((cind < cdof) && (k == cdofs[cind])) { 6725 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6726 cind++; 6727 } 6728 } 6729 } 6730 } else { 6731 if (perm) { 6732 for (k = 0; k < dof; ++k) { 6733 if ((cind < cdof) && (k == cdofs[cind])) { 6734 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6735 cind++; 6736 } 6737 } 6738 } else { 6739 for (k = 0; k < dof; ++k) { 6740 if ((cind < cdof) && (k == cdofs[cind])) { 6741 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6742 cind++; 6743 } 6744 } 6745 } 6746 } 6747 } 6748 PetscFunctionReturn(PETSC_SUCCESS); 6749 } 6750 6751 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[]) 6752 { 6753 PetscScalar *a; 6754 PetscInt fdof, foff, fcdof, foffset = *offset; 6755 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6756 PetscInt cind = 0, b; 6757 6758 PetscFunctionBegin; 6759 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6760 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6761 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6762 a = &array[foff]; 6763 if (!fcdof || setBC) { 6764 if (clperm) { 6765 if (perm) { 6766 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6767 } else { 6768 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6769 } 6770 } else { 6771 if (perm) { 6772 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6773 } else { 6774 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6775 } 6776 } 6777 } else { 6778 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6779 if (clperm) { 6780 if (perm) { 6781 for (b = 0; b < fdof; b++) { 6782 if ((cind < fcdof) && (b == fcdofs[cind])) { 6783 ++cind; 6784 continue; 6785 } 6786 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6787 } 6788 } else { 6789 for (b = 0; b < fdof; b++) { 6790 if ((cind < fcdof) && (b == fcdofs[cind])) { 6791 ++cind; 6792 continue; 6793 } 6794 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6795 } 6796 } 6797 } else { 6798 if (perm) { 6799 for (b = 0; b < fdof; b++) { 6800 if ((cind < fcdof) && (b == fcdofs[cind])) { 6801 ++cind; 6802 continue; 6803 } 6804 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6805 } 6806 } else { 6807 for (b = 0; b < fdof; b++) { 6808 if ((cind < fcdof) && (b == fcdofs[cind])) { 6809 ++cind; 6810 continue; 6811 } 6812 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6813 } 6814 } 6815 } 6816 } 6817 *offset += fdof; 6818 PetscFunctionReturn(PETSC_SUCCESS); 6819 } 6820 6821 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[]) 6822 { 6823 PetscScalar *a; 6824 PetscInt fdof, foff, fcdof, foffset = *offset; 6825 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6826 PetscInt Nc, cind = 0, ncind = 0, b; 6827 PetscBool ncSet, fcSet; 6828 6829 PetscFunctionBegin; 6830 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6831 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6832 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6833 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6834 a = &array[foff]; 6835 if (fcdof) { 6836 /* We just override fcdof and fcdofs with Ncc and comps */ 6837 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6838 if (clperm) { 6839 if (perm) { 6840 if (comps) { 6841 for (b = 0; b < fdof; b++) { 6842 ncSet = fcSet = PETSC_FALSE; 6843 if (b % Nc == comps[ncind]) { 6844 ncind = (ncind + 1) % Ncc; 6845 ncSet = PETSC_TRUE; 6846 } 6847 if ((cind < fcdof) && (b == fcdofs[cind])) { 6848 ++cind; 6849 fcSet = PETSC_TRUE; 6850 } 6851 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6852 } 6853 } else { 6854 for (b = 0; b < fdof; b++) { 6855 if ((cind < fcdof) && (b == fcdofs[cind])) { 6856 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6857 ++cind; 6858 } 6859 } 6860 } 6861 } else { 6862 if (comps) { 6863 for (b = 0; b < fdof; b++) { 6864 ncSet = fcSet = PETSC_FALSE; 6865 if (b % Nc == comps[ncind]) { 6866 ncind = (ncind + 1) % Ncc; 6867 ncSet = PETSC_TRUE; 6868 } 6869 if ((cind < fcdof) && (b == fcdofs[cind])) { 6870 ++cind; 6871 fcSet = PETSC_TRUE; 6872 } 6873 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6874 } 6875 } else { 6876 for (b = 0; b < fdof; b++) { 6877 if ((cind < fcdof) && (b == fcdofs[cind])) { 6878 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6879 ++cind; 6880 } 6881 } 6882 } 6883 } 6884 } else { 6885 if (perm) { 6886 if (comps) { 6887 for (b = 0; b < fdof; b++) { 6888 ncSet = fcSet = PETSC_FALSE; 6889 if (b % Nc == comps[ncind]) { 6890 ncind = (ncind + 1) % Ncc; 6891 ncSet = PETSC_TRUE; 6892 } 6893 if ((cind < fcdof) && (b == fcdofs[cind])) { 6894 ++cind; 6895 fcSet = PETSC_TRUE; 6896 } 6897 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6898 } 6899 } else { 6900 for (b = 0; b < fdof; b++) { 6901 if ((cind < fcdof) && (b == fcdofs[cind])) { 6902 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6903 ++cind; 6904 } 6905 } 6906 } 6907 } else { 6908 if (comps) { 6909 for (b = 0; b < fdof; b++) { 6910 ncSet = fcSet = PETSC_FALSE; 6911 if (b % Nc == comps[ncind]) { 6912 ncind = (ncind + 1) % Ncc; 6913 ncSet = PETSC_TRUE; 6914 } 6915 if ((cind < fcdof) && (b == fcdofs[cind])) { 6916 ++cind; 6917 fcSet = PETSC_TRUE; 6918 } 6919 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6920 } 6921 } else { 6922 for (b = 0; b < fdof; b++) { 6923 if ((cind < fcdof) && (b == fcdofs[cind])) { 6924 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6925 ++cind; 6926 } 6927 } 6928 } 6929 } 6930 } 6931 } 6932 *offset += fdof; 6933 PetscFunctionReturn(PETSC_SUCCESS); 6934 } 6935 6936 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6937 { 6938 PetscScalar *array; 6939 const PetscInt *cone, *coneO; 6940 PetscInt pStart, pEnd, p, numPoints, off, dof; 6941 6942 PetscFunctionBeginHot; 6943 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6944 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6945 PetscCall(DMPlexGetCone(dm, point, &cone)); 6946 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6947 PetscCall(VecGetArray(v, &array)); 6948 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6949 const PetscInt cp = !p ? point : cone[p - 1]; 6950 const PetscInt o = !p ? 0 : coneO[p - 1]; 6951 6952 if ((cp < pStart) || (cp >= pEnd)) { 6953 dof = 0; 6954 continue; 6955 } 6956 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6957 /* ADD_VALUES */ 6958 { 6959 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6960 PetscScalar *a; 6961 PetscInt cdof, coff, cind = 0, k; 6962 6963 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6964 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6965 a = &array[coff]; 6966 if (!cdof) { 6967 if (o >= 0) { 6968 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6969 } else { 6970 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6971 } 6972 } else { 6973 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6974 if (o >= 0) { 6975 for (k = 0; k < dof; ++k) { 6976 if ((cind < cdof) && (k == cdofs[cind])) { 6977 ++cind; 6978 continue; 6979 } 6980 a[k] += values[off + k]; 6981 } 6982 } else { 6983 for (k = 0; k < dof; ++k) { 6984 if ((cind < cdof) && (k == cdofs[cind])) { 6985 ++cind; 6986 continue; 6987 } 6988 a[k] += values[off + dof - k - 1]; 6989 } 6990 } 6991 } 6992 } 6993 } 6994 PetscCall(VecRestoreArray(v, &array)); 6995 PetscFunctionReturn(PETSC_SUCCESS); 6996 } 6997 6998 /*@C 6999 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7000 7001 Not collective 7002 7003 Input Parameters: 7004 + dm - The `DM` 7005 . section - The section describing the layout in `v`, or `NULL` to use the default section 7006 . v - The local vector 7007 . point - The point in the `DM` 7008 . values - The array of values 7009 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7010 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7011 7012 Level: intermediate 7013 7014 Note: 7015 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7016 7017 Fortran Note: 7018 `values` must be declared with 7019 .vb 7020 PetscScalar,dimension(:),pointer :: values 7021 .ve 7022 7023 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7024 @*/ 7025 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7026 { 7027 PetscSection clSection; 7028 IS clPoints; 7029 PetscScalar *array; 7030 PetscInt *points = NULL; 7031 const PetscInt *clp, *clperm = NULL; 7032 PetscInt depth, numFields, numPoints, p, clsize; 7033 7034 PetscFunctionBeginHot; 7035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7036 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7037 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7038 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7039 PetscCall(DMPlexGetDepth(dm, &depth)); 7040 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7041 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7042 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7043 PetscFunctionReturn(PETSC_SUCCESS); 7044 } 7045 /* Get points */ 7046 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7047 for (clsize = 0, p = 0; p < numPoints; p++) { 7048 PetscInt dof; 7049 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7050 clsize += dof; 7051 } 7052 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7053 /* Get array */ 7054 PetscCall(VecGetArray(v, &array)); 7055 /* Get values */ 7056 if (numFields > 0) { 7057 PetscInt offset = 0, f; 7058 for (f = 0; f < numFields; ++f) { 7059 const PetscInt **perms = NULL; 7060 const PetscScalar **flips = NULL; 7061 7062 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7063 switch (mode) { 7064 case INSERT_VALUES: 7065 for (p = 0; p < numPoints; p++) { 7066 const PetscInt point = points[2 * p]; 7067 const PetscInt *perm = perms ? perms[p] : NULL; 7068 const PetscScalar *flip = flips ? flips[p] : NULL; 7069 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7070 } 7071 break; 7072 case INSERT_ALL_VALUES: 7073 for (p = 0; p < numPoints; p++) { 7074 const PetscInt point = points[2 * p]; 7075 const PetscInt *perm = perms ? perms[p] : NULL; 7076 const PetscScalar *flip = flips ? flips[p] : NULL; 7077 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7078 } 7079 break; 7080 case INSERT_BC_VALUES: 7081 for (p = 0; p < numPoints; p++) { 7082 const PetscInt point = points[2 * p]; 7083 const PetscInt *perm = perms ? perms[p] : NULL; 7084 const PetscScalar *flip = flips ? flips[p] : NULL; 7085 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7086 } 7087 break; 7088 case ADD_VALUES: 7089 for (p = 0; p < numPoints; p++) { 7090 const PetscInt point = points[2 * p]; 7091 const PetscInt *perm = perms ? perms[p] : NULL; 7092 const PetscScalar *flip = flips ? flips[p] : NULL; 7093 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7094 } 7095 break; 7096 case ADD_ALL_VALUES: 7097 for (p = 0; p < numPoints; p++) { 7098 const PetscInt point = points[2 * p]; 7099 const PetscInt *perm = perms ? perms[p] : NULL; 7100 const PetscScalar *flip = flips ? flips[p] : NULL; 7101 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7102 } 7103 break; 7104 case ADD_BC_VALUES: 7105 for (p = 0; p < numPoints; p++) { 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(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7110 } 7111 break; 7112 default: 7113 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7114 } 7115 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7116 } 7117 } else { 7118 PetscInt dof, off; 7119 const PetscInt **perms = NULL; 7120 const PetscScalar **flips = NULL; 7121 7122 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7123 switch (mode) { 7124 case INSERT_VALUES: 7125 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7126 const PetscInt point = points[2 * p]; 7127 const PetscInt *perm = perms ? perms[p] : NULL; 7128 const PetscScalar *flip = flips ? flips[p] : NULL; 7129 PetscCall(PetscSectionGetDof(section, point, &dof)); 7130 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7131 } 7132 break; 7133 case INSERT_ALL_VALUES: 7134 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7135 const PetscInt point = points[2 * p]; 7136 const PetscInt *perm = perms ? perms[p] : NULL; 7137 const PetscScalar *flip = flips ? flips[p] : NULL; 7138 PetscCall(PetscSectionGetDof(section, point, &dof)); 7139 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7140 } 7141 break; 7142 case INSERT_BC_VALUES: 7143 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7144 const PetscInt point = points[2 * p]; 7145 const PetscInt *perm = perms ? perms[p] : NULL; 7146 const PetscScalar *flip = flips ? flips[p] : NULL; 7147 PetscCall(PetscSectionGetDof(section, point, &dof)); 7148 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7149 } 7150 break; 7151 case ADD_VALUES: 7152 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7153 const PetscInt point = points[2 * p]; 7154 const PetscInt *perm = perms ? perms[p] : NULL; 7155 const PetscScalar *flip = flips ? flips[p] : NULL; 7156 PetscCall(PetscSectionGetDof(section, point, &dof)); 7157 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7158 } 7159 break; 7160 case ADD_ALL_VALUES: 7161 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7162 const PetscInt point = points[2 * p]; 7163 const PetscInt *perm = perms ? perms[p] : NULL; 7164 const PetscScalar *flip = flips ? flips[p] : NULL; 7165 PetscCall(PetscSectionGetDof(section, point, &dof)); 7166 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7167 } 7168 break; 7169 case ADD_BC_VALUES: 7170 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7171 const PetscInt point = points[2 * p]; 7172 const PetscInt *perm = perms ? perms[p] : NULL; 7173 const PetscScalar *flip = flips ? flips[p] : NULL; 7174 PetscCall(PetscSectionGetDof(section, point, &dof)); 7175 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7176 } 7177 break; 7178 default: 7179 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7180 } 7181 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7182 } 7183 /* Cleanup points */ 7184 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7185 /* Cleanup array */ 7186 PetscCall(VecRestoreArray(v, &array)); 7187 PetscFunctionReturn(PETSC_SUCCESS); 7188 } 7189 7190 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7191 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7192 { 7193 PetscFunctionBegin; 7194 *contains = PETSC_TRUE; 7195 if (label) { 7196 PetscInt fdof; 7197 7198 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7199 if (!*contains) { 7200 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7201 *offset += fdof; 7202 PetscFunctionReturn(PETSC_SUCCESS); 7203 } 7204 } 7205 PetscFunctionReturn(PETSC_SUCCESS); 7206 } 7207 7208 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7209 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) 7210 { 7211 PetscSection clSection; 7212 IS clPoints; 7213 PetscScalar *array; 7214 PetscInt *points = NULL; 7215 const PetscInt *clp; 7216 PetscInt numFields, numPoints, p; 7217 PetscInt offset = 0, f; 7218 7219 PetscFunctionBeginHot; 7220 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7221 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7222 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7223 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7224 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7225 /* Get points */ 7226 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7227 /* Get array */ 7228 PetscCall(VecGetArray(v, &array)); 7229 /* Get values */ 7230 for (f = 0; f < numFields; ++f) { 7231 const PetscInt **perms = NULL; 7232 const PetscScalar **flips = NULL; 7233 PetscBool contains; 7234 7235 if (!fieldActive[f]) { 7236 for (p = 0; p < numPoints * 2; p += 2) { 7237 PetscInt fdof; 7238 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7239 offset += fdof; 7240 } 7241 continue; 7242 } 7243 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7244 switch (mode) { 7245 case INSERT_VALUES: 7246 for (p = 0; p < numPoints; p++) { 7247 const PetscInt point = points[2 * p]; 7248 const PetscInt *perm = perms ? perms[p] : NULL; 7249 const PetscScalar *flip = flips ? flips[p] : NULL; 7250 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7251 if (!contains) continue; 7252 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7253 } 7254 break; 7255 case INSERT_ALL_VALUES: 7256 for (p = 0; p < numPoints; p++) { 7257 const PetscInt point = points[2 * p]; 7258 const PetscInt *perm = perms ? perms[p] : NULL; 7259 const PetscScalar *flip = flips ? flips[p] : NULL; 7260 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7261 if (!contains) continue; 7262 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7263 } 7264 break; 7265 case INSERT_BC_VALUES: 7266 for (p = 0; p < numPoints; p++) { 7267 const PetscInt point = points[2 * p]; 7268 const PetscInt *perm = perms ? perms[p] : NULL; 7269 const PetscScalar *flip = flips ? flips[p] : NULL; 7270 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7271 if (!contains) continue; 7272 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7273 } 7274 break; 7275 case ADD_VALUES: 7276 for (p = 0; p < numPoints; p++) { 7277 const PetscInt point = points[2 * p]; 7278 const PetscInt *perm = perms ? perms[p] : NULL; 7279 const PetscScalar *flip = flips ? flips[p] : NULL; 7280 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7281 if (!contains) continue; 7282 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7283 } 7284 break; 7285 case ADD_ALL_VALUES: 7286 for (p = 0; p < numPoints; p++) { 7287 const PetscInt point = points[2 * p]; 7288 const PetscInt *perm = perms ? perms[p] : NULL; 7289 const PetscScalar *flip = flips ? flips[p] : NULL; 7290 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7291 if (!contains) continue; 7292 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7293 } 7294 break; 7295 default: 7296 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7297 } 7298 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7299 } 7300 /* Cleanup points */ 7301 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7302 /* Cleanup array */ 7303 PetscCall(VecRestoreArray(v, &array)); 7304 PetscFunctionReturn(PETSC_SUCCESS); 7305 } 7306 7307 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7308 { 7309 PetscMPIInt rank; 7310 PetscInt i, j; 7311 7312 PetscFunctionBegin; 7313 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7314 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7315 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7316 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7317 numCIndices = numCIndices ? numCIndices : numRIndices; 7318 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7319 for (i = 0; i < numRIndices; i++) { 7320 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7321 for (j = 0; j < numCIndices; j++) { 7322 #if defined(PETSC_USE_COMPLEX) 7323 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7324 #else 7325 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7326 #endif 7327 } 7328 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7329 } 7330 PetscFunctionReturn(PETSC_SUCCESS); 7331 } 7332 7333 /* 7334 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7335 7336 Input Parameters: 7337 + section - The section for this data layout 7338 . islocal - Is the section (and thus indices being requested) local or global? 7339 . point - The point contributing dofs with these indices 7340 . off - The global offset of this point 7341 . loff - The local offset of each field 7342 . setBC - The flag determining whether to include indices of boundary values 7343 . perm - A permutation of the dofs on this point, or NULL 7344 - indperm - A permutation of the entire indices array, or NULL 7345 7346 Output Parameter: 7347 . indices - Indices for dofs on this point 7348 7349 Level: developer 7350 7351 Note: The indices could be local or global, depending on the value of 'off'. 7352 */ 7353 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7354 { 7355 PetscInt dof; /* The number of unknowns on this point */ 7356 PetscInt cdof; /* The number of constraints on this point */ 7357 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7358 PetscInt cind = 0, k; 7359 7360 PetscFunctionBegin; 7361 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7362 PetscCall(PetscSectionGetDof(section, point, &dof)); 7363 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7364 if (!cdof || setBC) { 7365 for (k = 0; k < dof; ++k) { 7366 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7367 const PetscInt ind = indperm ? indperm[preind] : preind; 7368 7369 indices[ind] = off + k; 7370 } 7371 } else { 7372 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7373 for (k = 0; k < dof; ++k) { 7374 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7375 const PetscInt ind = indperm ? indperm[preind] : preind; 7376 7377 if ((cind < cdof) && (k == cdofs[cind])) { 7378 /* Insert check for returning constrained indices */ 7379 indices[ind] = -(off + k + 1); 7380 ++cind; 7381 } else { 7382 indices[ind] = off + k - (islocal ? 0 : cind); 7383 } 7384 } 7385 } 7386 *loff += dof; 7387 PetscFunctionReturn(PETSC_SUCCESS); 7388 } 7389 7390 /* 7391 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7392 7393 Input Parameters: 7394 + section - a section (global or local) 7395 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7396 . point - point within section 7397 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7398 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7399 . setBC - identify constrained (boundary condition) points via involution. 7400 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7401 . permsoff - offset 7402 - indperm - index permutation 7403 7404 Output Parameter: 7405 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7406 . indices - array to hold indices (as defined by section) of each dof associated with point 7407 7408 Notes: 7409 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7410 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7411 in the local vector. 7412 7413 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7414 significant). It is invalid to call with a global section and setBC=true. 7415 7416 Developer Note: 7417 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7418 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7419 offset could be obtained from the section instead of passing it explicitly as we do now. 7420 7421 Example: 7422 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7423 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7424 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7425 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. 7426 7427 Level: developer 7428 */ 7429 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[]) 7430 { 7431 PetscInt numFields, foff, f; 7432 7433 PetscFunctionBegin; 7434 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7435 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7436 for (f = 0, foff = 0; f < numFields; ++f) { 7437 PetscInt fdof, cfdof; 7438 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7439 PetscInt cind = 0, b; 7440 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7441 7442 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7443 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7444 if (!cfdof || setBC) { 7445 for (b = 0; b < fdof; ++b) { 7446 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7447 const PetscInt ind = indperm ? indperm[preind] : preind; 7448 7449 indices[ind] = off + foff + b; 7450 } 7451 } else { 7452 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7453 for (b = 0; b < fdof; ++b) { 7454 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7455 const PetscInt ind = indperm ? indperm[preind] : preind; 7456 7457 if ((cind < cfdof) && (b == fcdofs[cind])) { 7458 indices[ind] = -(off + foff + b + 1); 7459 ++cind; 7460 } else { 7461 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7462 } 7463 } 7464 } 7465 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7466 foffs[f] += fdof; 7467 } 7468 PetscFunctionReturn(PETSC_SUCCESS); 7469 } 7470 7471 /* 7472 This version believes the globalSection offsets for each field, rather than just the point offset 7473 7474 . foffs - The offset into 'indices' for each field, since it is segregated by field 7475 7476 Notes: 7477 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7478 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7479 */ 7480 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7481 { 7482 PetscInt numFields, foff, f; 7483 7484 PetscFunctionBegin; 7485 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7486 for (f = 0; f < numFields; ++f) { 7487 PetscInt fdof, cfdof; 7488 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7489 PetscInt cind = 0, b; 7490 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7491 7492 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7493 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7494 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7495 if (!cfdof) { 7496 for (b = 0; b < fdof; ++b) { 7497 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7498 const PetscInt ind = indperm ? indperm[preind] : preind; 7499 7500 indices[ind] = foff + b; 7501 } 7502 } else { 7503 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7504 for (b = 0; b < fdof; ++b) { 7505 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7506 const PetscInt ind = indperm ? indperm[preind] : preind; 7507 7508 if ((cind < cfdof) && (b == fcdofs[cind])) { 7509 indices[ind] = -(foff + b + 1); 7510 ++cind; 7511 } else { 7512 indices[ind] = foff + b - cind; 7513 } 7514 } 7515 } 7516 foffs[f] += fdof; 7517 } 7518 PetscFunctionReturn(PETSC_SUCCESS); 7519 } 7520 7521 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7522 { 7523 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7524 7525 PetscFunctionBegin; 7526 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7527 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7528 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7529 for (PetscInt p = 0; p < nPoints; p++) { 7530 PetscInt b = pnts[2 * p]; 7531 PetscInt bSecDof = 0, bOff; 7532 PetscInt cSecDof = 0; 7533 PetscSection indices_section; 7534 7535 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7536 if (!bSecDof) continue; 7537 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7538 indices_section = cSecDof > 0 ? cSec : section; 7539 if (numFields) { 7540 PetscInt fStart[32], fEnd[32]; 7541 7542 fStart[0] = 0; 7543 fEnd[0] = 0; 7544 for (PetscInt f = 0; f < numFields; f++) { 7545 PetscInt fDof = 0; 7546 7547 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7548 fStart[f + 1] = fStart[f] + fDof; 7549 fEnd[f + 1] = fStart[f + 1]; 7550 } 7551 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7552 // only apply permutations on one side 7553 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7554 for (PetscInt f = 0; f < numFields; f++) { 7555 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7556 } 7557 } else { 7558 PetscInt bEnd = 0; 7559 7560 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7561 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7562 7563 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7564 } 7565 } 7566 PetscFunctionReturn(PETSC_SUCCESS); 7567 } 7568 7569 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[]) 7570 { 7571 Mat cMat; 7572 PetscSection aSec, cSec; 7573 IS aIS; 7574 PetscInt aStart = -1, aEnd = -1; 7575 PetscInt sStart = -1, sEnd = -1; 7576 PetscInt cStart = -1, cEnd = -1; 7577 const PetscInt *anchors; 7578 PetscInt numFields, p; 7579 PetscInt newNumPoints = 0, newNumIndices = 0; 7580 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7581 PetscInt oldOffsets[32]; 7582 PetscInt newOffsets[32]; 7583 PetscInt oldOffsetsCopy[32]; 7584 PetscInt newOffsetsCopy[32]; 7585 PetscScalar *modMat = NULL; 7586 PetscBool anyConstrained = PETSC_FALSE; 7587 7588 PetscFunctionBegin; 7589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7590 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7591 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7592 7593 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7594 /* if there are point-to-point constraints */ 7595 if (aSec) { 7596 PetscCall(PetscArrayzero(newOffsets, 32)); 7597 PetscCall(PetscArrayzero(oldOffsets, 32)); 7598 PetscCall(ISGetIndices(aIS, &anchors)); 7599 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7600 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7601 /* figure out how many points are going to be in the new element matrix 7602 * (we allow double counting, because it's all just going to be summed 7603 * into the global matrix anyway) */ 7604 for (p = 0; p < 2 * numPoints; p += 2) { 7605 PetscInt b = points[p]; 7606 PetscInt bDof = 0, bSecDof = 0; 7607 7608 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7609 if (!bSecDof) continue; 7610 7611 for (PetscInt f = 0; f < numFields; f++) { 7612 PetscInt fDof = 0; 7613 7614 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7615 oldOffsets[f + 1] += fDof; 7616 } 7617 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7618 if (bDof) { 7619 /* this point is constrained */ 7620 /* it is going to be replaced by its anchors */ 7621 PetscInt bOff, q; 7622 7623 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7624 for (q = 0; q < bDof; q++) { 7625 PetscInt a = anchors[bOff + q]; 7626 PetscInt aDof = 0; 7627 7628 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7629 if (aDof) { 7630 anyConstrained = PETSC_TRUE; 7631 newNumPoints += 1; 7632 } 7633 newNumIndices += aDof; 7634 for (PetscInt f = 0; f < numFields; ++f) { 7635 PetscInt fDof = 0; 7636 7637 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7638 newOffsets[f + 1] += fDof; 7639 } 7640 } 7641 } else { 7642 /* this point is not constrained */ 7643 newNumPoints++; 7644 newNumIndices += bSecDof; 7645 for (PetscInt f = 0; f < numFields; ++f) { 7646 PetscInt fDof; 7647 7648 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7649 newOffsets[f + 1] += fDof; 7650 } 7651 } 7652 } 7653 } 7654 if (!anyConstrained) { 7655 if (outNumPoints) *outNumPoints = 0; 7656 if (outNumIndices) *outNumIndices = 0; 7657 if (outPoints) *outPoints = NULL; 7658 if (outMat) *outMat = NULL; 7659 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7660 PetscFunctionReturn(PETSC_SUCCESS); 7661 } 7662 7663 if (outNumPoints) *outNumPoints = newNumPoints; 7664 if (outNumIndices) *outNumIndices = newNumIndices; 7665 7666 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7667 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7668 7669 if (!outPoints && !outMat) { 7670 if (offsets) { 7671 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7672 } 7673 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7674 PetscFunctionReturn(PETSC_SUCCESS); 7675 } 7676 7677 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7678 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7679 7680 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7681 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7682 7683 /* output arrays */ 7684 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7685 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7686 7687 // get the new Points 7688 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7689 PetscInt b = points[2 * p]; 7690 PetscInt bDof = 0, bSecDof = 0, bOff; 7691 7692 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7693 if (!bSecDof) continue; 7694 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7695 if (bDof) { 7696 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7697 for (PetscInt q = 0; q < bDof; q++) { 7698 PetscInt a = anchors[bOff + q], aDof = 0; 7699 7700 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7701 if (aDof) { 7702 newPoints[2 * newP] = a; 7703 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7704 newP++; 7705 } 7706 } 7707 } else { 7708 newPoints[2 * newP] = b; 7709 newPoints[2 * newP + 1] = points[2 * p + 1]; 7710 newP++; 7711 } 7712 } 7713 7714 if (outMat) { 7715 PetscScalar *tmpMat; 7716 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7717 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7718 7719 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7720 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7721 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7722 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7723 7724 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7725 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7726 7727 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7728 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7729 7730 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7731 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7732 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7733 // for each field, insert the anchor modification into modMat 7734 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7735 PetscInt fStart = oldOffsets[f]; 7736 PetscInt fNewStart = newOffsets[f]; 7737 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7738 PetscInt b = points[2 * p]; 7739 PetscInt bDof = 0, bSecDof = 0, bOff; 7740 7741 if (b >= sStart && b < sEnd) { 7742 if (numFields) { 7743 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7744 } else { 7745 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7746 } 7747 } 7748 if (!bSecDof) continue; 7749 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7750 if (bDof) { 7751 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7752 for (PetscInt q = 0; q < bDof; q++, newP++) { 7753 PetscInt a = anchors[bOff + q], aDof = 0; 7754 7755 if (a >= sStart && a < sEnd) { 7756 if (numFields) { 7757 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7758 } else { 7759 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7760 } 7761 } 7762 if (aDof) { 7763 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7764 for (PetscInt d = 0; d < bSecDof; d++) { 7765 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7766 } 7767 } 7768 oNew += aDof; 7769 } 7770 } else { 7771 // Insert the identity matrix in this block 7772 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7773 oNew += bSecDof; 7774 newP++; 7775 } 7776 o += bSecDof; 7777 } 7778 } 7779 7780 *outMat = modMat; 7781 7782 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7783 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7784 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7785 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7786 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7787 } 7788 PetscCall(ISRestoreIndices(aIS, &anchors)); 7789 7790 /* output */ 7791 if (outPoints) { 7792 *outPoints = newPoints; 7793 } else { 7794 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7795 } 7796 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7797 PetscFunctionReturn(PETSC_SUCCESS); 7798 } 7799 7800 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) 7801 { 7802 PetscScalar *modMat = NULL; 7803 PetscInt newNumIndices = -1; 7804 7805 PetscFunctionBegin; 7806 /* 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. 7807 modMat is that matrix C */ 7808 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7809 if (outNumIndices) *outNumIndices = newNumIndices; 7810 if (modMat) { 7811 const PetscScalar *newValues = values; 7812 7813 if (multiplyRight) { 7814 PetscScalar *newNewValues = NULL; 7815 PetscBLASInt M = newNumIndices; 7816 PetscBLASInt N = numRows; 7817 PetscBLASInt K = numIndices; 7818 PetscScalar a = 1.0, b = 0.0; 7819 7820 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); 7821 7822 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7823 // row-major to column-major conversion, right multiplication becomes left multiplication 7824 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7825 7826 numCols = newNumIndices; 7827 newValues = newNewValues; 7828 } 7829 7830 if (multiplyLeft) { 7831 PetscScalar *newNewValues = NULL; 7832 PetscBLASInt M = numCols; 7833 PetscBLASInt N = newNumIndices; 7834 PetscBLASInt K = numIndices; 7835 PetscScalar a = 1.0, b = 0.0; 7836 7837 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); 7838 7839 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7840 // row-major to column-major conversion, left multiplication becomes right multiplication 7841 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7842 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7843 newValues = newNewValues; 7844 } 7845 *outValues = (PetscScalar *)newValues; 7846 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7847 } 7848 PetscFunctionReturn(PETSC_SUCCESS); 7849 } 7850 7851 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) 7852 { 7853 PetscFunctionBegin; 7854 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7855 PetscFunctionReturn(PETSC_SUCCESS); 7856 } 7857 7858 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7859 { 7860 /* Closure ordering */ 7861 PetscSection clSection; 7862 IS clPoints; 7863 const PetscInt *clp; 7864 PetscInt *points; 7865 PetscInt Ncl, Ni = 0; 7866 7867 PetscFunctionBeginHot; 7868 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7869 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7870 PetscInt dof; 7871 7872 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7873 Ni += dof; 7874 } 7875 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7876 *closureSize = Ni; 7877 PetscFunctionReturn(PETSC_SUCCESS); 7878 } 7879 7880 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) 7881 { 7882 /* Closure ordering */ 7883 PetscSection clSection; 7884 IS clPoints; 7885 const PetscInt *clp; 7886 PetscInt *points; 7887 const PetscInt *clperm = NULL; 7888 /* Dof permutation and sign flips */ 7889 const PetscInt **perms[32] = {NULL}; 7890 const PetscScalar **flips[32] = {NULL}; 7891 PetscScalar *valCopy = NULL; 7892 /* Hanging node constraints */ 7893 PetscInt *pointsC = NULL; 7894 PetscScalar *valuesC = NULL; 7895 PetscInt NclC, NiC; 7896 7897 PetscInt *idx; 7898 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7899 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7900 PetscInt idxStart, idxEnd; 7901 PetscInt nRows, nCols; 7902 7903 PetscFunctionBeginHot; 7904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7905 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7906 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7907 PetscAssertPointer(numRows, 6); 7908 PetscAssertPointer(numCols, 7); 7909 if (indices) PetscAssertPointer(indices, 8); 7910 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7911 if (values) PetscAssertPointer(values, 10); 7912 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7913 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7914 PetscCall(PetscArrayzero(offsets, 32)); 7915 /* 1) Get points in closure */ 7916 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7917 if (useClPerm) { 7918 PetscInt depth, clsize; 7919 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7920 for (clsize = 0, p = 0; p < Ncl; p++) { 7921 PetscInt dof; 7922 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7923 clsize += dof; 7924 } 7925 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7926 } 7927 /* 2) Get number of indices on these points and field offsets from section */ 7928 for (p = 0; p < Ncl * 2; p += 2) { 7929 PetscInt dof, fdof; 7930 7931 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7932 for (f = 0; f < Nf; ++f) { 7933 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7934 offsets[f + 1] += fdof; 7935 } 7936 Ni += dof; 7937 } 7938 if (*numRows == -1) *numRows = Ni; 7939 if (*numCols == -1) *numCols = Ni; 7940 nRows = *numRows; 7941 nCols = *numCols; 7942 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7943 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7944 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7945 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 7946 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 7947 for (f = 0; f < PetscMax(1, Nf); ++f) { 7948 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7949 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7950 /* may need to apply sign changes to the element matrix */ 7951 if (values && flips[f]) { 7952 PetscInt foffset = offsets[f]; 7953 7954 for (p = 0; p < Ncl; ++p) { 7955 PetscInt pnt = points[2 * p], fdof; 7956 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7957 7958 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7959 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7960 if (flip) { 7961 PetscInt i, j, k; 7962 7963 if (!valCopy) { 7964 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7965 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7966 *values = valCopy; 7967 } 7968 for (i = 0; i < fdof; ++i) { 7969 PetscScalar fval = flip[i]; 7970 7971 if (multiplyRight) { 7972 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 7973 } 7974 if (multiplyLeft) { 7975 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 7976 } 7977 } 7978 } 7979 foffset += fdof; 7980 } 7981 } 7982 } 7983 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7984 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 7985 if (NclC) { 7986 if (multiplyRight) { *numCols = nCols = NiC; } 7987 if (multiplyLeft) { *numRows = nRows = NiC; } 7988 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7989 for (f = 0; f < PetscMax(1, Nf); ++f) { 7990 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7991 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7992 } 7993 for (f = 0; f < PetscMax(1, Nf); ++f) { 7994 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7995 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7996 } 7997 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7998 Ncl = NclC; 7999 Ni = NiC; 8000 points = pointsC; 8001 if (values) *values = valuesC; 8002 } 8003 /* 5) Calculate indices */ 8004 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8005 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8006 if (Nf) { 8007 PetscInt idxOff; 8008 PetscBool useFieldOffsets; 8009 8010 if (outOffsets) { 8011 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8012 } 8013 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8014 if (useFieldOffsets) { 8015 for (p = 0; p < Ncl; ++p) { 8016 const PetscInt pnt = points[p * 2]; 8017 8018 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8019 } 8020 } else { 8021 for (p = 0; p < Ncl; ++p) { 8022 const PetscInt pnt = points[p * 2]; 8023 8024 if (pnt < idxStart || pnt >= idxEnd) continue; 8025 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8026 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8027 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8028 * global section. */ 8029 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8030 } 8031 } 8032 } else { 8033 PetscInt off = 0, idxOff; 8034 8035 for (p = 0; p < Ncl; ++p) { 8036 const PetscInt pnt = points[p * 2]; 8037 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8038 8039 if (pnt < idxStart || pnt >= idxEnd) continue; 8040 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8041 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8042 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8043 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8044 } 8045 } 8046 /* 6) Cleanup */ 8047 for (f = 0; f < PetscMax(1, Nf); ++f) { 8048 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8049 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8050 } 8051 if (NclC) { 8052 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8053 } else { 8054 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8055 } 8056 8057 if (indices) *indices = idx; 8058 PetscFunctionReturn(PETSC_SUCCESS); 8059 } 8060 8061 /*@C 8062 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8063 8064 Not collective 8065 8066 Input Parameters: 8067 + dm - The `DM` 8068 . section - The `PetscSection` describing the points (a local section) 8069 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8070 . point - The point defining the closure 8071 - useClPerm - Use the closure point permutation if available 8072 8073 Output Parameters: 8074 + numIndices - The number of dof indices in the closure of point with the input sections 8075 . indices - The dof indices 8076 . outOffsets - Array to write the field offsets into, or `NULL` 8077 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8078 8079 Level: advanced 8080 8081 Notes: 8082 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8083 8084 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8085 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8086 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8087 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8088 indices (with the above semantics) are implied. 8089 8090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8091 `PetscSection`, `DMGetGlobalSection()` 8092 @*/ 8093 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8094 { 8095 PetscInt numRows = -1, numCols = -1; 8096 8097 PetscFunctionBeginHot; 8098 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8099 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8100 *numIndices = numRows; 8101 PetscFunctionReturn(PETSC_SUCCESS); 8102 } 8103 8104 /*@C 8105 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8106 8107 Not collective 8108 8109 Input Parameters: 8110 + dm - The `DM` 8111 . section - The `PetscSection` describing the points (a local section) 8112 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8113 . point - The point defining the closure 8114 - useClPerm - Use the closure point permutation if available 8115 8116 Output Parameters: 8117 + numIndices - The number of dof indices in the closure of point with the input sections 8118 . indices - The dof indices 8119 . outOffsets - Array to write the field offsets into, or `NULL` 8120 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8121 8122 Level: advanced 8123 8124 Notes: 8125 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8126 8127 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8128 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8129 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8130 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8131 indices (with the above semantics) are implied. 8132 8133 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8134 @*/ 8135 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8136 { 8137 PetscFunctionBegin; 8138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8139 PetscAssertPointer(indices, 7); 8140 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8141 PetscFunctionReturn(PETSC_SUCCESS); 8142 } 8143 8144 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8145 { 8146 DM_Plex *mesh = (DM_Plex *)dm->data; 8147 PetscInt *indices; 8148 PetscInt numIndices; 8149 const PetscScalar *valuesOrig = values; 8150 PetscErrorCode ierr; 8151 8152 PetscFunctionBegin; 8153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8154 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8155 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8156 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8157 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8158 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8159 8160 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8161 8162 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8163 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8164 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8165 if (ierr) { 8166 PetscMPIInt rank; 8167 8168 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8169 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8170 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8171 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8172 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8173 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8174 } 8175 if (mesh->printFEM > 1) { 8176 PetscInt i; 8177 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8178 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8179 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8180 } 8181 8182 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8183 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8184 PetscFunctionReturn(PETSC_SUCCESS); 8185 } 8186 8187 /*@C 8188 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8189 8190 Not collective 8191 8192 Input Parameters: 8193 + dm - The `DM` 8194 . section - The section describing the layout in `v`, or `NULL` to use the default section 8195 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8196 . A - The matrix 8197 . point - The point in the `DM` 8198 . values - The array of values 8199 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8200 8201 Level: intermediate 8202 8203 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8204 @*/ 8205 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8206 { 8207 PetscFunctionBegin; 8208 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8209 PetscFunctionReturn(PETSC_SUCCESS); 8210 } 8211 8212 /*@C 8213 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8214 8215 Not collective 8216 8217 Input Parameters: 8218 + dmRow - The `DM` for the row fields 8219 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8220 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8221 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8222 . dmCol - The `DM` for the column fields 8223 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8224 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8225 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8226 . A - The matrix 8227 . point - The point in the `DM` 8228 . values - The array of values 8229 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8230 8231 Level: intermediate 8232 8233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8234 @*/ 8235 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) 8236 { 8237 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8238 PetscInt *indicesRow, *indicesCol; 8239 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8240 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8241 8242 PetscErrorCode ierr; 8243 8244 PetscFunctionBegin; 8245 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8246 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8247 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8248 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8249 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8250 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8251 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8252 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8253 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8254 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8255 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8256 8257 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8258 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8259 valuesV1 = valuesV0; 8260 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8261 valuesV2 = valuesV1; 8262 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8263 8264 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8265 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8266 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8267 if (ierr) { 8268 PetscMPIInt rank; 8269 8270 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8271 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8272 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8273 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8274 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8275 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8276 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8277 } 8278 8279 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8280 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8281 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8282 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8283 PetscFunctionReturn(PETSC_SUCCESS); 8284 } 8285 8286 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8287 { 8288 DM_Plex *mesh = (DM_Plex *)dmf->data; 8289 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8290 PetscInt *cpoints = NULL; 8291 PetscInt *findices, *cindices; 8292 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8293 PetscInt foffsets[32], coffsets[32]; 8294 DMPolytopeType ct; 8295 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8296 PetscErrorCode ierr; 8297 8298 PetscFunctionBegin; 8299 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8300 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8301 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8302 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8303 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8304 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8305 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8306 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8307 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8308 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8309 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8310 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8311 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8312 PetscCall(PetscArrayzero(foffsets, 32)); 8313 PetscCall(PetscArrayzero(coffsets, 32)); 8314 /* Column indices */ 8315 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8316 maxFPoints = numCPoints; 8317 /* Compress out points not in the section */ 8318 /* TODO: Squeeze out points with 0 dof as well */ 8319 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8320 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8321 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8322 cpoints[q * 2] = cpoints[p]; 8323 cpoints[q * 2 + 1] = cpoints[p + 1]; 8324 ++q; 8325 } 8326 } 8327 numCPoints = q; 8328 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8329 PetscInt fdof; 8330 8331 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8332 if (!dof) continue; 8333 for (f = 0; f < numFields; ++f) { 8334 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8335 coffsets[f + 1] += fdof; 8336 } 8337 numCIndices += dof; 8338 } 8339 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8340 /* Row indices */ 8341 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8342 { 8343 DMPlexTransform tr; 8344 DMPolytopeType *rct; 8345 PetscInt *rsize, *rcone, *rornt, Nt; 8346 8347 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8348 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8349 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8350 numSubcells = rsize[Nt - 1]; 8351 PetscCall(DMPlexTransformDestroy(&tr)); 8352 } 8353 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8354 for (r = 0, q = 0; r < numSubcells; ++r) { 8355 /* TODO Map from coarse to fine cells */ 8356 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8357 /* Compress out points not in the section */ 8358 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8359 for (p = 0; p < numFPoints * 2; p += 2) { 8360 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8361 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8362 if (!dof) continue; 8363 for (s = 0; s < q; ++s) 8364 if (fpoints[p] == ftotpoints[s * 2]) break; 8365 if (s < q) continue; 8366 ftotpoints[q * 2] = fpoints[p]; 8367 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8368 ++q; 8369 } 8370 } 8371 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8372 } 8373 numFPoints = q; 8374 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8375 PetscInt fdof; 8376 8377 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8378 if (!dof) continue; 8379 for (f = 0; f < numFields; ++f) { 8380 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8381 foffsets[f + 1] += fdof; 8382 } 8383 numFIndices += dof; 8384 } 8385 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8386 8387 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8388 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8389 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8390 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8391 if (numFields) { 8392 const PetscInt **permsF[32] = {NULL}; 8393 const PetscInt **permsC[32] = {NULL}; 8394 8395 for (f = 0; f < numFields; f++) { 8396 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8397 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8398 } 8399 for (p = 0; p < numFPoints; p++) { 8400 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8401 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8402 } 8403 for (p = 0; p < numCPoints; p++) { 8404 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8405 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8406 } 8407 for (f = 0; f < numFields; f++) { 8408 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8409 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8410 } 8411 } else { 8412 const PetscInt **permsF = NULL; 8413 const PetscInt **permsC = NULL; 8414 8415 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8416 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8417 for (p = 0, off = 0; p < numFPoints; p++) { 8418 const PetscInt *perm = permsF ? permsF[p] : NULL; 8419 8420 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8421 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8422 } 8423 for (p = 0, off = 0; p < numCPoints; p++) { 8424 const PetscInt *perm = permsC ? permsC[p] : NULL; 8425 8426 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8427 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8428 } 8429 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8430 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8431 } 8432 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8433 /* TODO: flips */ 8434 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8435 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8436 if (ierr) { 8437 PetscMPIInt rank; 8438 8439 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8440 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8441 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8442 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8443 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8444 } 8445 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8446 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8447 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8448 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8449 PetscFunctionReturn(PETSC_SUCCESS); 8450 } 8451 8452 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8453 { 8454 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8455 PetscInt *cpoints = NULL; 8456 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8457 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8458 DMPolytopeType ct; 8459 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8460 8461 PetscFunctionBegin; 8462 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8463 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8464 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8465 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8466 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8467 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8468 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8469 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8470 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8471 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8472 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8473 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8474 /* Column indices */ 8475 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8476 maxFPoints = numCPoints; 8477 /* Compress out points not in the section */ 8478 /* TODO: Squeeze out points with 0 dof as well */ 8479 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8480 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8481 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8482 cpoints[q * 2] = cpoints[p]; 8483 cpoints[q * 2 + 1] = cpoints[p + 1]; 8484 ++q; 8485 } 8486 } 8487 numCPoints = q; 8488 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8489 PetscInt fdof; 8490 8491 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8492 if (!dof) continue; 8493 for (f = 0; f < numFields; ++f) { 8494 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8495 coffsets[f + 1] += fdof; 8496 } 8497 numCIndices += dof; 8498 } 8499 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8500 /* Row indices */ 8501 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8502 { 8503 DMPlexTransform tr; 8504 DMPolytopeType *rct; 8505 PetscInt *rsize, *rcone, *rornt, Nt; 8506 8507 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8508 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8509 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8510 numSubcells = rsize[Nt - 1]; 8511 PetscCall(DMPlexTransformDestroy(&tr)); 8512 } 8513 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8514 for (r = 0, q = 0; r < numSubcells; ++r) { 8515 /* TODO Map from coarse to fine cells */ 8516 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8517 /* Compress out points not in the section */ 8518 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8519 for (p = 0; p < numFPoints * 2; p += 2) { 8520 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8521 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8522 if (!dof) continue; 8523 for (s = 0; s < q; ++s) 8524 if (fpoints[p] == ftotpoints[s * 2]) break; 8525 if (s < q) continue; 8526 ftotpoints[q * 2] = fpoints[p]; 8527 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8528 ++q; 8529 } 8530 } 8531 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8532 } 8533 numFPoints = q; 8534 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8535 PetscInt fdof; 8536 8537 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8538 if (!dof) continue; 8539 for (f = 0; f < numFields; ++f) { 8540 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8541 foffsets[f + 1] += fdof; 8542 } 8543 numFIndices += dof; 8544 } 8545 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8546 8547 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8548 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8549 if (numFields) { 8550 const PetscInt **permsF[32] = {NULL}; 8551 const PetscInt **permsC[32] = {NULL}; 8552 8553 for (f = 0; f < numFields; f++) { 8554 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8555 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8556 } 8557 for (p = 0; p < numFPoints; p++) { 8558 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8559 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8560 } 8561 for (p = 0; p < numCPoints; p++) { 8562 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8563 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8564 } 8565 for (f = 0; f < numFields; f++) { 8566 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8567 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8568 } 8569 } else { 8570 const PetscInt **permsF = NULL; 8571 const PetscInt **permsC = NULL; 8572 8573 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8574 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8575 for (p = 0, off = 0; p < numFPoints; p++) { 8576 const PetscInt *perm = permsF ? permsF[p] : NULL; 8577 8578 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8579 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8580 } 8581 for (p = 0, off = 0; p < numCPoints; p++) { 8582 const PetscInt *perm = permsC ? permsC[p] : NULL; 8583 8584 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8585 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8586 } 8587 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8588 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8589 } 8590 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8591 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8592 PetscFunctionReturn(PETSC_SUCCESS); 8593 } 8594 8595 /*@C 8596 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8597 8598 Input Parameter: 8599 . dm - The `DMPLEX` object 8600 8601 Output Parameter: 8602 . cellHeight - The height of a cell 8603 8604 Level: developer 8605 8606 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8607 @*/ 8608 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8609 { 8610 DM_Plex *mesh = (DM_Plex *)dm->data; 8611 8612 PetscFunctionBegin; 8613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8614 PetscAssertPointer(cellHeight, 2); 8615 *cellHeight = mesh->vtkCellHeight; 8616 PetscFunctionReturn(PETSC_SUCCESS); 8617 } 8618 8619 /*@C 8620 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8621 8622 Input Parameters: 8623 + dm - The `DMPLEX` object 8624 - cellHeight - The height of a cell 8625 8626 Level: developer 8627 8628 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8629 @*/ 8630 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8631 { 8632 DM_Plex *mesh = (DM_Plex *)dm->data; 8633 8634 PetscFunctionBegin; 8635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8636 mesh->vtkCellHeight = cellHeight; 8637 PetscFunctionReturn(PETSC_SUCCESS); 8638 } 8639 8640 /*@ 8641 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8642 8643 Input Parameters: 8644 + dm - The `DMPLEX` object 8645 - ct - The `DMPolytopeType` of the cell 8646 8647 Output Parameters: 8648 + start - The first cell of this type, or `NULL` 8649 - end - The upper bound on this celltype, or `NULL` 8650 8651 Level: advanced 8652 8653 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8654 @*/ 8655 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8656 { 8657 DM_Plex *mesh = (DM_Plex *)dm->data; 8658 DMLabel label; 8659 PetscInt pStart, pEnd; 8660 8661 PetscFunctionBegin; 8662 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8663 if (start) { 8664 PetscAssertPointer(start, 3); 8665 *start = 0; 8666 } 8667 if (end) { 8668 PetscAssertPointer(end, 4); 8669 *end = 0; 8670 } 8671 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8672 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8673 if (mesh->tr) { 8674 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8675 } else { 8676 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8677 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8678 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8679 } 8680 PetscFunctionReturn(PETSC_SUCCESS); 8681 } 8682 8683 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8684 { 8685 PetscSection section, globalSection; 8686 PetscInt *numbers, p; 8687 8688 PetscFunctionBegin; 8689 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8690 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8691 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8692 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8693 PetscCall(PetscSectionSetUp(section)); 8694 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8695 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8696 for (p = pStart; p < pEnd; ++p) { 8697 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8698 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8699 else numbers[p - pStart] += shift; 8700 } 8701 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8702 if (globalSize) { 8703 PetscLayout layout; 8704 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8705 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8706 PetscCall(PetscLayoutDestroy(&layout)); 8707 } 8708 PetscCall(PetscSectionDestroy(§ion)); 8709 PetscCall(PetscSectionDestroy(&globalSection)); 8710 PetscFunctionReturn(PETSC_SUCCESS); 8711 } 8712 8713 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8714 { 8715 PetscInt cellHeight, cStart, cEnd; 8716 8717 PetscFunctionBegin; 8718 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8719 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8720 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8721 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8722 PetscFunctionReturn(PETSC_SUCCESS); 8723 } 8724 8725 /*@ 8726 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8727 8728 Input Parameter: 8729 . dm - The `DMPLEX` object 8730 8731 Output Parameter: 8732 . globalCellNumbers - Global cell numbers for all cells on this process 8733 8734 Level: developer 8735 8736 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8737 @*/ 8738 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8739 { 8740 DM_Plex *mesh = (DM_Plex *)dm->data; 8741 8742 PetscFunctionBegin; 8743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8744 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8745 *globalCellNumbers = mesh->globalCellNumbers; 8746 PetscFunctionReturn(PETSC_SUCCESS); 8747 } 8748 8749 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8750 { 8751 PetscInt vStart, vEnd; 8752 8753 PetscFunctionBegin; 8754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8755 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8756 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8757 PetscFunctionReturn(PETSC_SUCCESS); 8758 } 8759 8760 /*@ 8761 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8762 8763 Input Parameter: 8764 . dm - The `DMPLEX` object 8765 8766 Output Parameter: 8767 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8768 8769 Level: developer 8770 8771 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8772 @*/ 8773 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8774 { 8775 DM_Plex *mesh = (DM_Plex *)dm->data; 8776 8777 PetscFunctionBegin; 8778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8779 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8780 *globalVertexNumbers = mesh->globalVertexNumbers; 8781 PetscFunctionReturn(PETSC_SUCCESS); 8782 } 8783 8784 /*@ 8785 DMPlexCreatePointNumbering - Create a global numbering for all points. 8786 8787 Collective 8788 8789 Input Parameter: 8790 . dm - The `DMPLEX` object 8791 8792 Output Parameter: 8793 . globalPointNumbers - Global numbers for all points on this process 8794 8795 Level: developer 8796 8797 Notes: 8798 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8799 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8800 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8801 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8802 8803 The partitioned mesh is 8804 ``` 8805 (2)--0--(3)--1--(4) (1)--0--(2) 8806 ``` 8807 and its global numbering is 8808 ``` 8809 (3)--0--(4)--1--(5)--2--(6) 8810 ``` 8811 Then the global numbering is provided as 8812 ``` 8813 [0] Number of indices in set 5 8814 [0] 0 0 8815 [0] 1 1 8816 [0] 2 3 8817 [0] 3 4 8818 [0] 4 -6 8819 [1] Number of indices in set 3 8820 [1] 0 2 8821 [1] 1 5 8822 [1] 2 6 8823 ``` 8824 8825 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8826 @*/ 8827 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8828 { 8829 IS nums[4]; 8830 PetscInt depths[4], gdepths[4], starts[4]; 8831 PetscInt depth, d, shift = 0; 8832 PetscBool empty = PETSC_FALSE; 8833 8834 PetscFunctionBegin; 8835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8836 PetscCall(DMPlexGetDepth(dm, &depth)); 8837 // For unstratified meshes use dim instead of depth 8838 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8839 // If any stratum is empty, we must mark all empty 8840 for (d = 0; d <= depth; ++d) { 8841 PetscInt end; 8842 8843 depths[d] = depth - d; 8844 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8845 if (!(starts[d] - end)) empty = PETSC_TRUE; 8846 } 8847 if (empty) 8848 for (d = 0; d <= depth; ++d) { 8849 depths[d] = -1; 8850 starts[d] = -1; 8851 } 8852 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8853 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8854 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]); 8855 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8856 for (d = 0; d <= depth; ++d) { 8857 PetscInt pStart, pEnd, gsize; 8858 8859 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8860 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8861 shift += gsize; 8862 } 8863 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8864 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8865 PetscFunctionReturn(PETSC_SUCCESS); 8866 } 8867 8868 /*@ 8869 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8870 8871 Input Parameter: 8872 . dm - The `DMPLEX` object 8873 8874 Output Parameter: 8875 . ranks - The rank field 8876 8877 Options Database Key: 8878 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8879 8880 Level: intermediate 8881 8882 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8883 @*/ 8884 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8885 { 8886 DM rdm; 8887 PetscFE fe; 8888 PetscScalar *r; 8889 PetscMPIInt rank; 8890 DMPolytopeType ct; 8891 PetscInt dim, cStart, cEnd, c; 8892 PetscBool simplex; 8893 8894 PetscFunctionBeginUser; 8895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8896 PetscAssertPointer(ranks, 2); 8897 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8898 PetscCall(DMClone(dm, &rdm)); 8899 PetscCall(DMGetDimension(rdm, &dim)); 8900 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8901 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8902 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8903 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8904 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8905 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8906 PetscCall(PetscFEDestroy(&fe)); 8907 PetscCall(DMCreateDS(rdm)); 8908 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8909 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8910 PetscCall(VecGetArray(*ranks, &r)); 8911 for (c = cStart; c < cEnd; ++c) { 8912 PetscScalar *lr; 8913 8914 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8915 if (lr) *lr = rank; 8916 } 8917 PetscCall(VecRestoreArray(*ranks, &r)); 8918 PetscCall(DMDestroy(&rdm)); 8919 PetscFunctionReturn(PETSC_SUCCESS); 8920 } 8921 8922 /*@ 8923 DMPlexCreateLabelField - Create a field whose value is the label value for that point 8924 8925 Input Parameters: 8926 + dm - The `DMPLEX` 8927 - label - The `DMLabel` 8928 8929 Output Parameter: 8930 . val - The label value field 8931 8932 Options Database Key: 8933 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8934 8935 Level: intermediate 8936 8937 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8938 @*/ 8939 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8940 { 8941 DM rdm, plex; 8942 Vec lval; 8943 PetscSection section; 8944 PetscFE fe; 8945 PetscScalar *v; 8946 PetscInt dim, pStart, pEnd, p, cStart; 8947 DMPolytopeType ct; 8948 char name[PETSC_MAX_PATH_LEN]; 8949 const char *lname, *prefix; 8950 8951 PetscFunctionBeginUser; 8952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8953 PetscAssertPointer(label, 2); 8954 PetscAssertPointer(val, 3); 8955 PetscCall(DMClone(dm, &rdm)); 8956 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 8957 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 8958 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 8959 PetscCall(DMDestroy(&plex)); 8960 PetscCall(DMGetDimension(rdm, &dim)); 8961 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 8962 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 8963 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 8964 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 8965 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 8966 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8967 PetscCall(PetscFEDestroy(&fe)); 8968 PetscCall(DMCreateDS(rdm)); 8969 PetscCall(DMCreateGlobalVector(rdm, val)); 8970 PetscCall(DMCreateLocalVector(rdm, &lval)); 8971 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 8972 PetscCall(DMGetLocalSection(rdm, §ion)); 8973 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 8974 PetscCall(VecGetArray(lval, &v)); 8975 for (p = pStart; p < pEnd; ++p) { 8976 PetscInt cval, dof, off; 8977 8978 PetscCall(PetscSectionGetDof(section, p, &dof)); 8979 if (!dof) continue; 8980 PetscCall(DMLabelGetValue(label, p, &cval)); 8981 PetscCall(PetscSectionGetOffset(section, p, &off)); 8982 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 8983 } 8984 PetscCall(VecRestoreArray(lval, &v)); 8985 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 8986 PetscCall(VecDestroy(&lval)); 8987 PetscCall(DMDestroy(&rdm)); 8988 PetscFunctionReturn(PETSC_SUCCESS); 8989 } 8990 8991 /*@ 8992 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8993 8994 Input Parameter: 8995 . dm - The `DMPLEX` object 8996 8997 Level: developer 8998 8999 Notes: 9000 This is a useful diagnostic when creating meshes programmatically. 9001 9002 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9003 9004 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9005 @*/ 9006 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9007 { 9008 PetscSection coneSection, supportSection; 9009 const PetscInt *cone, *support; 9010 PetscInt coneSize, c, supportSize, s; 9011 PetscInt pStart, pEnd, p, pp, csize, ssize; 9012 PetscBool storagecheck = PETSC_TRUE; 9013 9014 PetscFunctionBegin; 9015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9016 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9017 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9018 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9019 /* Check that point p is found in the support of its cone points, and vice versa */ 9020 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9021 for (p = pStart; p < pEnd; ++p) { 9022 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9023 PetscCall(DMPlexGetCone(dm, p, &cone)); 9024 for (c = 0; c < coneSize; ++c) { 9025 PetscBool dup = PETSC_FALSE; 9026 PetscInt d; 9027 for (d = c - 1; d >= 0; --d) { 9028 if (cone[c] == cone[d]) { 9029 dup = PETSC_TRUE; 9030 break; 9031 } 9032 } 9033 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9034 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9035 for (s = 0; s < supportSize; ++s) { 9036 if (support[s] == p) break; 9037 } 9038 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9039 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9040 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9041 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9042 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9043 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9044 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9045 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]); 9046 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9047 } 9048 } 9049 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9050 if (p != pp) { 9051 storagecheck = PETSC_FALSE; 9052 continue; 9053 } 9054 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9055 PetscCall(DMPlexGetSupport(dm, p, &support)); 9056 for (s = 0; s < supportSize; ++s) { 9057 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9058 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9059 for (c = 0; c < coneSize; ++c) { 9060 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9061 if (cone[c] != pp) { 9062 c = 0; 9063 break; 9064 } 9065 if (cone[c] == p) break; 9066 } 9067 if (c >= coneSize) { 9068 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9069 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9070 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9071 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9072 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9073 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9074 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9075 } 9076 } 9077 } 9078 if (storagecheck) { 9079 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9080 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9081 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9082 } 9083 PetscFunctionReturn(PETSC_SUCCESS); 9084 } 9085 9086 /* 9087 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. 9088 */ 9089 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9090 { 9091 DMPolytopeType cct; 9092 PetscInt ptpoints[4]; 9093 const PetscInt *cone, *ccone, *ptcone; 9094 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9095 9096 PetscFunctionBegin; 9097 *unsplit = 0; 9098 switch (ct) { 9099 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9100 ptpoints[npt++] = c; 9101 break; 9102 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9103 PetscCall(DMPlexGetCone(dm, c, &cone)); 9104 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9105 for (cp = 0; cp < coneSize; ++cp) { 9106 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9107 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9108 } 9109 break; 9110 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9111 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9112 PetscCall(DMPlexGetCone(dm, c, &cone)); 9113 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9114 for (cp = 0; cp < coneSize; ++cp) { 9115 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9116 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9117 for (ccp = 0; ccp < cconeSize; ++ccp) { 9118 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9119 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9120 PetscInt p; 9121 for (p = 0; p < npt; ++p) 9122 if (ptpoints[p] == ccone[ccp]) break; 9123 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9124 } 9125 } 9126 } 9127 break; 9128 default: 9129 break; 9130 } 9131 for (pt = 0; pt < npt; ++pt) { 9132 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9133 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9134 } 9135 PetscFunctionReturn(PETSC_SUCCESS); 9136 } 9137 9138 /*@ 9139 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9140 9141 Input Parameters: 9142 + dm - The `DMPLEX` object 9143 - cellHeight - Normally 0 9144 9145 Level: developer 9146 9147 Notes: 9148 This is a useful diagnostic when creating meshes programmatically. 9149 Currently applicable only to homogeneous simplex or tensor meshes. 9150 9151 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9152 9153 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9154 @*/ 9155 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9156 { 9157 DMPlexInterpolatedFlag interp; 9158 DMPolytopeType ct; 9159 PetscInt vStart, vEnd, cStart, cEnd, c; 9160 9161 PetscFunctionBegin; 9162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9163 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9164 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9165 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9166 for (c = cStart; c < cEnd; ++c) { 9167 PetscInt *closure = NULL; 9168 PetscInt coneSize, closureSize, cl, Nv = 0; 9169 9170 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9171 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9172 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9173 if (interp == DMPLEX_INTERPOLATED_FULL) { 9174 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9175 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)); 9176 } 9177 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9178 for (cl = 0; cl < closureSize * 2; cl += 2) { 9179 const PetscInt p = closure[cl]; 9180 if ((p >= vStart) && (p < vEnd)) ++Nv; 9181 } 9182 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9183 /* Special Case: Tensor faces with identified vertices */ 9184 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9185 PetscInt unsplit; 9186 9187 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9188 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9189 } 9190 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)); 9191 } 9192 PetscFunctionReturn(PETSC_SUCCESS); 9193 } 9194 9195 /*@ 9196 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9197 9198 Collective 9199 9200 Input Parameters: 9201 + dm - The `DMPLEX` object 9202 - cellHeight - Normally 0 9203 9204 Level: developer 9205 9206 Notes: 9207 This is a useful diagnostic when creating meshes programmatically. 9208 This routine is only relevant for meshes that are fully interpolated across all ranks. 9209 It will error out if a partially interpolated mesh is given on some rank. 9210 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9211 9212 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9213 9214 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9215 @*/ 9216 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9217 { 9218 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9219 DMPlexInterpolatedFlag interpEnum; 9220 9221 PetscFunctionBegin; 9222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9223 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9224 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9225 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9226 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9227 PetscFunctionReturn(PETSC_SUCCESS); 9228 } 9229 9230 PetscCall(DMGetDimension(dm, &dim)); 9231 PetscCall(DMPlexGetDepth(dm, &depth)); 9232 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9233 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9234 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9235 for (c = cStart; c < cEnd; ++c) { 9236 const PetscInt *cone, *ornt, *faceSizes, *faces; 9237 const DMPolytopeType *faceTypes; 9238 DMPolytopeType ct; 9239 PetscInt numFaces, coneSize, f; 9240 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9241 9242 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9243 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9244 if (unsplit) continue; 9245 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9246 PetscCall(DMPlexGetCone(dm, c, &cone)); 9247 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9248 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9249 for (cl = 0; cl < closureSize * 2; cl += 2) { 9250 const PetscInt p = closure[cl]; 9251 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9252 } 9253 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9254 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); 9255 for (f = 0; f < numFaces; ++f) { 9256 DMPolytopeType fct; 9257 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9258 9259 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9260 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9261 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9262 const PetscInt p = fclosure[cl]; 9263 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9264 } 9265 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]); 9266 for (v = 0; v < fnumCorners; ++v) { 9267 if (fclosure[v] != faces[fOff + v]) { 9268 PetscInt v1; 9269 9270 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9271 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9272 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9273 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9274 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9275 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]); 9276 } 9277 } 9278 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9279 fOff += faceSizes[f]; 9280 } 9281 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9282 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9283 } 9284 } 9285 PetscFunctionReturn(PETSC_SUCCESS); 9286 } 9287 9288 /*@ 9289 DMPlexCheckGeometry - Check the geometry of mesh cells 9290 9291 Input Parameter: 9292 . dm - The `DMPLEX` object 9293 9294 Level: developer 9295 9296 Notes: 9297 This is a useful diagnostic when creating meshes programmatically. 9298 9299 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9300 9301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9302 @*/ 9303 PetscErrorCode DMPlexCheckGeometry(DM dm) 9304 { 9305 Vec coordinates; 9306 PetscReal detJ, J[9], refVol = 1.0; 9307 PetscReal vol; 9308 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9309 9310 PetscFunctionBegin; 9311 PetscCall(DMGetDimension(dm, &dim)); 9312 PetscCall(DMGetCoordinateDim(dm, &dE)); 9313 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9314 PetscCall(DMPlexGetDepth(dm, &depth)); 9315 for (d = 0; d < dim; ++d) refVol *= 2.0; 9316 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9317 /* Make sure local coordinates are created, because that step is collective */ 9318 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9319 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9320 for (c = cStart; c < cEnd; ++c) { 9321 DMPolytopeType ct; 9322 PetscInt unsplit; 9323 PetscBool ignoreZeroVol = PETSC_FALSE; 9324 9325 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9326 switch (ct) { 9327 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9328 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9329 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9330 ignoreZeroVol = PETSC_TRUE; 9331 break; 9332 default: 9333 break; 9334 } 9335 switch (ct) { 9336 case DM_POLYTOPE_TRI_PRISM: 9337 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9338 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9339 case DM_POLYTOPE_PYRAMID: 9340 continue; 9341 default: 9342 break; 9343 } 9344 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9345 if (unsplit) continue; 9346 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9347 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); 9348 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9349 /* This should work with periodicity since DG coordinates should be used */ 9350 if (depth > 1) { 9351 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9352 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); 9353 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9354 } 9355 } 9356 PetscFunctionReturn(PETSC_SUCCESS); 9357 } 9358 9359 /*@ 9360 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9361 9362 Collective 9363 9364 Input Parameters: 9365 + dm - The `DMPLEX` object 9366 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9367 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9368 9369 Level: developer 9370 9371 Notes: 9372 This is mainly intended for debugging/testing purposes. 9373 9374 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9375 9376 Extra roots can come from periodic cuts, where additional points appear on the boundary 9377 9378 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9379 @*/ 9380 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9381 { 9382 PetscInt l, nleaves, nroots, overlap; 9383 const PetscInt *locals; 9384 const PetscSFNode *remotes; 9385 PetscBool distributed; 9386 MPI_Comm comm; 9387 PetscMPIInt rank; 9388 9389 PetscFunctionBegin; 9390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9391 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9392 else pointSF = dm->sf; 9393 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9394 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9395 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9396 { 9397 PetscMPIInt mpiFlag; 9398 9399 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9400 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9401 } 9402 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9403 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9404 if (!distributed) { 9405 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); 9406 PetscFunctionReturn(PETSC_SUCCESS); 9407 } 9408 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); 9409 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9410 9411 /* Check SF graph is compatible with DMPlex chart */ 9412 { 9413 PetscInt pStart, pEnd, maxLeaf; 9414 9415 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9416 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9417 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9418 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9419 } 9420 9421 /* Check Point SF has no local points referenced */ 9422 for (l = 0; l < nleaves; l++) { 9423 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); 9424 } 9425 9426 /* Check there are no cells in interface */ 9427 if (!overlap) { 9428 PetscInt cellHeight, cStart, cEnd; 9429 9430 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9431 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9432 for (l = 0; l < nleaves; ++l) { 9433 const PetscInt point = locals ? locals[l] : l; 9434 9435 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9436 } 9437 } 9438 9439 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9440 { 9441 const PetscInt *rootdegree; 9442 9443 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9444 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9445 for (l = 0; l < nleaves; ++l) { 9446 const PetscInt point = locals ? locals[l] : l; 9447 const PetscInt *cone; 9448 PetscInt coneSize, c, idx; 9449 9450 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9451 PetscCall(DMPlexGetCone(dm, point, &cone)); 9452 for (c = 0; c < coneSize; ++c) { 9453 if (!rootdegree[cone[c]]) { 9454 if (locals) { 9455 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9456 } else { 9457 idx = (cone[c] < nleaves) ? cone[c] : -1; 9458 } 9459 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9460 } 9461 } 9462 } 9463 } 9464 PetscFunctionReturn(PETSC_SUCCESS); 9465 } 9466 9467 /*@ 9468 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9469 9470 Input Parameter: 9471 . dm - The `DMPLEX` object 9472 9473 Level: developer 9474 9475 Notes: 9476 This is a useful diagnostic when creating meshes programmatically. 9477 9478 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9479 9480 Currently does not include `DMPlexCheckCellShape()`. 9481 9482 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9483 @*/ 9484 PetscErrorCode DMPlexCheck(DM dm) 9485 { 9486 PetscInt cellHeight; 9487 9488 PetscFunctionBegin; 9489 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9490 PetscCall(DMPlexCheckSymmetry(dm)); 9491 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9492 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9493 PetscCall(DMPlexCheckGeometry(dm)); 9494 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9495 PetscCall(DMPlexCheckInterfaceCones(dm)); 9496 PetscFunctionReturn(PETSC_SUCCESS); 9497 } 9498 9499 typedef struct cell_stats { 9500 PetscReal min, max, sum, squaresum; 9501 PetscInt count; 9502 } cell_stats_t; 9503 9504 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9505 { 9506 PetscInt i, N = *len; 9507 9508 for (i = 0; i < N; i++) { 9509 cell_stats_t *A = (cell_stats_t *)a; 9510 cell_stats_t *B = (cell_stats_t *)b; 9511 9512 B->min = PetscMin(A->min, B->min); 9513 B->max = PetscMax(A->max, B->max); 9514 B->sum += A->sum; 9515 B->squaresum += A->squaresum; 9516 B->count += A->count; 9517 } 9518 } 9519 9520 /*@ 9521 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9522 9523 Collective 9524 9525 Input Parameters: 9526 + dm - The `DMPLEX` object 9527 . output - If true, statistics will be displayed on `stdout` 9528 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9529 9530 Level: developer 9531 9532 Notes: 9533 This is mainly intended for debugging/testing purposes. 9534 9535 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9536 9537 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9538 @*/ 9539 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9540 { 9541 DM dmCoarse; 9542 cell_stats_t stats, globalStats; 9543 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9544 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9545 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9546 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9547 PetscMPIInt rank, size; 9548 9549 PetscFunctionBegin; 9550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9551 stats.min = PETSC_MAX_REAL; 9552 stats.max = PETSC_MIN_REAL; 9553 stats.sum = stats.squaresum = 0.; 9554 stats.count = 0; 9555 9556 PetscCallMPI(MPI_Comm_size(comm, &size)); 9557 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9558 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9559 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9560 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9561 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9562 for (c = cStart; c < cEnd; c++) { 9563 PetscInt i; 9564 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9565 9566 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9567 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9568 for (i = 0; i < PetscSqr(cdim); ++i) { 9569 frobJ += J[i] * J[i]; 9570 frobInvJ += invJ[i] * invJ[i]; 9571 } 9572 cond2 = frobJ * frobInvJ; 9573 cond = PetscSqrtReal(cond2); 9574 9575 stats.min = PetscMin(stats.min, cond); 9576 stats.max = PetscMax(stats.max, cond); 9577 stats.sum += cond; 9578 stats.squaresum += cond2; 9579 stats.count++; 9580 if (output && cond > limit) { 9581 PetscSection coordSection; 9582 Vec coordsLocal; 9583 PetscScalar *coords = NULL; 9584 PetscInt Nv, d, clSize, cl, *closure = NULL; 9585 9586 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9587 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9588 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9589 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9590 for (i = 0; i < Nv / cdim; ++i) { 9591 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9592 for (d = 0; d < cdim; ++d) { 9593 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9594 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9595 } 9596 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9597 } 9598 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9599 for (cl = 0; cl < clSize * 2; cl += 2) { 9600 const PetscInt edge = closure[cl]; 9601 9602 if ((edge >= eStart) && (edge < eEnd)) { 9603 PetscReal len; 9604 9605 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9606 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9607 } 9608 } 9609 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9610 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9611 } 9612 } 9613 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9614 9615 if (size > 1) { 9616 PetscMPIInt blockLengths[2] = {4, 1}; 9617 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9618 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9619 MPI_Op statReduce; 9620 9621 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9622 PetscCallMPI(MPI_Type_commit(&statType)); 9623 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9624 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9625 PetscCallMPI(MPI_Op_free(&statReduce)); 9626 PetscCallMPI(MPI_Type_free(&statType)); 9627 } else { 9628 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9629 } 9630 if (rank == 0) { 9631 count = globalStats.count; 9632 min = globalStats.min; 9633 max = globalStats.max; 9634 mean = globalStats.sum / globalStats.count; 9635 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9636 } 9637 9638 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)); 9639 PetscCall(PetscFree2(J, invJ)); 9640 9641 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9642 if (dmCoarse) { 9643 PetscBool isplex; 9644 9645 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9646 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9647 } 9648 PetscFunctionReturn(PETSC_SUCCESS); 9649 } 9650 9651 /*@ 9652 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9653 orthogonal quality below given tolerance. 9654 9655 Collective 9656 9657 Input Parameters: 9658 + dm - The `DMPLEX` object 9659 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9660 - atol - [0, 1] Absolute tolerance for tagging cells. 9661 9662 Output Parameters: 9663 + OrthQual - `Vec` containing orthogonal quality per cell 9664 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9665 9666 Options Database Keys: 9667 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9668 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9669 9670 Level: intermediate 9671 9672 Notes: 9673 Orthogonal quality is given by the following formula\: 9674 9675 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9676 9677 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 9678 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9679 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9680 calculating the cosine of the angle between these vectors. 9681 9682 Orthogonal quality ranges from 1 (best) to 0 (worst). 9683 9684 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9685 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9686 9687 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9688 9689 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9690 @*/ 9691 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9692 { 9693 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9694 PetscInt *idx; 9695 PetscScalar *oqVals; 9696 const PetscScalar *cellGeomArr, *faceGeomArr; 9697 PetscReal *ci, *fi, *Ai; 9698 MPI_Comm comm; 9699 Vec cellgeom, facegeom; 9700 DM dmFace, dmCell; 9701 IS glob; 9702 ISLocalToGlobalMapping ltog; 9703 PetscViewer vwr; 9704 9705 PetscFunctionBegin; 9706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9707 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9708 PetscAssertPointer(OrthQual, 4); 9709 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9710 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9711 PetscCall(DMGetDimension(dm, &nc)); 9712 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9713 { 9714 DMPlexInterpolatedFlag interpFlag; 9715 9716 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9717 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9718 PetscMPIInt rank; 9719 9720 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9721 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9722 } 9723 } 9724 if (OrthQualLabel) { 9725 PetscAssertPointer(OrthQualLabel, 5); 9726 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9727 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9728 } else { 9729 *OrthQualLabel = NULL; 9730 } 9731 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9732 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9733 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9734 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9735 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9736 PetscCall(VecCreate(comm, OrthQual)); 9737 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9738 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9739 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9740 PetscCall(VecSetUp(*OrthQual)); 9741 PetscCall(ISDestroy(&glob)); 9742 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9743 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9744 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9745 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9746 PetscCall(VecGetDM(cellgeom, &dmCell)); 9747 PetscCall(VecGetDM(facegeom, &dmFace)); 9748 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9749 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9750 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9751 PetscInt cellarr[2], *adj = NULL; 9752 PetscScalar *cArr, *fArr; 9753 PetscReal minvalc = 1.0, minvalf = 1.0; 9754 PetscFVCellGeom *cg; 9755 9756 idx[cellIter] = cell - cStart; 9757 cellarr[0] = cell; 9758 /* Make indexing into cellGeom easier */ 9759 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9760 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9761 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9762 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9763 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9764 PetscInt i; 9765 const PetscInt neigh = adj[cellneigh]; 9766 PetscReal normci = 0, normfi = 0, normai = 0; 9767 PetscFVCellGeom *cgneigh; 9768 PetscFVFaceGeom *fg; 9769 9770 /* Don't count ourselves in the neighbor list */ 9771 if (neigh == cell) continue; 9772 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9773 cellarr[1] = neigh; 9774 { 9775 PetscInt numcovpts; 9776 const PetscInt *covpts; 9777 9778 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9779 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9780 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9781 } 9782 9783 /* Compute c_i, f_i and their norms */ 9784 for (i = 0; i < nc; i++) { 9785 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9786 fi[i] = fg->centroid[i] - cg->centroid[i]; 9787 Ai[i] = fg->normal[i]; 9788 normci += PetscPowReal(ci[i], 2); 9789 normfi += PetscPowReal(fi[i], 2); 9790 normai += PetscPowReal(Ai[i], 2); 9791 } 9792 normci = PetscSqrtReal(normci); 9793 normfi = PetscSqrtReal(normfi); 9794 normai = PetscSqrtReal(normai); 9795 9796 /* Normalize and compute for each face-cell-normal pair */ 9797 for (i = 0; i < nc; i++) { 9798 ci[i] = ci[i] / normci; 9799 fi[i] = fi[i] / normfi; 9800 Ai[i] = Ai[i] / normai; 9801 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9802 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9803 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9804 } 9805 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9806 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9807 } 9808 PetscCall(PetscFree(adj)); 9809 PetscCall(PetscFree2(cArr, fArr)); 9810 /* Defer to cell if they're equal */ 9811 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9812 if (OrthQualLabel) { 9813 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9814 } 9815 } 9816 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9817 PetscCall(VecAssemblyBegin(*OrthQual)); 9818 PetscCall(VecAssemblyEnd(*OrthQual)); 9819 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9820 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9821 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9822 if (OrthQualLabel) { 9823 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9824 } 9825 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9826 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9827 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9828 PetscFunctionReturn(PETSC_SUCCESS); 9829 } 9830 9831 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9832 * interpolator construction */ 9833 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9834 { 9835 PetscSection section, newSection, gsection; 9836 PetscSF sf; 9837 PetscBool hasConstraints, ghasConstraints; 9838 9839 PetscFunctionBegin; 9840 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9841 PetscAssertPointer(odm, 2); 9842 PetscCall(DMGetLocalSection(dm, §ion)); 9843 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9844 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9845 if (!ghasConstraints) { 9846 PetscCall(PetscObjectReference((PetscObject)dm)); 9847 *odm = dm; 9848 PetscFunctionReturn(PETSC_SUCCESS); 9849 } 9850 PetscCall(DMClone(dm, odm)); 9851 PetscCall(DMCopyFields(dm, *odm)); 9852 PetscCall(DMGetLocalSection(*odm, &newSection)); 9853 PetscCall(DMGetPointSF(*odm, &sf)); 9854 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9855 PetscCall(DMSetGlobalSection(*odm, gsection)); 9856 PetscCall(PetscSectionDestroy(&gsection)); 9857 PetscFunctionReturn(PETSC_SUCCESS); 9858 } 9859 9860 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9861 { 9862 DM dmco, dmfo; 9863 Mat interpo; 9864 Vec rscale; 9865 Vec cglobalo, clocal; 9866 Vec fglobal, fglobalo, flocal; 9867 PetscBool regular; 9868 9869 PetscFunctionBegin; 9870 PetscCall(DMGetFullDM(dmc, &dmco)); 9871 PetscCall(DMGetFullDM(dmf, &dmfo)); 9872 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9873 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9874 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9875 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9876 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9877 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9878 PetscCall(VecSet(cglobalo, 0.)); 9879 PetscCall(VecSet(clocal, 0.)); 9880 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9881 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9882 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9883 PetscCall(VecSet(fglobal, 0.)); 9884 PetscCall(VecSet(fglobalo, 0.)); 9885 PetscCall(VecSet(flocal, 0.)); 9886 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9887 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9888 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9889 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9890 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9891 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9892 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9893 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9894 *shift = fglobal; 9895 PetscCall(VecDestroy(&flocal)); 9896 PetscCall(VecDestroy(&fglobalo)); 9897 PetscCall(VecDestroy(&clocal)); 9898 PetscCall(VecDestroy(&cglobalo)); 9899 PetscCall(VecDestroy(&rscale)); 9900 PetscCall(MatDestroy(&interpo)); 9901 PetscCall(DMDestroy(&dmfo)); 9902 PetscCall(DMDestroy(&dmco)); 9903 PetscFunctionReturn(PETSC_SUCCESS); 9904 } 9905 9906 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9907 { 9908 PetscObject shifto; 9909 Vec shift; 9910 9911 PetscFunctionBegin; 9912 if (!interp) { 9913 Vec rscale; 9914 9915 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9916 PetscCall(VecDestroy(&rscale)); 9917 } else { 9918 PetscCall(PetscObjectReference((PetscObject)interp)); 9919 } 9920 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9921 if (!shifto) { 9922 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9923 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9924 shifto = (PetscObject)shift; 9925 PetscCall(VecDestroy(&shift)); 9926 } 9927 shift = (Vec)shifto; 9928 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9929 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9930 PetscCall(MatDestroy(&interp)); 9931 PetscFunctionReturn(PETSC_SUCCESS); 9932 } 9933 9934 /* Pointwise interpolation 9935 Just code FEM for now 9936 u^f = I u^c 9937 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9938 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9939 I_{ij} = psi^f_i phi^c_j 9940 */ 9941 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9942 { 9943 PetscSection gsc, gsf; 9944 PetscInt m, n; 9945 void *ctx; 9946 DM cdm; 9947 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9948 9949 PetscFunctionBegin; 9950 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9951 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9952 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9953 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9954 9955 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9956 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9957 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9958 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9959 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9960 9961 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9962 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9963 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9964 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9965 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9966 if (scaling) { 9967 /* Use naive scaling */ 9968 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9969 } 9970 PetscFunctionReturn(PETSC_SUCCESS); 9971 } 9972 9973 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9974 { 9975 VecScatter ctx; 9976 9977 PetscFunctionBegin; 9978 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9979 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9980 PetscCall(VecScatterDestroy(&ctx)); 9981 PetscFunctionReturn(PETSC_SUCCESS); 9982 } 9983 9984 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[]) 9985 { 9986 const PetscInt Nc = uOff[1] - uOff[0]; 9987 PetscInt c; 9988 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9989 } 9990 9991 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9992 { 9993 DM dmc; 9994 PetscDS ds; 9995 Vec ones, locmass; 9996 IS cellIS; 9997 PetscFormKey key; 9998 PetscInt depth; 9999 10000 PetscFunctionBegin; 10001 PetscCall(DMClone(dm, &dmc)); 10002 PetscCall(DMCopyDisc(dm, dmc)); 10003 PetscCall(DMGetDS(dmc, &ds)); 10004 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10005 PetscCall(DMCreateGlobalVector(dmc, mass)); 10006 PetscCall(DMGetLocalVector(dmc, &ones)); 10007 PetscCall(DMGetLocalVector(dmc, &locmass)); 10008 PetscCall(DMPlexGetDepth(dmc, &depth)); 10009 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10010 PetscCall(VecSet(locmass, 0.0)); 10011 PetscCall(VecSet(ones, 1.0)); 10012 key.label = NULL; 10013 key.value = 0; 10014 key.field = 0; 10015 key.part = 0; 10016 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10017 PetscCall(ISDestroy(&cellIS)); 10018 PetscCall(VecSet(*mass, 0.0)); 10019 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 10020 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 10021 PetscCall(DMRestoreLocalVector(dmc, &ones)); 10022 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 10023 PetscCall(DMDestroy(&dmc)); 10024 PetscFunctionReturn(PETSC_SUCCESS); 10025 } 10026 10027 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10028 { 10029 PetscSection gsc, gsf; 10030 PetscInt m, n; 10031 void *ctx; 10032 DM cdm; 10033 PetscBool regular; 10034 10035 PetscFunctionBegin; 10036 if (dmFine == dmCoarse) { 10037 DM dmc; 10038 PetscDS ds; 10039 PetscWeakForm wf; 10040 Vec u; 10041 IS cellIS; 10042 PetscFormKey key; 10043 PetscInt depth; 10044 10045 PetscCall(DMClone(dmFine, &dmc)); 10046 PetscCall(DMCopyDisc(dmFine, dmc)); 10047 PetscCall(DMGetDS(dmc, &ds)); 10048 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10049 PetscCall(PetscWeakFormClear(wf)); 10050 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10051 PetscCall(DMCreateMatrix(dmc, mass)); 10052 PetscCall(DMGetLocalVector(dmc, &u)); 10053 PetscCall(DMPlexGetDepth(dmc, &depth)); 10054 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10055 PetscCall(MatZeroEntries(*mass)); 10056 key.label = NULL; 10057 key.value = 0; 10058 key.field = 0; 10059 key.part = 0; 10060 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10061 PetscCall(ISDestroy(&cellIS)); 10062 PetscCall(DMRestoreLocalVector(dmc, &u)); 10063 PetscCall(DMDestroy(&dmc)); 10064 } else { 10065 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10066 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10067 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10068 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10069 10070 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10071 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10072 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10073 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10074 10075 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10076 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10077 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10078 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10079 } 10080 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10081 PetscFunctionReturn(PETSC_SUCCESS); 10082 } 10083 10084 /*@ 10085 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10086 10087 Input Parameter: 10088 . dm - The `DMPLEX` object 10089 10090 Output Parameter: 10091 . regular - The flag 10092 10093 Level: intermediate 10094 10095 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10096 @*/ 10097 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10098 { 10099 PetscFunctionBegin; 10100 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10101 PetscAssertPointer(regular, 2); 10102 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10103 PetscFunctionReturn(PETSC_SUCCESS); 10104 } 10105 10106 /*@ 10107 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10108 10109 Input Parameters: 10110 + dm - The `DMPLEX` object 10111 - regular - The flag 10112 10113 Level: intermediate 10114 10115 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10116 @*/ 10117 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10118 { 10119 PetscFunctionBegin; 10120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10121 ((DM_Plex *)dm->data)->regularRefinement = regular; 10122 PetscFunctionReturn(PETSC_SUCCESS); 10123 } 10124 10125 /*@ 10126 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10127 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10128 10129 Not Collective 10130 10131 Input Parameter: 10132 . dm - The `DMPLEX` object 10133 10134 Output Parameters: 10135 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10136 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10137 10138 Level: intermediate 10139 10140 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10141 @*/ 10142 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10143 { 10144 DM_Plex *plex = (DM_Plex *)dm->data; 10145 10146 PetscFunctionBegin; 10147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10148 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10149 if (anchorSection) *anchorSection = plex->anchorSection; 10150 if (anchorIS) *anchorIS = plex->anchorIS; 10151 PetscFunctionReturn(PETSC_SUCCESS); 10152 } 10153 10154 /*@ 10155 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10156 10157 Collective 10158 10159 Input Parameters: 10160 + dm - The `DMPLEX` object 10161 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10162 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10163 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10164 10165 Level: intermediate 10166 10167 Notes: 10168 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10169 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10170 combination of other points' degrees of freedom. 10171 10172 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10173 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10174 10175 The reference counts of `anchorSection` and `anchorIS` are incremented. 10176 10177 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10178 @*/ 10179 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10180 { 10181 DM_Plex *plex = (DM_Plex *)dm->data; 10182 PetscMPIInt result; 10183 10184 PetscFunctionBegin; 10185 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10186 if (anchorSection) { 10187 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10188 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10189 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10190 } 10191 if (anchorIS) { 10192 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10193 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10194 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10195 } 10196 10197 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10198 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10199 plex->anchorSection = anchorSection; 10200 10201 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10202 PetscCall(ISDestroy(&plex->anchorIS)); 10203 plex->anchorIS = anchorIS; 10204 10205 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10206 PetscInt size, a, pStart, pEnd; 10207 const PetscInt *anchors; 10208 10209 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10210 PetscCall(ISGetLocalSize(anchorIS, &size)); 10211 PetscCall(ISGetIndices(anchorIS, &anchors)); 10212 for (a = 0; a < size; a++) { 10213 PetscInt p; 10214 10215 p = anchors[a]; 10216 if (p >= pStart && p < pEnd) { 10217 PetscInt dof; 10218 10219 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10220 if (dof) { 10221 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10222 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10223 } 10224 } 10225 } 10226 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10227 } 10228 /* reset the generic constraints */ 10229 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10230 PetscFunctionReturn(PETSC_SUCCESS); 10231 } 10232 10233 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10234 { 10235 PetscSection anchorSection; 10236 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10237 10238 PetscFunctionBegin; 10239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10240 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10241 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10242 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10243 if (numFields) { 10244 PetscInt f; 10245 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10246 10247 for (f = 0; f < numFields; f++) { 10248 PetscInt numComp; 10249 10250 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10251 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10252 } 10253 } 10254 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10255 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10256 pStart = PetscMax(pStart, sStart); 10257 pEnd = PetscMin(pEnd, sEnd); 10258 pEnd = PetscMax(pStart, pEnd); 10259 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10260 for (p = pStart; p < pEnd; p++) { 10261 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10262 if (dof) { 10263 PetscCall(PetscSectionGetDof(section, p, &dof)); 10264 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10265 for (f = 0; f < numFields; f++) { 10266 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10267 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10268 } 10269 } 10270 } 10271 PetscCall(PetscSectionSetUp(*cSec)); 10272 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10273 PetscFunctionReturn(PETSC_SUCCESS); 10274 } 10275 10276 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10277 { 10278 PetscSection aSec; 10279 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10280 const PetscInt *anchors; 10281 PetscInt numFields, f; 10282 IS aIS; 10283 MatType mtype; 10284 PetscBool iscuda, iskokkos; 10285 10286 PetscFunctionBegin; 10287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10288 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10289 PetscCall(PetscSectionGetStorageSize(section, &n)); 10290 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10291 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10292 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10293 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10294 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10295 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10296 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10297 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10298 else mtype = MATSEQAIJ; 10299 PetscCall(MatSetType(*cMat, mtype)); 10300 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10301 PetscCall(ISGetIndices(aIS, &anchors)); 10302 /* cSec will be a subset of aSec and section */ 10303 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10304 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10305 PetscCall(PetscMalloc1(m + 1, &i)); 10306 i[0] = 0; 10307 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10308 for (p = pStart; p < pEnd; p++) { 10309 PetscInt rDof, rOff, r; 10310 10311 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10312 if (!rDof) continue; 10313 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10314 if (numFields) { 10315 for (f = 0; f < numFields; f++) { 10316 annz = 0; 10317 for (r = 0; r < rDof; r++) { 10318 a = anchors[rOff + r]; 10319 if (a < sStart || a >= sEnd) continue; 10320 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10321 annz += aDof; 10322 } 10323 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10324 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10325 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10326 } 10327 } else { 10328 annz = 0; 10329 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10330 for (q = 0; q < dof; q++) { 10331 a = anchors[rOff + q]; 10332 if (a < sStart || a >= sEnd) continue; 10333 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10334 annz += aDof; 10335 } 10336 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10337 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10338 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10339 } 10340 } 10341 nnz = i[m]; 10342 PetscCall(PetscMalloc1(nnz, &j)); 10343 offset = 0; 10344 for (p = pStart; p < pEnd; p++) { 10345 if (numFields) { 10346 for (f = 0; f < numFields; f++) { 10347 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10348 for (q = 0; q < dof; q++) { 10349 PetscInt rDof, rOff, r; 10350 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10351 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10352 for (r = 0; r < rDof; r++) { 10353 PetscInt s; 10354 10355 a = anchors[rOff + r]; 10356 if (a < sStart || a >= sEnd) continue; 10357 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10358 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10359 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10360 } 10361 } 10362 } 10363 } else { 10364 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10365 for (q = 0; q < dof; q++) { 10366 PetscInt rDof, rOff, r; 10367 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10368 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10369 for (r = 0; r < rDof; r++) { 10370 PetscInt s; 10371 10372 a = anchors[rOff + r]; 10373 if (a < sStart || a >= sEnd) continue; 10374 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10375 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10376 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10377 } 10378 } 10379 } 10380 } 10381 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10382 PetscCall(PetscFree(i)); 10383 PetscCall(PetscFree(j)); 10384 PetscCall(ISRestoreIndices(aIS, &anchors)); 10385 PetscFunctionReturn(PETSC_SUCCESS); 10386 } 10387 10388 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10389 { 10390 DM_Plex *plex = (DM_Plex *)dm->data; 10391 PetscSection anchorSection, section, cSec; 10392 Mat cMat; 10393 10394 PetscFunctionBegin; 10395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10396 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10397 if (anchorSection) { 10398 PetscInt Nf; 10399 10400 PetscCall(DMGetLocalSection(dm, §ion)); 10401 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10402 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10403 PetscCall(DMGetNumFields(dm, &Nf)); 10404 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10405 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10406 PetscCall(PetscSectionDestroy(&cSec)); 10407 PetscCall(MatDestroy(&cMat)); 10408 } 10409 PetscFunctionReturn(PETSC_SUCCESS); 10410 } 10411 10412 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10413 { 10414 IS subis; 10415 PetscSection section, subsection; 10416 10417 PetscFunctionBegin; 10418 PetscCall(DMGetLocalSection(dm, §ion)); 10419 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10420 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10421 /* Create subdomain */ 10422 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10423 /* Create submodel */ 10424 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10425 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10426 PetscCall(DMSetLocalSection(*subdm, subsection)); 10427 PetscCall(PetscSectionDestroy(&subsection)); 10428 PetscCall(DMCopyDisc(dm, *subdm)); 10429 /* Create map from submodel to global model */ 10430 if (is) { 10431 PetscSection sectionGlobal, subsectionGlobal; 10432 IS spIS; 10433 const PetscInt *spmap; 10434 PetscInt *subIndices; 10435 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10436 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10437 10438 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10439 PetscCall(ISGetIndices(spIS, &spmap)); 10440 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10441 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10442 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10443 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10444 for (p = pStart; p < pEnd; ++p) { 10445 PetscInt gdof, pSubSize = 0; 10446 10447 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10448 if (gdof > 0) { 10449 for (f = 0; f < Nf; ++f) { 10450 PetscInt fdof, fcdof; 10451 10452 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10453 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10454 pSubSize += fdof - fcdof; 10455 } 10456 subSize += pSubSize; 10457 if (pSubSize) { 10458 if (bs < 0) { 10459 bs = pSubSize; 10460 } else if (bs != pSubSize) { 10461 /* Layout does not admit a pointwise block size */ 10462 bs = 1; 10463 } 10464 } 10465 } 10466 } 10467 /* Must have same blocksize on all procs (some might have no points) */ 10468 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10469 bsLocal[1] = bs; 10470 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10471 if (bsMinMax[0] != bsMinMax[1]) { 10472 bs = 1; 10473 } else { 10474 bs = bsMinMax[0]; 10475 } 10476 PetscCall(PetscMalloc1(subSize, &subIndices)); 10477 for (p = pStart; p < pEnd; ++p) { 10478 PetscInt gdof, goff; 10479 10480 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10481 if (gdof > 0) { 10482 const PetscInt point = spmap[p]; 10483 10484 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10485 for (f = 0; f < Nf; ++f) { 10486 PetscInt fdof, fcdof, fc, f2, poff = 0; 10487 10488 /* Can get rid of this loop by storing field information in the global section */ 10489 for (f2 = 0; f2 < f; ++f2) { 10490 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10491 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10492 poff += fdof - fcdof; 10493 } 10494 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10495 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10496 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10497 } 10498 } 10499 } 10500 PetscCall(ISRestoreIndices(spIS, &spmap)); 10501 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10502 if (bs > 1) { 10503 /* We need to check that the block size does not come from non-contiguous fields */ 10504 PetscInt i, j, set = 1; 10505 for (i = 0; i < subSize; i += bs) { 10506 for (j = 0; j < bs; ++j) { 10507 if (subIndices[i + j] != subIndices[i] + j) { 10508 set = 0; 10509 break; 10510 } 10511 } 10512 } 10513 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10514 } 10515 /* Attach nullspace */ 10516 for (f = 0; f < Nf; ++f) { 10517 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10518 if ((*subdm)->nullspaceConstructors[f]) break; 10519 } 10520 if (f < Nf) { 10521 MatNullSpace nullSpace; 10522 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10523 10524 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10525 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10526 } 10527 } 10528 PetscFunctionReturn(PETSC_SUCCESS); 10529 } 10530 10531 /*@ 10532 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10533 10534 Input Parameters: 10535 + dm - The `DM` 10536 - dummy - unused argument 10537 10538 Options Database Key: 10539 . -dm_plex_monitor_throughput - Activate the monitor 10540 10541 Level: developer 10542 10543 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10544 @*/ 10545 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10546 { 10547 PetscLogHandler default_handler; 10548 10549 PetscFunctionBegin; 10550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10551 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10552 if (default_handler) { 10553 PetscLogEvent event; 10554 PetscEventPerfInfo eventInfo; 10555 PetscReal cellRate, flopRate; 10556 PetscInt cStart, cEnd, Nf, N; 10557 const char *name; 10558 10559 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10560 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10561 PetscCall(DMGetNumFields(dm, &Nf)); 10562 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10563 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10564 N = (cEnd - cStart) * Nf * eventInfo.count; 10565 flopRate = eventInfo.flops / eventInfo.time; 10566 cellRate = N / eventInfo.time; 10567 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))); 10568 } else { 10569 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."); 10570 } 10571 PetscFunctionReturn(PETSC_SUCCESS); 10572 } 10573