1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 #include <petscblaslapack.h> 12 13 /* Logging support */ 14 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 15 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 16 17 PetscBool Plexcite = PETSC_FALSE; 18 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 19 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 20 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 21 "journal = {SIAM Journal on Scientific Computing},\n" 22 "volume = {38},\n" 23 "number = {5},\n" 24 "pages = {S143--S155},\n" 25 "eprint = {http://arxiv.org/abs/1506.07749},\n" 26 "doi = {10.1137/15M1026092},\n" 27 "year = {2016},\n" 28 "petsc_uses={DMPlex},\n}\n"; 29 30 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 31 32 /*@ 33 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 34 35 Input Parameter: 36 . dm - The `DMPLEX` object 37 38 Output Parameter: 39 . simplex - Flag checking for a simplex 40 41 Level: intermediate 42 43 Note: 44 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 45 If the mesh has no cells, this returns `PETSC_FALSE`. 46 47 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 48 @*/ 49 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 50 { 51 DMPolytopeType ct; 52 PetscInt cStart, cEnd; 53 54 PetscFunctionBegin; 55 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 56 if (cEnd <= cStart) { 57 *simplex = PETSC_FALSE; 58 PetscFunctionReturn(PETSC_SUCCESS); 59 } 60 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 61 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 /*@ 66 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 67 68 Input Parameters: 69 + dm - The `DMPLEX` object 70 - height - The cell height in the Plex, 0 is the default 71 72 Output Parameters: 73 + cStart - The first "normal" cell 74 - cEnd - The upper bound on "normal" cells 75 76 Level: developer 77 78 Note: 79 This function requires that tensor cells are ordered last. 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 82 @*/ 83 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 84 { 85 DMLabel ctLabel; 86 IS valueIS; 87 const PetscInt *ctypes; 88 PetscBool found = PETSC_FALSE; 89 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 90 91 PetscFunctionBegin; 92 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 93 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 94 PetscCall(ISGetLocalSize(valueIS, &Nct)); 95 PetscCall(ISGetIndices(valueIS, &ctypes)); 96 for (PetscInt t = 0; t < Nct; ++t) { 97 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 98 PetscInt ctS, ctE, ht; 99 100 if (ct == DM_POLYTOPE_UNKNOWN) { 101 // If any cells are not typed, just use all cells 102 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 103 break; 104 } 105 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 106 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 107 if (ctS >= ctE) continue; 108 // Check that a point has the right height 109 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 110 if (ht != height) continue; 111 cS = PetscMin(cS, ctS); 112 cE = PetscMax(cE, ctE); 113 found = PETSC_TRUE; 114 } 115 if (!Nct || !found) cS = cE = 0; 116 PetscCall(ISDestroy(&valueIS)); 117 // Reset label for fast lookup 118 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 119 if (cStart) *cStart = cS; 120 if (cEnd) *cEnd = cE; 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 125 { 126 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 127 PetscInt *sStart, *sEnd; 128 PetscViewerVTKFieldType *ft; 129 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 130 DMLabel depthLabel, ctLabel; 131 132 PetscFunctionBegin; 133 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 134 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 135 PetscCall(DMGetCoordinateDim(dm, &cdim)); 136 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 137 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 138 if (field >= 0) { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 140 } else { 141 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 142 } 143 144 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 145 PetscCall(DMPlexGetDepth(dm, &depth)); 146 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 147 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 148 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 149 const DMPolytopeType ict = (DMPolytopeType)c; 150 PetscInt dep; 151 152 if (ict == DM_POLYTOPE_FV_GHOST) continue; 153 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 154 if (pStart >= 0) { 155 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 156 if (dep != depth - cellHeight) continue; 157 } 158 if (field >= 0) { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 160 } else { 161 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 162 } 163 } 164 165 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 166 *types = 0; 167 168 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 169 if (globalvcdof[c]) ++(*types); 170 } 171 172 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 173 t = 0; 174 if (globalvcdof[DM_NUM_POLYTOPES]) { 175 sStart[t] = vStart; 176 sEnd[t] = vEnd; 177 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 178 ++t; 179 } 180 181 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 182 if (globalvcdof[c]) { 183 const DMPolytopeType ict = (DMPolytopeType)c; 184 185 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 186 sStart[t] = cStart; 187 sEnd[t] = cEnd; 188 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 189 ++t; 190 } 191 } 192 193 if (!*types) { 194 if (field >= 0) { 195 const char *fieldname; 196 197 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 198 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 199 } else { 200 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 201 } 202 } 203 204 *ssStart = sStart; 205 *ssEnd = sEnd; 206 *sft = ft; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 211 { 212 PetscFunctionBegin; 213 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 217 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 218 { 219 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 220 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 221 222 PetscFunctionBegin; 223 *ft = PETSC_VTK_INVALID; 224 PetscCall(DMGetCoordinateDim(dm, &cdim)); 225 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 226 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 227 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 228 if (field >= 0) { 229 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 230 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 231 } else { 232 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 233 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 234 } 235 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 PetscDS ds; 277 PetscDraw draw = NULL; 278 PetscDrawLG lg; 279 Vec coordinates; 280 const PetscScalar *coords, **sol; 281 PetscReal *vals; 282 PetscInt *Nc; 283 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 284 char **names; 285 286 PetscFunctionBegin; 287 PetscCall(DMGetDS(dm, &ds)); 288 PetscCall(PetscDSGetNumFields(ds, &Nf)); 289 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 290 PetscCall(PetscDSGetComponents(ds, &Nc)); 291 292 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 293 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 294 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 295 296 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 297 for (i = 0, l = 0; i < n; ++i) { 298 const char *vname; 299 300 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 301 for (f = 0; f < Nf; ++f) { 302 PetscObject disc; 303 const char *fname; 304 char tmpname[PETSC_MAX_PATH_LEN]; 305 306 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 307 /* TODO Create names for components */ 308 for (c = 0; c < Nc[f]; ++c, ++l) { 309 PetscCall(PetscObjectGetName(disc, &fname)); 310 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 312 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 313 PetscCall(PetscStrallocpy(tmpname, &names[l])); 314 } 315 } 316 } 317 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 318 /* Just add P_1 support for now */ 319 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 for (v = vStart; v < vEnd; ++v) { 324 PetscScalar *x, *svals; 325 326 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 327 for (i = 0; i < n; ++i) { 328 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 329 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 330 } 331 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 332 } 333 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 334 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 335 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 336 PetscCall(PetscFree3(sol, names, vals)); 337 338 PetscCall(PetscDrawLGDraw(lg)); 339 PetscCall(PetscDrawLGDestroy(&lg)); 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 343 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 344 { 345 DM dm; 346 347 PetscFunctionBegin; 348 PetscCall(VecGetDM(u, &dm)); 349 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 350 PetscFunctionReturn(PETSC_SUCCESS); 351 } 352 353 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 354 { 355 DM dm; 356 PetscSection s; 357 PetscDraw draw, popup; 358 DM cdm; 359 PetscSection coordSection; 360 Vec coordinates; 361 const PetscScalar *array; 362 PetscReal lbound[3], ubound[3]; 363 PetscReal vbound[2], time; 364 PetscBool flg; 365 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 366 const char *name; 367 char title[PETSC_MAX_PATH_LEN]; 368 369 PetscFunctionBegin; 370 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 371 PetscCall(VecGetDM(v, &dm)); 372 PetscCall(DMGetCoordinateDim(dm, &dim)); 373 PetscCall(DMGetLocalSection(dm, &s)); 374 PetscCall(PetscSectionGetNumFields(s, &Nf)); 375 PetscCall(DMGetCoarsenLevel(dm, &level)); 376 PetscCall(DMGetCoordinateDM(dm, &cdm)); 377 PetscCall(DMGetLocalSection(cdm, &coordSection)); 378 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 379 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 380 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 381 382 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 383 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 384 385 PetscCall(VecGetLocalSize(coordinates, &N)); 386 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 387 PetscCall(PetscDrawClear(draw)); 388 389 /* Could implement something like DMDASelectFields() */ 390 for (f = 0; f < Nf; ++f) { 391 DM fdm = dm; 392 Vec fv = v; 393 IS fis; 394 char prefix[PETSC_MAX_PATH_LEN]; 395 const char *fname; 396 397 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 398 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 399 400 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 401 else prefix[0] = '\0'; 402 if (Nf > 1) { 403 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 404 PetscCall(VecGetSubVector(v, fis, &fv)); 405 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 406 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 407 } 408 for (comp = 0; comp < Nc; ++comp, ++w) { 409 PetscInt nmax = 2; 410 411 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 412 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 413 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 414 PetscCall(PetscDrawSetTitle(draw, title)); 415 416 /* TODO Get max and min only for this component */ 417 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 418 if (!flg) { 419 PetscCall(VecMin(fv, NULL, &vbound[0])); 420 PetscCall(VecMax(fv, NULL, &vbound[1])); 421 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 422 } 423 424 PetscCall(PetscDrawGetPopup(draw, &popup)); 425 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 426 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 427 PetscCall(VecGetArrayRead(fv, &array)); 428 for (c = cStart; c < cEnd; ++c) { 429 PetscScalar *coords = NULL, *a = NULL; 430 const PetscScalar *coords_arr; 431 PetscBool isDG; 432 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 433 434 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 435 if (a) { 436 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 437 color[1] = color[2] = color[3] = color[0]; 438 } else { 439 PetscScalar *vals = NULL; 440 PetscInt numVals, va; 441 442 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 443 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); 444 switch (numVals / Nc) { 445 case 3: /* P1 Triangle */ 446 case 4: /* P1 Quadrangle */ 447 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 448 break; 449 case 6: /* P2 Triangle */ 450 case 8: /* P2 Quadrangle */ 451 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 452 break; 453 default: 454 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 455 } 456 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 457 } 458 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 459 switch (numCoords) { 460 case 6: 461 case 12: /* Localized triangle */ 462 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])); 463 break; 464 case 8: 465 case 16: /* Localized quadrilateral */ 466 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])); 467 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])); 468 break; 469 default: 470 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 471 } 472 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 473 } 474 PetscCall(VecRestoreArrayRead(fv, &array)); 475 PetscCall(PetscDrawFlush(draw)); 476 PetscCall(PetscDrawPause(draw)); 477 PetscCall(PetscDrawSave(draw)); 478 } 479 if (Nf > 1) { 480 PetscCall(VecRestoreSubVector(v, fis, &fv)); 481 PetscCall(ISDestroy(&fis)); 482 PetscCall(DMDestroy(&fdm)); 483 } 484 } 485 PetscFunctionReturn(PETSC_SUCCESS); 486 } 487 488 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 489 { 490 DM dm; 491 PetscDraw draw; 492 PetscInt dim; 493 PetscBool isnull; 494 495 PetscFunctionBegin; 496 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 497 PetscCall(PetscDrawIsNull(draw, &isnull)); 498 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 499 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCall(DMGetCoordinateDim(dm, &dim)); 502 switch (dim) { 503 case 1: 504 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 505 break; 506 case 2: 507 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 508 break; 509 default: 510 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 511 } 512 PetscFunctionReturn(PETSC_SUCCESS); 513 } 514 515 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 516 { 517 DM dm; 518 Vec locv; 519 const char *name; 520 PetscSection section; 521 PetscInt pStart, pEnd; 522 PetscInt numFields; 523 PetscViewerVTKFieldType ft; 524 525 PetscFunctionBegin; 526 PetscCall(VecGetDM(v, &dm)); 527 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 528 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 529 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 530 PetscCall(VecCopy(v, locv)); 531 PetscCall(DMGetLocalSection(dm, §ion)); 532 PetscCall(PetscSectionGetNumFields(section, &numFields)); 533 if (!numFields) { 534 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 535 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 536 } else { 537 PetscInt f; 538 539 for (f = 0; f < numFields; f++) { 540 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 541 if (ft == PETSC_VTK_INVALID) continue; 542 PetscCall(PetscObjectReference((PetscObject)locv)); 543 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 544 } 545 PetscCall(VecDestroy(&locv)); 546 } 547 PetscFunctionReturn(PETSC_SUCCESS); 548 } 549 550 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 551 { 552 DM dm; 553 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 554 555 PetscFunctionBegin; 556 PetscCall(VecGetDM(v, &dm)); 557 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 562 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 563 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 564 PetscInt i, numFields; 565 PetscObject fe; 566 PetscBool fem = PETSC_FALSE; 567 Vec locv = v; 568 const char *name; 569 PetscInt step; 570 PetscReal time; 571 572 PetscCall(DMGetNumFields(dm, &numFields)); 573 for (i = 0; i < numFields; i++) { 574 PetscCall(DMGetField(dm, i, NULL, &fe)); 575 if (fe->classid == PETSCFE_CLASSID) { 576 fem = PETSC_TRUE; 577 break; 578 } 579 } 580 if (fem) { 581 PetscObject isZero; 582 583 PetscCall(DMGetLocalVector(dm, &locv)); 584 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 585 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 586 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 587 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 588 PetscCall(VecCopy(v, locv)); 589 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 590 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 591 } 592 if (isvtk) { 593 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 594 } else if (ishdf5) { 595 #if defined(PETSC_HAVE_HDF5) 596 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 597 #else 598 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 599 #endif 600 } else if (isdraw) { 601 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 602 } else if (isglvis) { 603 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 604 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 605 PetscCall(VecView_GLVis(locv, viewer)); 606 } else if (iscgns) { 607 #if defined(PETSC_HAVE_CGNS) 608 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 609 #else 610 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 611 #endif 612 } 613 if (fem) { 614 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 615 PetscCall(DMRestoreLocalVector(dm, &locv)); 616 } 617 } else { 618 PetscBool isseq; 619 620 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 621 if (isseq) PetscCall(VecView_Seq(v, viewer)); 622 else PetscCall(VecView_MPI(v, viewer)); 623 } 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 640 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 641 if (isvtk || isdraw || isglvis || iscgns) { 642 Vec locv; 643 PetscObject isZero; 644 const char *name; 645 646 PetscCall(DMGetLocalVector(dm, &locv)); 647 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 648 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 649 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 650 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 651 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 652 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 653 PetscCall(VecView_Plex_Local(locv, viewer)); 654 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 655 PetscCall(DMRestoreLocalVector(dm, &locv)); 656 /* Call flush for proper logging of VecView timings */ 657 if (isvtk) PetscCall(PetscViewerFlush(viewer)); 658 } else if (ishdf5) { 659 #if defined(PETSC_HAVE_HDF5) 660 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 661 #else 662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 663 #endif 664 } else if (isexodusii) { 665 #if defined(PETSC_HAVE_EXODUSII) 666 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 667 #else 668 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 669 #endif 670 } else { 671 PetscBool isseq; 672 673 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 674 if (isseq) PetscCall(VecView_Seq(v, viewer)); 675 else PetscCall(VecView_MPI(v, viewer)); 676 } 677 PetscFunctionReturn(PETSC_SUCCESS); 678 } 679 680 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 681 { 682 DM dm; 683 MPI_Comm comm; 684 PetscViewerFormat format; 685 Vec v; 686 PetscBool isvtk, ishdf5; 687 688 PetscFunctionBegin; 689 PetscCall(VecGetDM(originalv, &dm)); 690 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 691 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 692 PetscCall(PetscViewerGetFormat(viewer, &format)); 693 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 694 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 695 if (format == PETSC_VIEWER_NATIVE) { 696 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 697 /* this need a better fix */ 698 if (dm->useNatural) { 699 if (dm->sfNatural) { 700 const char *vecname; 701 PetscInt n, nroots; 702 703 PetscCall(VecGetLocalSize(originalv, &n)); 704 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 705 if (n == nroots) { 706 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 707 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 708 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 709 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 710 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 711 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 712 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 713 } else v = originalv; 714 } else v = originalv; 715 716 if (ishdf5) { 717 #if defined(PETSC_HAVE_HDF5) 718 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 719 #else 720 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 721 #endif 722 } else if (isvtk) { 723 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 724 } else { 725 PetscBool isseq; 726 727 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 728 if (isseq) PetscCall(VecView_Seq(v, viewer)); 729 else PetscCall(VecView_MPI(v, viewer)); 730 } 731 if (v != originalv) PetscCall(VecDestroy(&v)); 732 PetscFunctionReturn(PETSC_SUCCESS); 733 } 734 735 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 736 { 737 DM dm; 738 PetscBool ishdf5; 739 740 PetscFunctionBegin; 741 PetscCall(VecGetDM(v, &dm)); 742 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 743 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 744 if (ishdf5) { 745 DM dmBC; 746 Vec gv; 747 const char *name; 748 749 PetscCall(DMGetOutputDM(dm, &dmBC)); 750 PetscCall(DMGetGlobalVector(dmBC, &gv)); 751 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 752 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 753 PetscCall(VecLoad_Default(gv, viewer)); 754 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 755 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 756 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 757 } else PetscCall(VecLoad_Default(v, viewer)); 758 PetscFunctionReturn(PETSC_SUCCESS); 759 } 760 761 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 762 { 763 DM dm; 764 PetscBool ishdf5, isexodusii; 765 766 PetscFunctionBegin; 767 PetscCall(VecGetDM(v, &dm)); 768 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 769 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 770 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 771 if (ishdf5) { 772 #if defined(PETSC_HAVE_HDF5) 773 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 774 #else 775 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 776 #endif 777 } else if (isexodusii) { 778 #if defined(PETSC_HAVE_EXODUSII) 779 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 780 #else 781 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 782 #endif 783 } else PetscCall(VecLoad_Default(v, viewer)); 784 PetscFunctionReturn(PETSC_SUCCESS); 785 } 786 787 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 788 { 789 DM dm; 790 PetscViewerFormat format; 791 PetscBool ishdf5; 792 793 PetscFunctionBegin; 794 PetscCall(VecGetDM(originalv, &dm)); 795 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 796 PetscCall(PetscViewerGetFormat(viewer, &format)); 797 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 798 if (format == PETSC_VIEWER_NATIVE) { 799 if (dm->useNatural) { 800 if (dm->sfNatural) { 801 if (ishdf5) { 802 #if defined(PETSC_HAVE_HDF5) 803 Vec v; 804 const char *vecname; 805 806 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 807 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 808 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 809 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 810 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 811 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 812 PetscCall(VecDestroy(&v)); 813 #else 814 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 815 #endif 816 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 817 } 818 } else PetscCall(VecLoad_Default(originalv, viewer)); 819 } 820 PetscFunctionReturn(PETSC_SUCCESS); 821 } 822 823 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 824 { 825 PetscSection coordSection; 826 Vec coordinates; 827 DMLabel depthLabel, celltypeLabel; 828 const char *name[4]; 829 const PetscScalar *a; 830 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 831 832 PetscFunctionBegin; 833 PetscCall(DMGetDimension(dm, &dim)); 834 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 835 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 836 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 837 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 838 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 839 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 840 PetscCall(VecGetArrayRead(coordinates, &a)); 841 name[0] = "vertex"; 842 name[1] = "edge"; 843 name[dim - 1] = "face"; 844 name[dim] = "cell"; 845 for (c = cStart; c < cEnd; ++c) { 846 PetscInt *closure = NULL; 847 PetscInt closureSize, cl, ct; 848 849 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 850 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 851 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 852 PetscCall(PetscViewerASCIIPushTab(viewer)); 853 for (cl = 0; cl < closureSize * 2; cl += 2) { 854 PetscInt point = closure[cl], depth, dof, off, d, p; 855 856 if ((point < pStart) || (point >= pEnd)) continue; 857 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 858 if (!dof) continue; 859 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 860 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 862 for (p = 0; p < dof / dim; ++p) { 863 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 864 for (d = 0; d < dim; ++d) { 865 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 866 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 867 } 868 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 869 } 870 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 871 } 872 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 873 PetscCall(PetscViewerASCIIPopTab(viewer)); 874 } 875 PetscCall(VecRestoreArrayRead(coordinates, &a)); 876 PetscFunctionReturn(PETSC_SUCCESS); 877 } 878 879 typedef enum { 880 CS_CARTESIAN, 881 CS_POLAR, 882 CS_CYLINDRICAL, 883 CS_SPHERICAL 884 } CoordSystem; 885 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 886 887 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 888 { 889 PetscInt i; 890 891 PetscFunctionBegin; 892 if (dim > 3) { 893 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 894 } else { 895 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 896 897 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 898 switch (cs) { 899 case CS_CARTESIAN: 900 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 901 break; 902 case CS_POLAR: 903 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 904 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 905 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 906 break; 907 case CS_CYLINDRICAL: 908 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 909 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 910 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 911 trcoords[2] = coords[2]; 912 break; 913 case CS_SPHERICAL: 914 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 915 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 916 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 917 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 918 break; 919 } 920 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 921 } 922 PetscFunctionReturn(PETSC_SUCCESS); 923 } 924 925 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 926 { 927 DM_Plex *mesh = (DM_Plex *)dm->data; 928 DM cdm, cdmCell; 929 PetscSection coordSection, coordSectionCell; 930 Vec coordinates, coordinatesCell; 931 PetscViewerFormat format; 932 933 PetscFunctionBegin; 934 PetscCall(PetscViewerGetFormat(viewer, &format)); 935 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 936 const char *name; 937 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 938 PetscInt pStart, pEnd, p, numLabels, l; 939 PetscMPIInt rank, size; 940 941 PetscCall(DMGetCoordinateDM(dm, &cdm)); 942 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 943 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 944 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 945 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 946 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 947 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 948 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 949 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 950 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 951 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 952 PetscCall(DMGetDimension(dm, &dim)); 953 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 954 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 955 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 956 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 957 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 958 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 959 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 960 for (p = pStart; p < pEnd; ++p) { 961 PetscInt dof, off, s; 962 963 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 964 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 965 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 966 } 967 PetscCall(PetscViewerFlush(viewer)); 968 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 969 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 970 for (p = pStart; p < pEnd; ++p) { 971 PetscInt dof, off, c; 972 973 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 974 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 975 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])); 976 } 977 PetscCall(PetscViewerFlush(viewer)); 978 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 979 if (coordSection && coordinates) { 980 CoordSystem cs = CS_CARTESIAN; 981 const PetscScalar *array, *arrayCell = NULL; 982 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 983 PetscMPIInt rank; 984 const char *name; 985 986 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 987 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 988 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 989 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 990 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 991 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 992 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 993 pStart = PetscMin(pvStart, pcStart); 994 pEnd = PetscMax(pvEnd, pcEnd); 995 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 996 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 997 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 998 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 999 1000 PetscCall(VecGetArrayRead(coordinates, &array)); 1001 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1002 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1003 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1004 for (p = pStart; p < pEnd; ++p) { 1005 PetscInt dof, off; 1006 1007 if (p >= pvStart && p < pvEnd) { 1008 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1009 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1010 if (dof) { 1011 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1012 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1013 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1014 } 1015 } 1016 if (cdmCell && p >= pcStart && p < pcEnd) { 1017 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1018 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1019 if (dof) { 1020 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1021 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1022 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1023 } 1024 } 1025 } 1026 PetscCall(PetscViewerFlush(viewer)); 1027 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1028 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1029 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1030 } 1031 PetscCall(DMGetNumLabels(dm, &numLabels)); 1032 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1033 for (l = 0; l < numLabels; ++l) { 1034 DMLabel label; 1035 PetscBool isdepth; 1036 const char *name; 1037 1038 PetscCall(DMGetLabelName(dm, l, &name)); 1039 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1040 if (isdepth) continue; 1041 PetscCall(DMGetLabel(dm, name, &label)); 1042 PetscCall(DMLabelView(label, viewer)); 1043 } 1044 if (size > 1) { 1045 PetscSF sf; 1046 1047 PetscCall(DMGetPointSF(dm, &sf)); 1048 PetscCall(PetscSFView(sf, viewer)); 1049 } 1050 if (mesh->periodic.face_sfs) 1051 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1052 PetscCall(PetscViewerFlush(viewer)); 1053 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1054 const char *name, *color; 1055 const char *defcolors[3] = {"gray", "orange", "green"}; 1056 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1057 char lname[PETSC_MAX_PATH_LEN]; 1058 PetscReal scale = 2.0; 1059 PetscReal tikzscale = 1.0; 1060 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1061 double tcoords[3]; 1062 PetscScalar *coords; 1063 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, fStart = 0, fEnd = 0, e, p, n; 1064 PetscMPIInt rank, size; 1065 char **names, **colors, **lcolors; 1066 PetscBool flg, lflg; 1067 PetscBT wp = NULL; 1068 PetscInt pEnd, pStart; 1069 1070 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1071 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1072 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1073 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1074 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1075 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1076 PetscCall(DMGetDimension(dm, &dim)); 1077 PetscCall(DMPlexGetDepth(dm, &depth)); 1078 PetscCall(DMGetNumLabels(dm, &numLabels)); 1079 numLabels = PetscMax(numLabels, 10); 1080 numColors = 10; 1081 numLColors = 10; 1082 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1083 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1084 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1085 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1086 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1087 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1088 n = 4; 1089 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1090 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1091 n = 4; 1092 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1093 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1094 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1095 if (!useLabels) numLabels = 0; 1096 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1097 if (!useColors) { 1098 numColors = 3; 1099 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1100 } 1101 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1102 if (!useColors) { 1103 numLColors = 4; 1104 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1105 } 1106 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1107 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1108 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1109 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1110 if (depth < dim) plotEdges = PETSC_FALSE; 1111 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1112 1113 /* filter points with labelvalue != labeldefaultvalue */ 1114 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1115 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1116 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1117 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1118 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1119 if (lflg) { 1120 DMLabel lbl; 1121 1122 PetscCall(DMGetLabel(dm, lname, &lbl)); 1123 if (lbl) { 1124 PetscInt val, defval; 1125 1126 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1127 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1128 for (c = pStart; c < pEnd; c++) { 1129 PetscInt *closure = NULL; 1130 PetscInt closureSize; 1131 1132 PetscCall(DMLabelGetValue(lbl, c, &val)); 1133 if (val == defval) continue; 1134 1135 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1136 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1137 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1138 } 1139 } 1140 } 1141 1142 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1143 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1144 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1145 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1146 \\documentclass[tikz]{standalone}\n\n\ 1147 \\usepackage{pgflibraryshapes}\n\ 1148 \\usetikzlibrary{backgrounds}\n\ 1149 \\usetikzlibrary{arrows}\n\ 1150 \\begin{document}\n")); 1151 if (size > 1) { 1152 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1153 for (p = 0; p < size; ++p) { 1154 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1155 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1156 } 1157 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1158 } 1159 if (drawHasse) { 1160 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1161 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1169 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1171 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1172 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1173 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1174 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1175 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1176 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1177 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1178 } 1179 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1180 1181 /* Plot vertices */ 1182 PetscCall(VecGetArray(coordinates, &coords)); 1183 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1184 for (v = vStart; v < vEnd; ++v) { 1185 PetscInt off, dof, d; 1186 PetscBool isLabeled = PETSC_FALSE; 1187 1188 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1189 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1190 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1191 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1192 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1193 for (d = 0; d < dof; ++d) { 1194 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1195 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1196 } 1197 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1198 if (dim == 3) { 1199 PetscReal tmp = tcoords[1]; 1200 tcoords[1] = tcoords[2]; 1201 tcoords[2] = -tmp; 1202 } 1203 for (d = 0; d < dof; ++d) { 1204 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1205 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1206 } 1207 if (drawHasse) color = colors[0 % numColors]; 1208 else color = colors[rank % numColors]; 1209 for (l = 0; l < numLabels; ++l) { 1210 PetscInt val; 1211 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1212 if (val >= 0) { 1213 color = lcolors[l % numLColors]; 1214 isLabeled = PETSC_TRUE; 1215 break; 1216 } 1217 } 1218 if (drawNumbers[0]) { 1219 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1220 } else if (drawColors[0]) { 1221 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1222 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1223 } 1224 PetscCall(VecRestoreArray(coordinates, &coords)); 1225 PetscCall(PetscViewerFlush(viewer)); 1226 /* Plot edges */ 1227 if (plotEdges) { 1228 PetscCall(VecGetArray(coordinates, &coords)); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1230 for (e = eStart; e < eEnd; ++e) { 1231 const PetscInt *cone; 1232 PetscInt coneSize, offA, offB, dof, d; 1233 1234 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1235 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1236 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1237 PetscCall(DMPlexGetCone(dm, e, &cone)); 1238 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1239 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1240 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1241 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1242 for (d = 0; d < dof; ++d) { 1243 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1244 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1245 } 1246 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1247 if (dim == 3) { 1248 PetscReal tmp = tcoords[1]; 1249 tcoords[1] = tcoords[2]; 1250 tcoords[2] = -tmp; 1251 } 1252 for (d = 0; d < dof; ++d) { 1253 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1254 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1255 } 1256 if (drawHasse) color = colors[1 % numColors]; 1257 else color = colors[rank % numColors]; 1258 for (l = 0; l < numLabels; ++l) { 1259 PetscInt val; 1260 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1261 if (val >= 0) { 1262 color = lcolors[l % numLColors]; 1263 break; 1264 } 1265 } 1266 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1267 } 1268 PetscCall(VecRestoreArray(coordinates, &coords)); 1269 PetscCall(PetscViewerFlush(viewer)); 1270 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1271 } 1272 /* Plot cells */ 1273 if (dim == 3 || !drawNumbers[1]) { 1274 for (e = eStart; e < eEnd; ++e) { 1275 const PetscInt *cone; 1276 1277 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1278 color = colors[rank % numColors]; 1279 for (l = 0; l < numLabels; ++l) { 1280 PetscInt val; 1281 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1282 if (val >= 0) { 1283 color = lcolors[l % numLColors]; 1284 break; 1285 } 1286 } 1287 PetscCall(DMPlexGetCone(dm, e, &cone)); 1288 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1289 } 1290 } else { 1291 DMPolytopeType ct; 1292 1293 /* Drawing a 2D polygon */ 1294 for (c = cStart; c < cEnd; ++c) { 1295 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1296 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1297 if (DMPolytopeTypeIsHybrid(ct)) { 1298 const PetscInt *cone; 1299 PetscInt coneSize, e; 1300 1301 PetscCall(DMPlexGetCone(dm, c, &cone)); 1302 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1303 for (e = 0; e < coneSize; ++e) { 1304 const PetscInt *econe; 1305 1306 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1307 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)); 1308 } 1309 } else { 1310 PetscInt *closure = NULL; 1311 PetscInt closureSize, Nv = 0, v; 1312 1313 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1314 for (p = 0; p < closureSize * 2; p += 2) { 1315 const PetscInt point = closure[p]; 1316 1317 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1318 } 1319 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1320 for (v = 0; v <= Nv; ++v) { 1321 const PetscInt vertex = closure[v % Nv]; 1322 1323 if (v > 0) { 1324 if (plotEdges) { 1325 const PetscInt *edge; 1326 PetscInt endpoints[2], ne; 1327 1328 endpoints[0] = closure[v - 1]; 1329 endpoints[1] = vertex; 1330 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1331 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1332 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1333 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1334 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1335 } 1336 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1337 } 1338 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1339 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1340 } 1341 } 1342 } 1343 for (c = cStart; c < cEnd; ++c) { 1344 double ccoords[3] = {0.0, 0.0, 0.0}; 1345 PetscBool isLabeled = PETSC_FALSE; 1346 PetscScalar *cellCoords = NULL; 1347 const PetscScalar *array; 1348 PetscInt numCoords, cdim, d; 1349 PetscBool isDG; 1350 1351 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1352 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1353 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1354 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1355 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1356 for (p = 0; p < numCoords / cdim; ++p) { 1357 for (d = 0; d < cdim; ++d) { 1358 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1359 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1360 } 1361 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1362 if (cdim == 3) { 1363 PetscReal tmp = tcoords[1]; 1364 tcoords[1] = tcoords[2]; 1365 tcoords[2] = -tmp; 1366 } 1367 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1368 } 1369 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1370 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1371 for (d = 0; d < cdim; ++d) { 1372 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1373 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1374 } 1375 if (drawHasse) color = colors[depth % numColors]; 1376 else color = colors[rank % numColors]; 1377 for (l = 0; l < numLabels; ++l) { 1378 PetscInt val; 1379 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1380 if (val >= 0) { 1381 color = lcolors[l % numLColors]; 1382 isLabeled = PETSC_TRUE; 1383 break; 1384 } 1385 } 1386 if (drawNumbers[dim]) { 1387 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1388 } else if (drawColors[dim]) { 1389 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1390 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1391 } 1392 if (drawHasse) { 1393 int height = 0; 1394 1395 color = colors[depth % numColors]; 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1397 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1398 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1401 1402 if (depth > 2) { 1403 color = colors[1 % numColors]; 1404 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1406 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1407 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1408 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1409 } 1410 1411 color = colors[1 % numColors]; 1412 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1413 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1414 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1415 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1417 1418 color = colors[0 % numColors]; 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1420 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1422 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1424 1425 for (p = pStart; p < pEnd; ++p) { 1426 const PetscInt *cone; 1427 PetscInt coneSize, cp; 1428 1429 PetscCall(DMPlexGetCone(dm, p, &cone)); 1430 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1431 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1432 } 1433 } 1434 PetscCall(PetscViewerFlush(viewer)); 1435 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1436 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1437 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1438 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1439 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1440 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1441 PetscCall(PetscFree3(names, colors, lcolors)); 1442 PetscCall(PetscBTDestroy(&wp)); 1443 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1444 Vec cown, acown; 1445 VecScatter sct; 1446 ISLocalToGlobalMapping g2l; 1447 IS gid, acis; 1448 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1449 MPI_Group ggroup, ngroup; 1450 PetscScalar *array, nid; 1451 const PetscInt *idxs; 1452 PetscInt *idxs2, *start, *adjacency, *work; 1453 PetscInt64 lm[3], gm[3]; 1454 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1455 PetscMPIInt d1, d2, rank; 1456 1457 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1458 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1459 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1460 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1461 #endif 1462 if (ncomm != MPI_COMM_NULL) { 1463 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1464 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1465 d1 = 0; 1466 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1467 nid = d2; 1468 PetscCallMPI(MPI_Group_free(&ggroup)); 1469 PetscCallMPI(MPI_Group_free(&ngroup)); 1470 PetscCallMPI(MPI_Comm_free(&ncomm)); 1471 } else nid = 0.0; 1472 1473 /* Get connectivity */ 1474 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1475 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1476 1477 /* filter overlapped local cells */ 1478 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1479 PetscCall(ISGetIndices(gid, &idxs)); 1480 PetscCall(ISGetLocalSize(gid, &cum)); 1481 PetscCall(PetscMalloc1(cum, &idxs2)); 1482 for (c = cStart, cum = 0; c < cEnd; c++) { 1483 if (idxs[c - cStart] < 0) continue; 1484 idxs2[cum++] = idxs[c - cStart]; 1485 } 1486 PetscCall(ISRestoreIndices(gid, &idxs)); 1487 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1488 PetscCall(ISDestroy(&gid)); 1489 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1490 1491 /* support for node-aware cell locality */ 1492 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1493 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1494 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1495 PetscCall(VecGetArray(cown, &array)); 1496 for (c = 0; c < numVertices; c++) array[c] = nid; 1497 PetscCall(VecRestoreArray(cown, &array)); 1498 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1499 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1500 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1501 PetscCall(ISDestroy(&acis)); 1502 PetscCall(VecScatterDestroy(&sct)); 1503 PetscCall(VecDestroy(&cown)); 1504 1505 /* compute edgeCut */ 1506 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1507 PetscCall(PetscMalloc1(cum, &work)); 1508 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1509 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1510 PetscCall(ISDestroy(&gid)); 1511 PetscCall(VecGetArray(acown, &array)); 1512 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1513 PetscInt totl; 1514 1515 totl = start[c + 1] - start[c]; 1516 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1517 for (i = 0; i < totl; i++) { 1518 if (work[i] < 0) { 1519 ect += 1; 1520 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1521 } 1522 } 1523 } 1524 PetscCall(PetscFree(work)); 1525 PetscCall(VecRestoreArray(acown, &array)); 1526 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1527 lm[1] = -numVertices; 1528 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1529 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1530 lm[0] = ect; /* edgeCut */ 1531 lm[1] = ectn; /* node-aware edgeCut */ 1532 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1533 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1534 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1535 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1536 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1537 #else 1538 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1539 #endif 1540 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1541 PetscCall(PetscFree(start)); 1542 PetscCall(PetscFree(adjacency)); 1543 PetscCall(VecDestroy(&acown)); 1544 } else { 1545 const char *name; 1546 PetscInt *sizes, *hybsizes, *ghostsizes; 1547 PetscInt locDepth, depth, cellHeight, dim, d; 1548 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1549 PetscInt numLabels, l, maxSize = 17; 1550 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1551 MPI_Comm comm; 1552 PetscMPIInt size, rank; 1553 1554 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1555 PetscCallMPI(MPI_Comm_size(comm, &size)); 1556 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1557 PetscCall(DMGetDimension(dm, &dim)); 1558 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1559 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1560 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1561 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1562 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1563 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1564 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1565 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1566 gcNum = gcEnd - gcStart; 1567 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1568 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1569 for (d = 0; d <= depth; d++) { 1570 PetscInt Nc[2] = {0, 0}, ict; 1571 1572 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1573 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1574 ict = ct0; 1575 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1576 ct0 = (DMPolytopeType)ict; 1577 for (p = pStart; p < pEnd; ++p) { 1578 DMPolytopeType ct; 1579 1580 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1581 if (ct == ct0) ++Nc[0]; 1582 else ++Nc[1]; 1583 } 1584 if (size < maxSize) { 1585 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1586 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1587 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1588 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1589 for (p = 0; p < size; ++p) { 1590 if (rank == 0) { 1591 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1592 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1593 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1594 } 1595 } 1596 } else { 1597 PetscInt locMinMax[2]; 1598 1599 locMinMax[0] = Nc[0] + Nc[1]; 1600 locMinMax[1] = Nc[0] + Nc[1]; 1601 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1602 locMinMax[0] = Nc[1]; 1603 locMinMax[1] = Nc[1]; 1604 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1605 if (d == depth) { 1606 locMinMax[0] = gcNum; 1607 locMinMax[1] = gcNum; 1608 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1609 } 1610 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1611 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1612 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1613 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1614 } 1615 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1616 } 1617 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1618 { 1619 const PetscReal *maxCell; 1620 const PetscReal *L; 1621 PetscBool localized; 1622 1623 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1624 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1625 if (L || localized) { 1626 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1627 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1628 if (L) { 1629 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1630 for (d = 0; d < dim; ++d) { 1631 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1632 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1633 } 1634 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1635 } 1636 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1637 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1638 } 1639 } 1640 PetscCall(DMGetNumLabels(dm, &numLabels)); 1641 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1642 for (l = 0; l < numLabels; ++l) { 1643 DMLabel label; 1644 const char *name; 1645 PetscInt *values; 1646 PetscInt numValues, v; 1647 1648 PetscCall(DMGetLabelName(dm, l, &name)); 1649 PetscCall(DMGetLabel(dm, name, &label)); 1650 PetscCall(DMLabelGetNumValues(label, &numValues)); 1651 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1652 1653 { // Extract array of DMLabel values so it can be sorted 1654 IS is_values; 1655 const PetscInt *is_values_local = NULL; 1656 1657 PetscCall(DMLabelGetValueIS(label, &is_values)); 1658 PetscCall(ISGetIndices(is_values, &is_values_local)); 1659 PetscCall(PetscMalloc1(numValues, &values)); 1660 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1661 PetscCall(PetscSortInt(numValues, values)); 1662 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1663 PetscCall(ISDestroy(&is_values)); 1664 } 1665 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1666 for (v = 0; v < numValues; ++v) { 1667 PetscInt size; 1668 1669 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1670 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1671 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1672 } 1673 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1674 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1675 PetscCall(PetscFree(values)); 1676 } 1677 { 1678 char **labelNames; 1679 PetscInt Nl = numLabels; 1680 PetscBool flg; 1681 1682 PetscCall(PetscMalloc1(Nl, &labelNames)); 1683 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1684 for (l = 0; l < Nl; ++l) { 1685 DMLabel label; 1686 1687 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1688 if (flg) { 1689 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1690 PetscCall(DMLabelView(label, viewer)); 1691 } 1692 PetscCall(PetscFree(labelNames[l])); 1693 } 1694 PetscCall(PetscFree(labelNames)); 1695 } 1696 /* If no fields are specified, people do not want to see adjacency */ 1697 if (dm->Nf) { 1698 PetscInt f; 1699 1700 for (f = 0; f < dm->Nf; ++f) { 1701 const char *name; 1702 1703 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1704 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1705 PetscCall(PetscViewerASCIIPushTab(viewer)); 1706 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1707 if (dm->fields[f].adjacency[0]) { 1708 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1709 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1710 } else { 1711 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1712 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1713 } 1714 PetscCall(PetscViewerASCIIPopTab(viewer)); 1715 } 1716 } 1717 PetscCall(DMGetCoarseDM(dm, &cdm)); 1718 if (cdm) { 1719 PetscCall(PetscViewerASCIIPushTab(viewer)); 1720 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1721 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1722 PetscCall(PetscViewerASCIIPopTab(viewer)); 1723 } 1724 } 1725 PetscFunctionReturn(PETSC_SUCCESS); 1726 } 1727 1728 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1729 { 1730 DMPolytopeType ct; 1731 PetscMPIInt rank; 1732 PetscInt cdim; 1733 1734 PetscFunctionBegin; 1735 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1736 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1737 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1738 switch (ct) { 1739 case DM_POLYTOPE_SEGMENT: 1740 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1741 switch (cdim) { 1742 case 1: { 1743 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1744 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1745 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1747 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1748 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1749 } break; 1750 case 2: { 1751 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1752 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1753 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1754 1755 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1756 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)); 1757 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)); 1758 } break; 1759 default: 1760 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1761 } 1762 break; 1763 case DM_POLYTOPE_TRIANGLE: 1764 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)); 1765 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1766 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1767 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1768 break; 1769 case DM_POLYTOPE_QUADRILATERAL: 1770 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)); 1771 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)); 1772 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1773 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1774 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1775 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1776 break; 1777 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1778 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)); 1779 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)); 1780 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1781 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1782 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1783 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1784 break; 1785 case DM_POLYTOPE_FV_GHOST: 1786 break; 1787 default: 1788 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1789 } 1790 PetscFunctionReturn(PETSC_SUCCESS); 1791 } 1792 1793 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1794 { 1795 PetscReal centroid[2] = {0., 0.}; 1796 PetscMPIInt rank; 1797 PetscInt fillColor; 1798 1799 PetscFunctionBegin; 1800 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1801 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1802 for (PetscInt v = 0; v < Nv; ++v) { 1803 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1804 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1805 } 1806 for (PetscInt e = 0; e < Nv; ++e) { 1807 refCoords[0] = refVertices[e * 2 + 0]; 1808 refCoords[1] = refVertices[e * 2 + 1]; 1809 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1810 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1811 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1812 } 1813 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1814 for (PetscInt d = 0; d < edgeDiv; ++d) { 1815 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)); 1816 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1817 } 1818 } 1819 PetscFunctionReturn(PETSC_SUCCESS); 1820 } 1821 1822 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1823 { 1824 DMPolytopeType ct; 1825 1826 PetscFunctionBegin; 1827 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1828 switch (ct) { 1829 case DM_POLYTOPE_TRIANGLE: { 1830 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1831 1832 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1833 } break; 1834 case DM_POLYTOPE_QUADRILATERAL: { 1835 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1836 1837 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1838 } break; 1839 default: 1840 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1841 } 1842 PetscFunctionReturn(PETSC_SUCCESS); 1843 } 1844 1845 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1846 { 1847 PetscDraw draw; 1848 DM cdm; 1849 PetscSection coordSection; 1850 Vec coordinates; 1851 PetscReal xyl[3], xyr[3]; 1852 PetscReal *refCoords, *edgeCoords; 1853 PetscBool isnull, drawAffine; 1854 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1855 1856 PetscFunctionBegin; 1857 PetscCall(DMGetCoordinateDim(dm, &dim)); 1858 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1859 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1860 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1861 edgeDiv = cDegree + 1; 1862 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1863 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1864 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1865 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1866 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1867 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1868 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1869 1870 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1871 PetscCall(PetscDrawIsNull(draw, &isnull)); 1872 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1873 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1874 1875 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1876 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1877 PetscCall(PetscDrawClear(draw)); 1878 1879 for (c = cStart; c < cEnd; ++c) { 1880 PetscScalar *coords = NULL; 1881 const PetscScalar *coords_arr; 1882 PetscInt numCoords; 1883 PetscBool isDG; 1884 1885 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1886 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1887 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1888 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1889 } 1890 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1891 PetscCall(PetscDrawFlush(draw)); 1892 PetscCall(PetscDrawPause(draw)); 1893 PetscCall(PetscDrawSave(draw)); 1894 PetscFunctionReturn(PETSC_SUCCESS); 1895 } 1896 1897 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1898 { 1899 DM odm = dm, rdm = dm, cdm; 1900 PetscFE fe; 1901 PetscSpace sp; 1902 PetscClassId id; 1903 PetscInt degree; 1904 PetscBool hoView = PETSC_TRUE; 1905 1906 PetscFunctionBegin; 1907 PetscObjectOptionsBegin((PetscObject)dm); 1908 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1909 PetscOptionsEnd(); 1910 PetscCall(PetscObjectReference((PetscObject)dm)); 1911 *hdm = dm; 1912 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1913 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1914 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1915 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1916 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1917 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1918 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1919 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1920 DM cdm, rcdm; 1921 Mat In; 1922 Vec cl, rcl; 1923 1924 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1925 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1926 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1927 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1928 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1929 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1930 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1931 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1932 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1933 PetscCall(MatMult(In, cl, rcl)); 1934 PetscCall(MatDestroy(&In)); 1935 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1936 PetscCall(DMDestroy(&odm)); 1937 odm = rdm; 1938 } 1939 *hdm = rdm; 1940 PetscFunctionReturn(PETSC_SUCCESS); 1941 } 1942 1943 #if defined(PETSC_HAVE_EXODUSII) 1944 #include <exodusII.h> 1945 #include <petscviewerexodusii.h> 1946 #endif 1947 1948 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1949 { 1950 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1951 char name[PETSC_MAX_PATH_LEN]; 1952 1953 PetscFunctionBegin; 1954 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1955 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1956 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1957 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1958 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1959 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1960 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1961 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1962 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1963 if (iascii) { 1964 PetscViewerFormat format; 1965 PetscCall(PetscViewerGetFormat(viewer, &format)); 1966 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1967 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1968 } else if (ishdf5) { 1969 #if defined(PETSC_HAVE_HDF5) 1970 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1971 #else 1972 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1973 #endif 1974 } else if (isvtk) { 1975 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1976 } else if (isdraw) { 1977 DM hdm; 1978 1979 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1980 PetscCall(DMPlexView_Draw(hdm, viewer)); 1981 PetscCall(DMDestroy(&hdm)); 1982 } else if (isglvis) { 1983 PetscCall(DMPlexView_GLVis(dm, viewer)); 1984 #if defined(PETSC_HAVE_EXODUSII) 1985 } else if (isexodus) { 1986 /* 1987 exodusII requires that all sets be part of exactly one cell set. 1988 If the dm does not have a "Cell Sets" label defined, we create one 1989 with ID 1, containing all cells. 1990 Note that if the Cell Sets label is defined but does not cover all cells, 1991 we may still have a problem. This should probably be checked here or in the viewer; 1992 */ 1993 PetscInt numCS; 1994 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1995 if (!numCS) { 1996 PetscInt cStart, cEnd, c; 1997 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1998 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1999 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2000 } 2001 PetscCall(DMView_PlexExodusII(dm, viewer)); 2002 #endif 2003 #if defined(PETSC_HAVE_CGNS) 2004 } else if (iscgns) { 2005 PetscCall(DMView_PlexCGNS(dm, viewer)); 2006 #endif 2007 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2008 /* Optionally view the partition */ 2009 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2010 if (flg) { 2011 Vec ranks; 2012 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2013 PetscCall(VecView(ranks, viewer)); 2014 PetscCall(VecDestroy(&ranks)); 2015 } 2016 /* Optionally view a label */ 2017 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2018 if (flg) { 2019 DMLabel label; 2020 Vec val; 2021 2022 PetscCall(DMGetLabel(dm, name, &label)); 2023 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2024 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2025 PetscCall(VecView(val, viewer)); 2026 PetscCall(VecDestroy(&val)); 2027 } 2028 PetscFunctionReturn(PETSC_SUCCESS); 2029 } 2030 2031 /*@ 2032 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2033 2034 Collective 2035 2036 Input Parameters: 2037 + dm - The `DM` whose topology is to be saved 2038 - viewer - The `PetscViewer` to save it in 2039 2040 Level: advanced 2041 2042 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2043 @*/ 2044 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2045 { 2046 PetscBool ishdf5; 2047 2048 PetscFunctionBegin; 2049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2050 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2051 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2052 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2053 if (ishdf5) { 2054 #if defined(PETSC_HAVE_HDF5) 2055 PetscViewerFormat format; 2056 PetscCall(PetscViewerGetFormat(viewer, &format)); 2057 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2058 IS globalPointNumbering; 2059 2060 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2061 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2062 PetscCall(ISDestroy(&globalPointNumbering)); 2063 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2064 #else 2065 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2066 #endif 2067 } 2068 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2069 PetscFunctionReturn(PETSC_SUCCESS); 2070 } 2071 2072 /*@ 2073 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2074 2075 Collective 2076 2077 Input Parameters: 2078 + dm - The `DM` whose coordinates are to be saved 2079 - viewer - The `PetscViewer` for saving 2080 2081 Level: advanced 2082 2083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2084 @*/ 2085 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2086 { 2087 PetscBool ishdf5; 2088 2089 PetscFunctionBegin; 2090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2091 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2092 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2093 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2094 if (ishdf5) { 2095 #if defined(PETSC_HAVE_HDF5) 2096 PetscViewerFormat format; 2097 PetscCall(PetscViewerGetFormat(viewer, &format)); 2098 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2099 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2100 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2101 #else 2102 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2103 #endif 2104 } 2105 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2106 PetscFunctionReturn(PETSC_SUCCESS); 2107 } 2108 2109 /*@ 2110 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2111 2112 Collective 2113 2114 Input Parameters: 2115 + dm - The `DM` whose labels are to be saved 2116 - viewer - The `PetscViewer` for saving 2117 2118 Level: advanced 2119 2120 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2121 @*/ 2122 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2123 { 2124 PetscBool ishdf5; 2125 2126 PetscFunctionBegin; 2127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2128 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2129 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2130 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2131 if (ishdf5) { 2132 #if defined(PETSC_HAVE_HDF5) 2133 IS globalPointNumbering; 2134 PetscViewerFormat format; 2135 2136 PetscCall(PetscViewerGetFormat(viewer, &format)); 2137 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2138 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2139 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2140 PetscCall(ISDestroy(&globalPointNumbering)); 2141 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2142 #else 2143 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2144 #endif 2145 } 2146 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2147 PetscFunctionReturn(PETSC_SUCCESS); 2148 } 2149 2150 /*@ 2151 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2152 2153 Collective 2154 2155 Input Parameters: 2156 + dm - The `DM` that contains the topology on which the section to be saved is defined 2157 . viewer - The `PetscViewer` for saving 2158 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2159 2160 Level: advanced 2161 2162 Notes: 2163 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. 2164 2165 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. 2166 2167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2168 @*/ 2169 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2170 { 2171 PetscBool ishdf5; 2172 2173 PetscFunctionBegin; 2174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2175 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2176 if (!sectiondm) sectiondm = dm; 2177 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2178 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2179 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2180 if (ishdf5) { 2181 #if defined(PETSC_HAVE_HDF5) 2182 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2183 #else 2184 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2185 #endif 2186 } 2187 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2188 PetscFunctionReturn(PETSC_SUCCESS); 2189 } 2190 2191 /*@ 2192 DMPlexGlobalVectorView - Saves a global vector 2193 2194 Collective 2195 2196 Input Parameters: 2197 + dm - The `DM` that represents the topology 2198 . viewer - The `PetscViewer` to save data with 2199 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2200 - vec - The global vector to be saved 2201 2202 Level: advanced 2203 2204 Notes: 2205 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. 2206 2207 Calling sequence: 2208 .vb 2209 DMCreate(PETSC_COMM_WORLD, &dm); 2210 DMSetType(dm, DMPLEX); 2211 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2212 DMClone(dm, §iondm); 2213 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2214 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2215 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2216 PetscSectionSetChart(section, pStart, pEnd); 2217 PetscSectionSetUp(section); 2218 DMSetLocalSection(sectiondm, section); 2219 PetscSectionDestroy(§ion); 2220 DMGetGlobalVector(sectiondm, &vec); 2221 PetscObjectSetName((PetscObject)vec, "vec_name"); 2222 DMPlexTopologyView(dm, viewer); 2223 DMPlexSectionView(dm, viewer, sectiondm); 2224 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2225 DMRestoreGlobalVector(sectiondm, &vec); 2226 DMDestroy(§iondm); 2227 DMDestroy(&dm); 2228 .ve 2229 2230 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2231 @*/ 2232 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2233 { 2234 PetscBool ishdf5; 2235 2236 PetscFunctionBegin; 2237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2238 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2239 if (!sectiondm) sectiondm = dm; 2240 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2241 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2242 /* Check consistency */ 2243 { 2244 PetscSection section; 2245 PetscBool includesConstraints; 2246 PetscInt m, m1; 2247 2248 PetscCall(VecGetLocalSize(vec, &m1)); 2249 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2250 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2251 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2252 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2253 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2254 } 2255 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2256 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2257 if (ishdf5) { 2258 #if defined(PETSC_HAVE_HDF5) 2259 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2260 #else 2261 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2262 #endif 2263 } 2264 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2265 PetscFunctionReturn(PETSC_SUCCESS); 2266 } 2267 2268 /*@ 2269 DMPlexLocalVectorView - Saves a local vector 2270 2271 Collective 2272 2273 Input Parameters: 2274 + dm - The `DM` that represents the topology 2275 . viewer - The `PetscViewer` to save data with 2276 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2277 - vec - The local vector to be saved 2278 2279 Level: advanced 2280 2281 Note: 2282 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. 2283 2284 Calling sequence: 2285 .vb 2286 DMCreate(PETSC_COMM_WORLD, &dm); 2287 DMSetType(dm, DMPLEX); 2288 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2289 DMClone(dm, §iondm); 2290 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2291 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2292 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2293 PetscSectionSetChart(section, pStart, pEnd); 2294 PetscSectionSetUp(section); 2295 DMSetLocalSection(sectiondm, section); 2296 DMGetLocalVector(sectiondm, &vec); 2297 PetscObjectSetName((PetscObject)vec, "vec_name"); 2298 DMPlexTopologyView(dm, viewer); 2299 DMPlexSectionView(dm, viewer, sectiondm); 2300 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2301 DMRestoreLocalVector(sectiondm, &vec); 2302 DMDestroy(§iondm); 2303 DMDestroy(&dm); 2304 .ve 2305 2306 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2307 @*/ 2308 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2309 { 2310 PetscBool ishdf5; 2311 2312 PetscFunctionBegin; 2313 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2314 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2315 if (!sectiondm) sectiondm = dm; 2316 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2317 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2318 /* Check consistency */ 2319 { 2320 PetscSection section; 2321 PetscBool includesConstraints; 2322 PetscInt m, m1; 2323 2324 PetscCall(VecGetLocalSize(vec, &m1)); 2325 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2326 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2327 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2328 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2329 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2330 } 2331 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2332 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2333 if (ishdf5) { 2334 #if defined(PETSC_HAVE_HDF5) 2335 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2336 #else 2337 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2338 #endif 2339 } 2340 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2341 PetscFunctionReturn(PETSC_SUCCESS); 2342 } 2343 2344 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2345 { 2346 PetscBool ishdf5; 2347 2348 PetscFunctionBegin; 2349 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2350 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2351 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2352 if (ishdf5) { 2353 #if defined(PETSC_HAVE_HDF5) 2354 PetscViewerFormat format; 2355 PetscCall(PetscViewerGetFormat(viewer, &format)); 2356 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2357 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2358 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2359 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2360 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2361 PetscFunctionReturn(PETSC_SUCCESS); 2362 #else 2363 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2364 #endif 2365 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2366 } 2367 2368 /*@ 2369 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2370 2371 Collective 2372 2373 Input Parameters: 2374 + dm - The `DM` into which the topology is loaded 2375 - viewer - The `PetscViewer` for the saved topology 2376 2377 Output Parameter: 2378 . 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; 2379 `NULL` if unneeded 2380 2381 Level: advanced 2382 2383 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2384 `PetscViewer`, `PetscSF` 2385 @*/ 2386 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2387 { 2388 PetscBool ishdf5; 2389 2390 PetscFunctionBegin; 2391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2392 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2393 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2394 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2395 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2396 if (ishdf5) { 2397 #if defined(PETSC_HAVE_HDF5) 2398 PetscViewerFormat format; 2399 PetscCall(PetscViewerGetFormat(viewer, &format)); 2400 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2401 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2402 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2403 #else 2404 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2405 #endif 2406 } 2407 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2408 PetscFunctionReturn(PETSC_SUCCESS); 2409 } 2410 2411 /*@ 2412 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2413 2414 Collective 2415 2416 Input Parameters: 2417 + dm - The `DM` into which the coordinates are loaded 2418 . viewer - The `PetscViewer` for the saved coordinates 2419 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2420 2421 Level: advanced 2422 2423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2424 `PetscSF`, `PetscViewer` 2425 @*/ 2426 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2427 { 2428 PetscBool ishdf5; 2429 2430 PetscFunctionBegin; 2431 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2432 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2433 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2434 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2435 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2436 if (ishdf5) { 2437 #if defined(PETSC_HAVE_HDF5) 2438 PetscViewerFormat format; 2439 PetscCall(PetscViewerGetFormat(viewer, &format)); 2440 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2441 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2442 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2443 #else 2444 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2445 #endif 2446 } 2447 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2448 PetscFunctionReturn(PETSC_SUCCESS); 2449 } 2450 2451 /*@ 2452 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2453 2454 Collective 2455 2456 Input Parameters: 2457 + dm - The `DM` into which the labels are loaded 2458 . viewer - The `PetscViewer` for the saved labels 2459 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2460 2461 Level: advanced 2462 2463 Note: 2464 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2465 2466 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2467 `PetscSF`, `PetscViewer` 2468 @*/ 2469 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2470 { 2471 PetscBool ishdf5; 2472 2473 PetscFunctionBegin; 2474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2475 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2476 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2477 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2478 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2479 if (ishdf5) { 2480 #if defined(PETSC_HAVE_HDF5) 2481 PetscViewerFormat format; 2482 2483 PetscCall(PetscViewerGetFormat(viewer, &format)); 2484 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2485 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2486 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2487 #else 2488 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2489 #endif 2490 } 2491 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2492 PetscFunctionReturn(PETSC_SUCCESS); 2493 } 2494 2495 /*@ 2496 DMPlexSectionLoad - Loads section into a `DMPLEX` 2497 2498 Collective 2499 2500 Input Parameters: 2501 + dm - The `DM` that represents the topology 2502 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2503 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2504 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2505 2506 Output Parameters: 2507 + 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) 2508 - 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) 2509 2510 Level: advanced 2511 2512 Notes: 2513 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. 2514 2515 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. 2516 2517 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. 2518 2519 Example using 2 processes: 2520 .vb 2521 NX (number of points on dm): 4 2522 sectionA : the on-disk section 2523 vecA : a vector associated with sectionA 2524 sectionB : sectiondm's local section constructed in this function 2525 vecB (local) : a vector associated with sectiondm's local section 2526 vecB (global) : a vector associated with sectiondm's global section 2527 2528 rank 0 rank 1 2529 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2530 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2531 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2532 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2533 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2534 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2535 sectionB->atlasDof : 1 0 1 | 1 3 2536 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2537 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2538 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2539 .ve 2540 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2541 2542 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2543 @*/ 2544 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2545 { 2546 PetscBool ishdf5; 2547 2548 PetscFunctionBegin; 2549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2550 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2551 if (!sectiondm) sectiondm = dm; 2552 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2553 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2554 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2555 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2556 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2557 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2558 if (ishdf5) { 2559 #if defined(PETSC_HAVE_HDF5) 2560 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2561 #else 2562 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2563 #endif 2564 } 2565 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2566 PetscFunctionReturn(PETSC_SUCCESS); 2567 } 2568 2569 /*@ 2570 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2571 2572 Collective 2573 2574 Input Parameters: 2575 + dm - The `DM` that represents the topology 2576 . viewer - The `PetscViewer` that represents the on-disk vector data 2577 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2578 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2579 - vec - The global vector to set values of 2580 2581 Level: advanced 2582 2583 Notes: 2584 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. 2585 2586 Calling sequence: 2587 .vb 2588 DMCreate(PETSC_COMM_WORLD, &dm); 2589 DMSetType(dm, DMPLEX); 2590 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2591 DMPlexTopologyLoad(dm, viewer, &sfX); 2592 DMClone(dm, §iondm); 2593 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2594 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2595 DMGetGlobalVector(sectiondm, &vec); 2596 PetscObjectSetName((PetscObject)vec, "vec_name"); 2597 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2598 DMRestoreGlobalVector(sectiondm, &vec); 2599 PetscSFDestroy(&gsf); 2600 PetscSFDestroy(&sfX); 2601 DMDestroy(§iondm); 2602 DMDestroy(&dm); 2603 .ve 2604 2605 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2606 `PetscSF`, `PetscViewer` 2607 @*/ 2608 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2609 { 2610 PetscBool ishdf5; 2611 2612 PetscFunctionBegin; 2613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2614 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2615 if (!sectiondm) sectiondm = dm; 2616 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2617 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2618 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2619 /* Check consistency */ 2620 { 2621 PetscSection section; 2622 PetscBool includesConstraints; 2623 PetscInt m, m1; 2624 2625 PetscCall(VecGetLocalSize(vec, &m1)); 2626 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2627 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2628 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2629 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2630 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2631 } 2632 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2633 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2634 if (ishdf5) { 2635 #if defined(PETSC_HAVE_HDF5) 2636 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2637 #else 2638 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2639 #endif 2640 } 2641 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2642 PetscFunctionReturn(PETSC_SUCCESS); 2643 } 2644 2645 /*@ 2646 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2647 2648 Collective 2649 2650 Input Parameters: 2651 + dm - The `DM` that represents the topology 2652 . viewer - The `PetscViewer` that represents the on-disk vector data 2653 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2654 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2655 - vec - The local vector to set values of 2656 2657 Level: advanced 2658 2659 Notes: 2660 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. 2661 2662 Calling sequence: 2663 .vb 2664 DMCreate(PETSC_COMM_WORLD, &dm); 2665 DMSetType(dm, DMPLEX); 2666 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2667 DMPlexTopologyLoad(dm, viewer, &sfX); 2668 DMClone(dm, §iondm); 2669 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2670 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2671 DMGetLocalVector(sectiondm, &vec); 2672 PetscObjectSetName((PetscObject)vec, "vec_name"); 2673 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2674 DMRestoreLocalVector(sectiondm, &vec); 2675 PetscSFDestroy(&lsf); 2676 PetscSFDestroy(&sfX); 2677 DMDestroy(§iondm); 2678 DMDestroy(&dm); 2679 .ve 2680 2681 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2682 `PetscSF`, `PetscViewer` 2683 @*/ 2684 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2685 { 2686 PetscBool ishdf5; 2687 2688 PetscFunctionBegin; 2689 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2690 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2691 if (!sectiondm) sectiondm = dm; 2692 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2693 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2694 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2695 /* Check consistency */ 2696 { 2697 PetscSection section; 2698 PetscBool includesConstraints; 2699 PetscInt m, m1; 2700 2701 PetscCall(VecGetLocalSize(vec, &m1)); 2702 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2703 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2704 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2705 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2706 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2707 } 2708 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2709 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2710 if (ishdf5) { 2711 #if defined(PETSC_HAVE_HDF5) 2712 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2713 #else 2714 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2715 #endif 2716 } 2717 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2718 PetscFunctionReturn(PETSC_SUCCESS); 2719 } 2720 2721 PetscErrorCode DMDestroy_Plex(DM dm) 2722 { 2723 DM_Plex *mesh = (DM_Plex *)dm->data; 2724 2725 PetscFunctionBegin; 2726 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2727 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2728 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2729 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2730 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2731 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2732 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2733 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2734 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2735 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2736 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2737 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2738 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2739 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2740 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2741 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2742 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2743 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2744 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2745 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2746 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2747 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2748 PetscCall(PetscFree(mesh->cones)); 2749 PetscCall(PetscFree(mesh->coneOrientations)); 2750 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2751 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2752 PetscCall(PetscFree(mesh->supports)); 2753 PetscCall(PetscFree(mesh->cellTypes)); 2754 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2755 PetscCall(PetscFree(mesh->tetgenOpts)); 2756 PetscCall(PetscFree(mesh->triangleOpts)); 2757 PetscCall(PetscFree(mesh->transformType)); 2758 PetscCall(PetscFree(mesh->distributionName)); 2759 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2760 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2761 PetscCall(ISDestroy(&mesh->subpointIS)); 2762 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2763 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2764 if (mesh->periodic.face_sfs) { 2765 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2766 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2767 } 2768 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2769 if (mesh->periodic.periodic_points) { 2770 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2771 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2772 } 2773 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2774 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2775 PetscCall(ISDestroy(&mesh->anchorIS)); 2776 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2777 PetscCall(PetscFree(mesh->parents)); 2778 PetscCall(PetscFree(mesh->childIDs)); 2779 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2780 PetscCall(PetscFree(mesh->children)); 2781 PetscCall(DMDestroy(&mesh->referenceTree)); 2782 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2783 PetscCall(PetscFree(mesh->neighbors)); 2784 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2785 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2786 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2787 PetscCall(PetscFree(mesh)); 2788 PetscFunctionReturn(PETSC_SUCCESS); 2789 } 2790 2791 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2792 { 2793 PetscSection sectionGlobal, sectionLocal; 2794 PetscInt bs = -1, mbs; 2795 PetscInt localSize, localStart = 0; 2796 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2797 MatType mtype; 2798 ISLocalToGlobalMapping ltog; 2799 2800 PetscFunctionBegin; 2801 PetscCall(MatInitializePackage()); 2802 mtype = dm->mattype; 2803 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2804 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2805 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2806 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2807 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2808 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2809 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2810 PetscCall(MatSetType(*J, mtype)); 2811 PetscCall(MatSetFromOptions(*J)); 2812 PetscCall(MatGetBlockSize(*J, &mbs)); 2813 if (mbs > 1) bs = mbs; 2814 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2815 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2816 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2817 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2818 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2819 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2820 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2821 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2822 if (!isShell) { 2823 // There are three states with pblocks, since block starts can have no dofs: 2824 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2825 // TRUE) Block Start: The first entry in a block has been added 2826 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2827 PetscBT blst; 2828 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2829 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2830 const PetscInt *perm = NULL; 2831 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2832 PetscInt pStart, pEnd, dof, cdof, num_fields; 2833 2834 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2835 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2836 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2837 2838 PetscCall(PetscCalloc1(localSize, &pblocks)); 2839 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2840 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2841 // We need to process in the permuted order to get block sizes right 2842 for (PetscInt point = pStart; point < pEnd; ++point) { 2843 const PetscInt p = perm ? perm[point] : point; 2844 2845 switch (dm->blocking_type) { 2846 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2847 PetscInt bdof, offset; 2848 2849 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2850 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2851 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2852 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2853 if (dof > 0) { 2854 // State change 2855 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2856 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2857 2858 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2859 // Signal block concatenation 2860 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2861 } 2862 dof = dof < 0 ? -(dof + 1) : dof; 2863 bdof = cdof && (dof - cdof) ? 1 : dof; 2864 if (dof) { 2865 if (bs < 0) { 2866 bs = bdof; 2867 } else if (bs != bdof) { 2868 bs = 1; 2869 } 2870 } 2871 } break; 2872 case DM_BLOCKING_FIELD_NODE: { 2873 for (PetscInt field = 0; field < num_fields; field++) { 2874 PetscInt num_comp, bdof, offset; 2875 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2876 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2877 if (dof < 0) continue; 2878 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2879 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2880 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); 2881 PetscInt num_nodes = dof / num_comp; 2882 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2883 // Handle possibly constant block size (unlikely) 2884 bdof = cdof && (dof - cdof) ? 1 : dof; 2885 if (dof) { 2886 if (bs < 0) { 2887 bs = bdof; 2888 } else if (bs != bdof) { 2889 bs = 1; 2890 } 2891 } 2892 } 2893 } break; 2894 } 2895 } 2896 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2897 /* Must have same blocksize on all procs (some might have no points) */ 2898 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2899 bsLocal[1] = bs; 2900 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2901 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2902 else bs = bsMinMax[0]; 2903 bs = PetscMax(1, bs); 2904 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2905 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2906 PetscCall(MatSetBlockSize(*J, bs)); 2907 PetscCall(MatSetUp(*J)); 2908 } else { 2909 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2910 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2911 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2912 } 2913 if (pblocks) { // Consolidate blocks 2914 PetscInt nblocks = 0; 2915 pblocks[0] = PetscAbs(pblocks[0]); 2916 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2917 if (pblocks[i] == 0) continue; 2918 // Negative block size indicates the blocks should be concatenated 2919 if (pblocks[i] < 0) { 2920 pblocks[i] = -pblocks[i]; 2921 pblocks[nblocks - 1] += pblocks[i]; 2922 } else { 2923 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2924 } 2925 for (PetscInt j = 1; j < pblocks[i]; j++) 2926 PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " at %" PetscInt_FMT " mismatches entry %" PetscInt_FMT " at %" PetscInt_FMT, pblocks[i], i, pblocks[i + j], i + j); 2927 } 2928 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2929 } 2930 PetscCall(PetscFree(pblocks)); 2931 } 2932 PetscCall(MatSetDM(*J, dm)); 2933 PetscFunctionReturn(PETSC_SUCCESS); 2934 } 2935 2936 /*@ 2937 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2938 2939 Not Collective 2940 2941 Input Parameter: 2942 . dm - The `DMPLEX` 2943 2944 Output Parameter: 2945 . subsection - The subdomain section 2946 2947 Level: developer 2948 2949 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2950 @*/ 2951 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2952 { 2953 DM_Plex *mesh = (DM_Plex *)dm->data; 2954 2955 PetscFunctionBegin; 2956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2957 if (!mesh->subdomainSection) { 2958 PetscSection section; 2959 PetscSF sf; 2960 2961 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2962 PetscCall(DMGetLocalSection(dm, §ion)); 2963 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2964 PetscCall(PetscSFDestroy(&sf)); 2965 } 2966 *subsection = mesh->subdomainSection; 2967 PetscFunctionReturn(PETSC_SUCCESS); 2968 } 2969 2970 /*@ 2971 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2972 2973 Not Collective 2974 2975 Input Parameter: 2976 . dm - The `DMPLEX` 2977 2978 Output Parameters: 2979 + pStart - The first mesh point 2980 - pEnd - The upper bound for mesh points 2981 2982 Level: beginner 2983 2984 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2985 @*/ 2986 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2987 { 2988 DM_Plex *mesh = (DM_Plex *)dm->data; 2989 2990 PetscFunctionBegin; 2991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2992 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2993 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2994 PetscFunctionReturn(PETSC_SUCCESS); 2995 } 2996 2997 /*@ 2998 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2999 3000 Not Collective 3001 3002 Input Parameters: 3003 + dm - The `DMPLEX` 3004 . pStart - The first mesh point 3005 - pEnd - The upper bound for mesh points 3006 3007 Level: beginner 3008 3009 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3010 @*/ 3011 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3012 { 3013 DM_Plex *mesh = (DM_Plex *)dm->data; 3014 3015 PetscFunctionBegin; 3016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3017 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3018 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3019 PetscCall(PetscFree(mesh->cellTypes)); 3020 PetscFunctionReturn(PETSC_SUCCESS); 3021 } 3022 3023 /*@ 3024 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3025 3026 Not Collective 3027 3028 Input Parameters: 3029 + dm - The `DMPLEX` 3030 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3031 3032 Output Parameter: 3033 . size - The cone size for point `p` 3034 3035 Level: beginner 3036 3037 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3038 @*/ 3039 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3040 { 3041 DM_Plex *mesh = (DM_Plex *)dm->data; 3042 3043 PetscFunctionBegin; 3044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3045 PetscAssertPointer(size, 3); 3046 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3047 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3048 PetscFunctionReturn(PETSC_SUCCESS); 3049 } 3050 3051 /*@ 3052 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3053 3054 Not Collective 3055 3056 Input Parameters: 3057 + dm - The `DMPLEX` 3058 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3059 - size - The cone size for point `p` 3060 3061 Level: beginner 3062 3063 Note: 3064 This should be called after `DMPlexSetChart()`. 3065 3066 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3067 @*/ 3068 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3069 { 3070 DM_Plex *mesh = (DM_Plex *)dm->data; 3071 3072 PetscFunctionBegin; 3073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3074 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3075 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3076 PetscFunctionReturn(PETSC_SUCCESS); 3077 } 3078 3079 /*@C 3080 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3081 3082 Not Collective 3083 3084 Input Parameters: 3085 + dm - The `DMPLEX` 3086 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3087 3088 Output Parameter: 3089 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3090 3091 Level: beginner 3092 3093 Fortran Notes: 3094 `cone` must be declared with 3095 .vb 3096 PetscInt, pointer :: cone(:) 3097 .ve 3098 3099 You must also call `DMPlexRestoreCone()` after you finish using the array. 3100 `DMPlexRestoreCone()` is not needed/available in C. 3101 3102 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3103 @*/ 3104 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3105 { 3106 DM_Plex *mesh = (DM_Plex *)dm->data; 3107 PetscInt off; 3108 3109 PetscFunctionBegin; 3110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3111 PetscAssertPointer(cone, 3); 3112 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3113 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3114 PetscFunctionReturn(PETSC_SUCCESS); 3115 } 3116 3117 /*@ 3118 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3119 3120 Not Collective 3121 3122 Input Parameters: 3123 + dm - The `DMPLEX` 3124 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3125 3126 Output Parameters: 3127 + pConesSection - `PetscSection` describing the layout of `pCones` 3128 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3129 3130 Level: intermediate 3131 3132 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3133 @*/ 3134 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3135 { 3136 PetscSection cs, newcs; 3137 PetscInt *cones; 3138 PetscInt *newarr = NULL; 3139 PetscInt n; 3140 3141 PetscFunctionBegin; 3142 PetscCall(DMPlexGetCones(dm, &cones)); 3143 PetscCall(DMPlexGetConeSection(dm, &cs)); 3144 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3145 if (pConesSection) *pConesSection = newcs; 3146 if (pCones) { 3147 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3148 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3149 } 3150 PetscFunctionReturn(PETSC_SUCCESS); 3151 } 3152 3153 /*@ 3154 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3155 3156 Not Collective 3157 3158 Input Parameters: 3159 + dm - The `DMPLEX` 3160 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3161 3162 Output Parameter: 3163 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3164 3165 Level: advanced 3166 3167 Notes: 3168 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3169 3170 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3171 3172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3173 `DMPlexGetDepth()`, `IS` 3174 @*/ 3175 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3176 { 3177 IS *expandedPointsAll; 3178 PetscInt depth; 3179 3180 PetscFunctionBegin; 3181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3182 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3183 PetscAssertPointer(expandedPoints, 3); 3184 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3185 *expandedPoints = expandedPointsAll[0]; 3186 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3187 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3188 PetscFunctionReturn(PETSC_SUCCESS); 3189 } 3190 3191 /*@ 3192 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3193 (DAG points of depth 0, i.e., without cones). 3194 3195 Not Collective 3196 3197 Input Parameters: 3198 + dm - The `DMPLEX` 3199 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3200 3201 Output Parameters: 3202 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3203 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3204 - sections - (optional) An array of sections which describe mappings from points to their cone points 3205 3206 Level: advanced 3207 3208 Notes: 3209 Like `DMPlexGetConeTuple()` but recursive. 3210 3211 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. 3212 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3213 3214 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\: 3215 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3216 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3217 3218 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3219 `DMPlexGetDepth()`, `PetscSection`, `IS` 3220 @*/ 3221 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3222 { 3223 const PetscInt *arr0 = NULL, *cone = NULL; 3224 PetscInt *arr = NULL, *newarr = NULL; 3225 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3226 IS *expandedPoints_; 3227 PetscSection *sections_; 3228 3229 PetscFunctionBegin; 3230 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3231 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3232 if (depth) PetscAssertPointer(depth, 3); 3233 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3234 if (sections) PetscAssertPointer(sections, 5); 3235 PetscCall(ISGetLocalSize(points, &n)); 3236 PetscCall(ISGetIndices(points, &arr0)); 3237 PetscCall(DMPlexGetDepth(dm, &depth_)); 3238 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3239 PetscCall(PetscCalloc1(depth_, §ions_)); 3240 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3241 for (d = depth_ - 1; d >= 0; d--) { 3242 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3243 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3244 for (i = 0; i < n; i++) { 3245 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3246 if (arr[i] >= start && arr[i] < end) { 3247 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3248 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3249 } else { 3250 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3251 } 3252 } 3253 PetscCall(PetscSectionSetUp(sections_[d])); 3254 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3255 PetscCall(PetscMalloc1(newn, &newarr)); 3256 for (i = 0; i < n; i++) { 3257 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3258 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3259 if (cn > 1) { 3260 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3261 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3262 } else { 3263 newarr[co] = arr[i]; 3264 } 3265 } 3266 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3267 arr = newarr; 3268 n = newn; 3269 } 3270 PetscCall(ISRestoreIndices(points, &arr0)); 3271 *depth = depth_; 3272 if (expandedPoints) *expandedPoints = expandedPoints_; 3273 else { 3274 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3275 PetscCall(PetscFree(expandedPoints_)); 3276 } 3277 if (sections) *sections = sections_; 3278 else { 3279 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3280 PetscCall(PetscFree(sections_)); 3281 } 3282 PetscFunctionReturn(PETSC_SUCCESS); 3283 } 3284 3285 /*@ 3286 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3287 3288 Not Collective 3289 3290 Input Parameters: 3291 + dm - The `DMPLEX` 3292 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3293 3294 Output Parameters: 3295 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3296 . expandedPoints - (optional) An array of recursively expanded cones 3297 - sections - (optional) An array of sections which describe mappings from points to their cone points 3298 3299 Level: advanced 3300 3301 Note: 3302 See `DMPlexGetConeRecursive()` 3303 3304 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3305 `DMPlexGetDepth()`, `IS`, `PetscSection` 3306 @*/ 3307 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3308 { 3309 PetscInt d, depth_; 3310 3311 PetscFunctionBegin; 3312 PetscCall(DMPlexGetDepth(dm, &depth_)); 3313 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3314 if (depth) *depth = 0; 3315 if (expandedPoints) { 3316 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3317 PetscCall(PetscFree(*expandedPoints)); 3318 } 3319 if (sections) { 3320 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3321 PetscCall(PetscFree(*sections)); 3322 } 3323 PetscFunctionReturn(PETSC_SUCCESS); 3324 } 3325 3326 /*@ 3327 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 3328 3329 Not Collective 3330 3331 Input Parameters: 3332 + dm - The `DMPLEX` 3333 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3334 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3335 3336 Level: beginner 3337 3338 Note: 3339 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3340 3341 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3342 @*/ 3343 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3344 { 3345 DM_Plex *mesh = (DM_Plex *)dm->data; 3346 PetscInt dof, off, c; 3347 3348 PetscFunctionBegin; 3349 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3350 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3351 if (dof) PetscAssertPointer(cone, 3); 3352 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3353 if (PetscDefined(USE_DEBUG)) { 3354 PetscInt pStart, pEnd; 3355 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3356 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); 3357 for (c = 0; c < dof; ++c) { 3358 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); 3359 mesh->cones[off + c] = cone[c]; 3360 } 3361 } else { 3362 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3363 } 3364 PetscFunctionReturn(PETSC_SUCCESS); 3365 } 3366 3367 /*@C 3368 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3369 3370 Not Collective 3371 3372 Input Parameters: 3373 + dm - The `DMPLEX` 3374 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3375 3376 Output Parameter: 3377 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3378 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3379 3380 Level: beginner 3381 3382 Note: 3383 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3384 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3385 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3386 with the identity. 3387 3388 Fortran Notes: 3389 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3390 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3391 3392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3393 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3394 @*/ 3395 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3396 { 3397 DM_Plex *mesh = (DM_Plex *)dm->data; 3398 PetscInt off; 3399 3400 PetscFunctionBegin; 3401 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3402 if (PetscDefined(USE_DEBUG)) { 3403 PetscInt dof; 3404 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3405 if (dof) PetscAssertPointer(coneOrientation, 3); 3406 } 3407 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3408 3409 *coneOrientation = &mesh->coneOrientations[off]; 3410 PetscFunctionReturn(PETSC_SUCCESS); 3411 } 3412 3413 /*@ 3414 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3415 3416 Not Collective 3417 3418 Input Parameters: 3419 + dm - The `DMPLEX` 3420 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3421 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3422 3423 Level: beginner 3424 3425 Notes: 3426 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3427 3428 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3429 3430 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3431 @*/ 3432 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3433 { 3434 DM_Plex *mesh = (DM_Plex *)dm->data; 3435 PetscInt pStart, pEnd; 3436 PetscInt dof, off, c; 3437 3438 PetscFunctionBegin; 3439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3440 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3441 if (dof) PetscAssertPointer(coneOrientation, 3); 3442 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3443 if (PetscDefined(USE_DEBUG)) { 3444 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3445 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); 3446 for (c = 0; c < dof; ++c) { 3447 PetscInt cdof, o = coneOrientation[c]; 3448 3449 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3450 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); 3451 mesh->coneOrientations[off + c] = o; 3452 } 3453 } else { 3454 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3455 } 3456 PetscFunctionReturn(PETSC_SUCCESS); 3457 } 3458 3459 /*@ 3460 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3461 3462 Not Collective 3463 3464 Input Parameters: 3465 + dm - The `DMPLEX` 3466 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3467 . conePos - The local index in the cone where the point should be put 3468 - conePoint - The mesh point to insert 3469 3470 Level: beginner 3471 3472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3473 @*/ 3474 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3475 { 3476 DM_Plex *mesh = (DM_Plex *)dm->data; 3477 PetscInt pStart, pEnd; 3478 PetscInt dof, off; 3479 3480 PetscFunctionBegin; 3481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3482 if (PetscDefined(USE_DEBUG)) { 3483 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3484 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); 3485 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); 3486 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3487 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); 3488 } 3489 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3490 mesh->cones[off + conePos] = conePoint; 3491 PetscFunctionReturn(PETSC_SUCCESS); 3492 } 3493 3494 /*@ 3495 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3496 3497 Not Collective 3498 3499 Input Parameters: 3500 + dm - The `DMPLEX` 3501 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3502 . conePos - The local index in the cone where the point should be put 3503 - coneOrientation - The point orientation to insert 3504 3505 Level: beginner 3506 3507 Note: 3508 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3509 3510 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3511 @*/ 3512 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3513 { 3514 DM_Plex *mesh = (DM_Plex *)dm->data; 3515 PetscInt pStart, pEnd; 3516 PetscInt dof, off; 3517 3518 PetscFunctionBegin; 3519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3520 if (PetscDefined(USE_DEBUG)) { 3521 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3522 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); 3523 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3524 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); 3525 } 3526 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3527 mesh->coneOrientations[off + conePos] = coneOrientation; 3528 PetscFunctionReturn(PETSC_SUCCESS); 3529 } 3530 3531 /*@C 3532 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3533 3534 Not collective 3535 3536 Input Parameters: 3537 + dm - The DMPlex 3538 - p - The point, which must lie in the chart set with DMPlexSetChart() 3539 3540 Output Parameters: 3541 + cone - An array of points which are on the in-edges for point `p` 3542 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3543 integer giving the prescription for cone traversal. 3544 3545 Level: beginner 3546 3547 Notes: 3548 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3549 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3550 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3551 with the identity. 3552 3553 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3554 3555 Fortran Notes: 3556 `cone` and `ornt` must be declared with 3557 .vb 3558 PetscInt, pointer :: cone(:) 3559 PetscInt, pointer :: ornt(:) 3560 .ve 3561 3562 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3563 @*/ 3564 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3565 { 3566 DM_Plex *mesh = (DM_Plex *)dm->data; 3567 3568 PetscFunctionBegin; 3569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3570 if (mesh->tr) { 3571 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3572 } else { 3573 PetscInt off; 3574 if (PetscDefined(USE_DEBUG)) { 3575 PetscInt dof; 3576 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3577 if (dof) { 3578 if (cone) PetscAssertPointer(cone, 3); 3579 if (ornt) PetscAssertPointer(ornt, 4); 3580 } 3581 } 3582 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3583 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3584 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3585 } 3586 PetscFunctionReturn(PETSC_SUCCESS); 3587 } 3588 3589 /*@C 3590 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3591 3592 Not Collective 3593 3594 Input Parameters: 3595 + dm - The DMPlex 3596 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3597 . cone - An array of points which are on the in-edges for point p 3598 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3599 integer giving the prescription for cone traversal. 3600 3601 Level: beginner 3602 3603 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3604 @*/ 3605 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3606 { 3607 DM_Plex *mesh = (DM_Plex *)dm->data; 3608 3609 PetscFunctionBegin; 3610 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3611 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3612 PetscFunctionReturn(PETSC_SUCCESS); 3613 } 3614 3615 /*@ 3616 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3617 3618 Not Collective 3619 3620 Input Parameters: 3621 + dm - The `DMPLEX` 3622 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3623 3624 Output Parameter: 3625 . size - The support size for point `p` 3626 3627 Level: beginner 3628 3629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3630 @*/ 3631 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3632 { 3633 DM_Plex *mesh = (DM_Plex *)dm->data; 3634 3635 PetscFunctionBegin; 3636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3637 PetscAssertPointer(size, 3); 3638 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3639 PetscFunctionReturn(PETSC_SUCCESS); 3640 } 3641 3642 /*@ 3643 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3644 3645 Not Collective 3646 3647 Input Parameters: 3648 + dm - The `DMPLEX` 3649 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3650 - size - The support size for point `p` 3651 3652 Level: beginner 3653 3654 Note: 3655 This should be called after `DMPlexSetChart()`. 3656 3657 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3658 @*/ 3659 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3660 { 3661 DM_Plex *mesh = (DM_Plex *)dm->data; 3662 3663 PetscFunctionBegin; 3664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3665 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3666 PetscFunctionReturn(PETSC_SUCCESS); 3667 } 3668 3669 /*@C 3670 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3671 3672 Not Collective 3673 3674 Input Parameters: 3675 + dm - The `DMPLEX` 3676 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3677 3678 Output Parameter: 3679 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3680 3681 Level: beginner 3682 3683 Fortran Notes: 3684 `support` must be declared with 3685 .vb 3686 PetscInt, pointer :: support(:) 3687 .ve 3688 3689 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3690 `DMPlexRestoreSupport()` is not needed/available in C. 3691 3692 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3693 @*/ 3694 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3695 { 3696 DM_Plex *mesh = (DM_Plex *)dm->data; 3697 PetscInt off; 3698 3699 PetscFunctionBegin; 3700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3701 PetscAssertPointer(support, 3); 3702 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3703 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3704 PetscFunctionReturn(PETSC_SUCCESS); 3705 } 3706 3707 /*@ 3708 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3709 3710 Not Collective 3711 3712 Input Parameters: 3713 + dm - The `DMPLEX` 3714 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3715 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3716 3717 Level: beginner 3718 3719 Note: 3720 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3721 3722 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3723 @*/ 3724 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3725 { 3726 DM_Plex *mesh = (DM_Plex *)dm->data; 3727 PetscInt pStart, pEnd; 3728 PetscInt dof, off, c; 3729 3730 PetscFunctionBegin; 3731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3732 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3733 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3734 if (dof) PetscAssertPointer(support, 3); 3735 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3736 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); 3737 for (c = 0; c < dof; ++c) { 3738 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); 3739 mesh->supports[off + c] = support[c]; 3740 } 3741 PetscFunctionReturn(PETSC_SUCCESS); 3742 } 3743 3744 /*@ 3745 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3746 3747 Not Collective 3748 3749 Input Parameters: 3750 + dm - The `DMPLEX` 3751 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3752 . supportPos - The local index in the cone where the point should be put 3753 - supportPoint - The mesh point to insert 3754 3755 Level: beginner 3756 3757 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3758 @*/ 3759 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3760 { 3761 DM_Plex *mesh = (DM_Plex *)dm->data; 3762 PetscInt pStart, pEnd; 3763 PetscInt dof, off; 3764 3765 PetscFunctionBegin; 3766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3767 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3768 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3769 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3770 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); 3771 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); 3772 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); 3773 mesh->supports[off + supportPos] = supportPoint; 3774 PetscFunctionReturn(PETSC_SUCCESS); 3775 } 3776 3777 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3778 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3779 { 3780 switch (ct) { 3781 case DM_POLYTOPE_SEGMENT: 3782 if (o == -1) return -2; 3783 break; 3784 case DM_POLYTOPE_TRIANGLE: 3785 if (o == -3) return -1; 3786 if (o == -2) return -3; 3787 if (o == -1) return -2; 3788 break; 3789 case DM_POLYTOPE_QUADRILATERAL: 3790 if (o == -4) return -2; 3791 if (o == -3) return -1; 3792 if (o == -2) return -4; 3793 if (o == -1) return -3; 3794 break; 3795 default: 3796 return o; 3797 } 3798 return o; 3799 } 3800 3801 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3802 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3803 { 3804 switch (ct) { 3805 case DM_POLYTOPE_SEGMENT: 3806 if ((o == -2) || (o == 1)) return -1; 3807 if (o == -1) return 0; 3808 break; 3809 case DM_POLYTOPE_TRIANGLE: 3810 if (o == -3) return -2; 3811 if (o == -2) return -1; 3812 if (o == -1) return -3; 3813 break; 3814 case DM_POLYTOPE_QUADRILATERAL: 3815 if (o == -4) return -2; 3816 if (o == -3) return -1; 3817 if (o == -2) return -4; 3818 if (o == -1) return -3; 3819 break; 3820 default: 3821 return o; 3822 } 3823 return o; 3824 } 3825 3826 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3827 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3828 { 3829 PetscInt pStart, pEnd, p; 3830 3831 PetscFunctionBegin; 3832 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3833 for (p = pStart; p < pEnd; ++p) { 3834 const PetscInt *cone, *ornt; 3835 PetscInt coneSize, c; 3836 3837 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3838 PetscCall(DMPlexGetCone(dm, p, &cone)); 3839 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3840 for (c = 0; c < coneSize; ++c) { 3841 DMPolytopeType ct; 3842 const PetscInt o = ornt[c]; 3843 3844 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3845 switch (ct) { 3846 case DM_POLYTOPE_SEGMENT: 3847 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3848 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3849 break; 3850 case DM_POLYTOPE_TRIANGLE: 3851 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3852 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3853 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3854 break; 3855 case DM_POLYTOPE_QUADRILATERAL: 3856 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3857 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3858 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3859 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3860 break; 3861 default: 3862 break; 3863 } 3864 } 3865 } 3866 PetscFunctionReturn(PETSC_SUCCESS); 3867 } 3868 3869 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3870 { 3871 DM_Plex *mesh = (DM_Plex *)dm->data; 3872 3873 PetscFunctionBeginHot; 3874 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3875 if (useCone) { 3876 PetscCall(DMPlexGetConeSize(dm, p, size)); 3877 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3878 } else { 3879 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3880 PetscCall(DMPlexGetSupport(dm, p, arr)); 3881 } 3882 } else { 3883 if (useCone) { 3884 const PetscSection s = mesh->coneSection; 3885 const PetscInt ps = p - s->pStart; 3886 const PetscInt off = s->atlasOff[ps]; 3887 3888 *size = s->atlasDof[ps]; 3889 *arr = mesh->cones + off; 3890 *ornt = mesh->coneOrientations + off; 3891 } else { 3892 const PetscSection s = mesh->supportSection; 3893 const PetscInt ps = p - s->pStart; 3894 const PetscInt off = s->atlasOff[ps]; 3895 3896 *size = s->atlasDof[ps]; 3897 *arr = mesh->supports + off; 3898 } 3899 } 3900 PetscFunctionReturn(PETSC_SUCCESS); 3901 } 3902 3903 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3904 { 3905 DM_Plex *mesh = (DM_Plex *)dm->data; 3906 3907 PetscFunctionBeginHot; 3908 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3909 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3910 } 3911 PetscFunctionReturn(PETSC_SUCCESS); 3912 } 3913 3914 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3915 { 3916 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3917 PetscInt *closure; 3918 const PetscInt *tmp = NULL, *tmpO = NULL; 3919 PetscInt off = 0, tmpSize, t; 3920 3921 PetscFunctionBeginHot; 3922 if (ornt) { 3923 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3924 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; 3925 } 3926 if (*points) { 3927 closure = *points; 3928 } else { 3929 PetscInt maxConeSize, maxSupportSize; 3930 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3931 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3932 } 3933 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3934 if (ct == DM_POLYTOPE_UNKNOWN) { 3935 closure[off++] = p; 3936 closure[off++] = 0; 3937 for (t = 0; t < tmpSize; ++t) { 3938 closure[off++] = tmp[t]; 3939 closure[off++] = tmpO ? tmpO[t] : 0; 3940 } 3941 } else { 3942 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3943 3944 /* We assume that cells with a valid type have faces with a valid type */ 3945 closure[off++] = p; 3946 closure[off++] = ornt; 3947 for (t = 0; t < tmpSize; ++t) { 3948 DMPolytopeType ft; 3949 3950 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3951 closure[off++] = tmp[arr[t]]; 3952 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3953 } 3954 } 3955 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3956 if (numPoints) *numPoints = tmpSize + 1; 3957 if (points) *points = closure; 3958 PetscFunctionReturn(PETSC_SUCCESS); 3959 } 3960 3961 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3962 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3963 { 3964 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3965 const PetscInt *cone, *ornt; 3966 PetscInt *pts, *closure = NULL; 3967 DMPolytopeType ft; 3968 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3969 PetscInt dim, coneSize, c, d, clSize, cl; 3970 3971 PetscFunctionBeginHot; 3972 PetscCall(DMGetDimension(dm, &dim)); 3973 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3974 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3975 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3976 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3977 maxSize = PetscMax(coneSeries, supportSeries); 3978 if (*points) { 3979 pts = *points; 3980 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3981 c = 0; 3982 pts[c++] = point; 3983 pts[c++] = o; 3984 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3985 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3986 for (cl = 0; cl < clSize * 2; cl += 2) { 3987 pts[c++] = closure[cl]; 3988 pts[c++] = closure[cl + 1]; 3989 } 3990 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3991 for (cl = 0; cl < clSize * 2; cl += 2) { 3992 pts[c++] = closure[cl]; 3993 pts[c++] = closure[cl + 1]; 3994 } 3995 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3996 for (d = 2; d < coneSize; ++d) { 3997 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3998 pts[c++] = cone[arr[d * 2 + 0]]; 3999 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4000 } 4001 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4002 if (dim >= 3) { 4003 for (d = 2; d < coneSize; ++d) { 4004 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4005 const PetscInt *fcone, *fornt; 4006 PetscInt fconeSize, fc, i; 4007 4008 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4009 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4010 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4011 for (fc = 0; fc < fconeSize; ++fc) { 4012 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4013 const PetscInt co = farr[fc * 2 + 1]; 4014 4015 for (i = 0; i < c; i += 2) 4016 if (pts[i] == cp) break; 4017 if (i == c) { 4018 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4019 pts[c++] = cp; 4020 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4021 } 4022 } 4023 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4024 } 4025 } 4026 *numPoints = c / 2; 4027 *points = pts; 4028 PetscFunctionReturn(PETSC_SUCCESS); 4029 } 4030 4031 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4032 { 4033 DMPolytopeType ct; 4034 PetscInt *closure, *fifo; 4035 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4036 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4037 PetscInt depth, maxSize; 4038 4039 PetscFunctionBeginHot; 4040 PetscCall(DMPlexGetDepth(dm, &depth)); 4041 if (depth == 1) { 4042 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4043 PetscFunctionReturn(PETSC_SUCCESS); 4044 } 4045 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4046 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; 4047 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4048 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4049 PetscFunctionReturn(PETSC_SUCCESS); 4050 } 4051 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4052 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4053 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4054 maxSize = PetscMax(coneSeries, supportSeries); 4055 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4056 if (*points) { 4057 closure = *points; 4058 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4059 closure[closureSize++] = p; 4060 closure[closureSize++] = ornt; 4061 fifo[fifoSize++] = p; 4062 fifo[fifoSize++] = ornt; 4063 fifo[fifoSize++] = ct; 4064 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4065 while (fifoSize - fifoStart) { 4066 const PetscInt q = fifo[fifoStart++]; 4067 const PetscInt o = fifo[fifoStart++]; 4068 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4069 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4070 const PetscInt *tmp, *tmpO = NULL; 4071 PetscInt tmpSize, t; 4072 4073 if (PetscDefined(USE_DEBUG)) { 4074 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4075 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); 4076 } 4077 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4078 for (t = 0; t < tmpSize; ++t) { 4079 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4080 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4081 const PetscInt cp = tmp[ip]; 4082 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4083 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4084 PetscInt c; 4085 4086 /* Check for duplicate */ 4087 for (c = 0; c < closureSize; c += 2) { 4088 if (closure[c] == cp) break; 4089 } 4090 if (c == closureSize) { 4091 closure[closureSize++] = cp; 4092 closure[closureSize++] = co; 4093 fifo[fifoSize++] = cp; 4094 fifo[fifoSize++] = co; 4095 fifo[fifoSize++] = ct; 4096 } 4097 } 4098 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4099 } 4100 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4101 if (numPoints) *numPoints = closureSize / 2; 4102 if (points) *points = closure; 4103 PetscFunctionReturn(PETSC_SUCCESS); 4104 } 4105 4106 /*@C 4107 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4108 4109 Not Collective 4110 4111 Input Parameters: 4112 + dm - The `DMPLEX` 4113 . p - The mesh point 4114 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4115 4116 Input/Output Parameter: 4117 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4118 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4119 otherwise the provided array is used to hold the values 4120 4121 Output Parameter: 4122 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4123 4124 Level: beginner 4125 4126 Note: 4127 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4128 4129 Fortran Notes: 4130 `points` must be declared with 4131 .vb 4132 PetscInt, pointer :: points(:) 4133 .ve 4134 and is always allocated by the function. 4135 4136 The `numPoints` argument is not present in the Fortran binding. 4137 4138 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4139 @*/ 4140 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4141 { 4142 PetscFunctionBeginHot; 4143 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4144 if (numPoints) PetscAssertPointer(numPoints, 4); 4145 if (points) PetscAssertPointer(points, 5); 4146 if (PetscDefined(USE_DEBUG)) { 4147 PetscInt pStart, pEnd; 4148 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4149 PetscCheck(p >= pStart && p < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 4150 } 4151 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4152 PetscFunctionReturn(PETSC_SUCCESS); 4153 } 4154 4155 /*@C 4156 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4157 4158 Not Collective 4159 4160 Input Parameters: 4161 + dm - The `DMPLEX` 4162 . p - The mesh point 4163 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4164 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4165 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4166 4167 Level: beginner 4168 4169 Note: 4170 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4171 4172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4173 @*/ 4174 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4175 { 4176 PetscFunctionBeginHot; 4177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4178 if (numPoints) *numPoints = 0; 4179 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4180 PetscFunctionReturn(PETSC_SUCCESS); 4181 } 4182 4183 /*@ 4184 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4185 4186 Not Collective 4187 4188 Input Parameter: 4189 . dm - The `DMPLEX` 4190 4191 Output Parameters: 4192 + maxConeSize - The maximum number of in-edges 4193 - maxSupportSize - The maximum number of out-edges 4194 4195 Level: beginner 4196 4197 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4198 @*/ 4199 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4200 { 4201 DM_Plex *mesh = (DM_Plex *)dm->data; 4202 4203 PetscFunctionBegin; 4204 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4205 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4206 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4207 PetscFunctionReturn(PETSC_SUCCESS); 4208 } 4209 4210 PetscErrorCode DMSetUp_Plex(DM dm) 4211 { 4212 DM_Plex *mesh = (DM_Plex *)dm->data; 4213 PetscInt size, maxSupportSize; 4214 4215 PetscFunctionBegin; 4216 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4217 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4218 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4219 PetscCall(PetscMalloc1(size, &mesh->cones)); 4220 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4221 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4222 if (maxSupportSize) { 4223 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4224 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4225 PetscCall(PetscMalloc1(size, &mesh->supports)); 4226 } 4227 PetscFunctionReturn(PETSC_SUCCESS); 4228 } 4229 4230 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4231 { 4232 PetscFunctionBegin; 4233 if (subdm) PetscCall(DMClone(dm, subdm)); 4234 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4235 if (subdm) (*subdm)->useNatural = dm->useNatural; 4236 if (dm->useNatural && dm->sfMigration) { 4237 PetscSF sfNatural; 4238 4239 (*subdm)->sfMigration = dm->sfMigration; 4240 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4241 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4242 (*subdm)->sfNatural = sfNatural; 4243 } 4244 PetscFunctionReturn(PETSC_SUCCESS); 4245 } 4246 4247 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4248 { 4249 PetscInt i = 0; 4250 4251 PetscFunctionBegin; 4252 PetscCall(DMClone(dms[0], superdm)); 4253 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4254 (*superdm)->useNatural = PETSC_FALSE; 4255 for (i = 0; i < len; i++) { 4256 if (dms[i]->useNatural && dms[i]->sfMigration) { 4257 PetscSF sfNatural; 4258 4259 (*superdm)->sfMigration = dms[i]->sfMigration; 4260 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4261 (*superdm)->useNatural = PETSC_TRUE; 4262 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4263 (*superdm)->sfNatural = sfNatural; 4264 break; 4265 } 4266 } 4267 PetscFunctionReturn(PETSC_SUCCESS); 4268 } 4269 4270 /*@ 4271 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4272 4273 Not Collective 4274 4275 Input Parameter: 4276 . dm - The `DMPLEX` 4277 4278 Level: beginner 4279 4280 Note: 4281 This should be called after all calls to `DMPlexSetCone()` 4282 4283 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4284 @*/ 4285 PetscErrorCode DMPlexSymmetrize(DM dm) 4286 { 4287 DM_Plex *mesh = (DM_Plex *)dm->data; 4288 PetscInt *offsets; 4289 PetscInt supportSize; 4290 PetscInt pStart, pEnd, p; 4291 4292 PetscFunctionBegin; 4293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4294 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4295 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4296 /* Calculate support sizes */ 4297 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4298 for (p = pStart; p < pEnd; ++p) { 4299 PetscInt dof, off, c; 4300 4301 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4302 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4303 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4304 } 4305 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4306 /* Calculate supports */ 4307 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4308 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4309 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4310 for (p = pStart; p < pEnd; ++p) { 4311 PetscInt dof, off, c; 4312 4313 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4314 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4315 for (c = off; c < off + dof; ++c) { 4316 const PetscInt q = mesh->cones[c]; 4317 PetscInt offS; 4318 4319 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4320 4321 mesh->supports[offS + offsets[q]] = p; 4322 ++offsets[q]; 4323 } 4324 } 4325 PetscCall(PetscFree(offsets)); 4326 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4327 PetscFunctionReturn(PETSC_SUCCESS); 4328 } 4329 4330 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4331 { 4332 IS stratumIS; 4333 4334 PetscFunctionBegin; 4335 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4336 if (PetscDefined(USE_DEBUG)) { 4337 PetscInt qStart, qEnd, numLevels, level; 4338 PetscBool overlap = PETSC_FALSE; 4339 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4340 for (level = 0; level < numLevels; level++) { 4341 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4342 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4343 overlap = PETSC_TRUE; 4344 break; 4345 } 4346 } 4347 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); 4348 } 4349 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4350 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4351 PetscCall(ISDestroy(&stratumIS)); 4352 PetscFunctionReturn(PETSC_SUCCESS); 4353 } 4354 4355 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4356 { 4357 PetscInt *pMin, *pMax; 4358 PetscInt pStart, pEnd; 4359 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4360 4361 PetscFunctionBegin; 4362 { 4363 DMLabel label2; 4364 4365 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4366 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4367 } 4368 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4369 for (PetscInt p = pStart; p < pEnd; ++p) { 4370 DMPolytopeType ct; 4371 4372 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4373 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4374 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4375 } 4376 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4377 for (PetscInt d = dmin; d <= dmax; ++d) { 4378 pMin[d] = PETSC_MAX_INT; 4379 pMax[d] = PETSC_MIN_INT; 4380 } 4381 for (PetscInt p = pStart; p < pEnd; ++p) { 4382 DMPolytopeType ct; 4383 PetscInt d; 4384 4385 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4386 d = DMPolytopeTypeGetDim(ct); 4387 pMin[d] = PetscMin(p, pMin[d]); 4388 pMax[d] = PetscMax(p, pMax[d]); 4389 } 4390 for (PetscInt d = dmin; d <= dmax; ++d) { 4391 if (pMin[d] > pMax[d]) continue; 4392 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4393 } 4394 PetscCall(PetscFree2(pMin, pMax)); 4395 PetscFunctionReturn(PETSC_SUCCESS); 4396 } 4397 4398 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4399 { 4400 PetscInt pStart, pEnd; 4401 PetscInt numRoots = 0, numLeaves = 0; 4402 4403 PetscFunctionBegin; 4404 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4405 { 4406 /* Initialize roots and count leaves */ 4407 PetscInt sMin = PETSC_MAX_INT; 4408 PetscInt sMax = PETSC_MIN_INT; 4409 PetscInt coneSize, supportSize; 4410 4411 for (PetscInt p = pStart; p < pEnd; ++p) { 4412 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4413 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4414 if (!coneSize && supportSize) { 4415 sMin = PetscMin(p, sMin); 4416 sMax = PetscMax(p, sMax); 4417 ++numRoots; 4418 } else if (!supportSize && coneSize) { 4419 ++numLeaves; 4420 } else if (!supportSize && !coneSize) { 4421 /* Isolated points */ 4422 sMin = PetscMin(p, sMin); 4423 sMax = PetscMax(p, sMax); 4424 } 4425 } 4426 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4427 } 4428 4429 if (numRoots + numLeaves == (pEnd - pStart)) { 4430 PetscInt sMin = PETSC_MAX_INT; 4431 PetscInt sMax = PETSC_MIN_INT; 4432 PetscInt coneSize, supportSize; 4433 4434 for (PetscInt p = pStart; p < pEnd; ++p) { 4435 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4436 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4437 if (!supportSize && coneSize) { 4438 sMin = PetscMin(p, sMin); 4439 sMax = PetscMax(p, sMax); 4440 } 4441 } 4442 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4443 } else { 4444 PetscInt level = 0; 4445 PetscInt qStart, qEnd; 4446 4447 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4448 while (qEnd > qStart) { 4449 PetscInt sMin = PETSC_MAX_INT; 4450 PetscInt sMax = PETSC_MIN_INT; 4451 4452 for (PetscInt q = qStart; q < qEnd; ++q) { 4453 const PetscInt *support; 4454 PetscInt supportSize; 4455 4456 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4457 PetscCall(DMPlexGetSupport(dm, q, &support)); 4458 for (PetscInt s = 0; s < supportSize; ++s) { 4459 sMin = PetscMin(support[s], sMin); 4460 sMax = PetscMax(support[s], sMax); 4461 } 4462 } 4463 PetscCall(DMLabelGetNumValues(label, &level)); 4464 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4465 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4466 } 4467 } 4468 PetscFunctionReturn(PETSC_SUCCESS); 4469 } 4470 4471 /*@ 4472 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4473 4474 Collective 4475 4476 Input Parameter: 4477 . dm - The `DMPLEX` 4478 4479 Level: beginner 4480 4481 Notes: 4482 The strata group all points of the same grade, and this function calculates the strata. This 4483 grade can be seen as the height (or depth) of the point in the DAG. 4484 4485 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4486 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4487 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4488 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4489 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4490 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4491 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4492 4493 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4494 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4495 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 4496 to interpolate only that one (e0), so that 4497 .vb 4498 cone(c0) = {e0, v2} 4499 cone(e0) = {v0, v1} 4500 .ve 4501 If `DMPlexStratify()` is run on this mesh, it will give depths 4502 .vb 4503 depth 0 = {v0, v1, v2} 4504 depth 1 = {e0, c0} 4505 .ve 4506 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4507 4508 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4509 4510 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4511 @*/ 4512 PetscErrorCode DMPlexStratify(DM dm) 4513 { 4514 DM_Plex *mesh = (DM_Plex *)dm->data; 4515 DMLabel label; 4516 PetscBool flg = PETSC_FALSE; 4517 4518 PetscFunctionBegin; 4519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4520 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4521 4522 // Create depth label 4523 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4524 PetscCall(DMCreateLabel(dm, "depth")); 4525 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4526 4527 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4528 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4529 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4530 4531 { /* just in case there is an empty process */ 4532 PetscInt numValues, maxValues = 0, v; 4533 4534 PetscCall(DMLabelGetNumValues(label, &numValues)); 4535 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4536 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4537 } 4538 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4539 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4540 PetscFunctionReturn(PETSC_SUCCESS); 4541 } 4542 4543 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4544 { 4545 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4546 PetscInt dim, depth, pheight, coneSize; 4547 4548 PetscFunctionBeginHot; 4549 PetscCall(DMGetDimension(dm, &dim)); 4550 PetscCall(DMPlexGetDepth(dm, &depth)); 4551 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4552 pheight = depth - pdepth; 4553 if (depth <= 1) { 4554 switch (pdepth) { 4555 case 0: 4556 ct = DM_POLYTOPE_POINT; 4557 break; 4558 case 1: 4559 switch (coneSize) { 4560 case 2: 4561 ct = DM_POLYTOPE_SEGMENT; 4562 break; 4563 case 3: 4564 ct = DM_POLYTOPE_TRIANGLE; 4565 break; 4566 case 4: 4567 switch (dim) { 4568 case 2: 4569 ct = DM_POLYTOPE_QUADRILATERAL; 4570 break; 4571 case 3: 4572 ct = DM_POLYTOPE_TETRAHEDRON; 4573 break; 4574 default: 4575 break; 4576 } 4577 break; 4578 case 5: 4579 ct = DM_POLYTOPE_PYRAMID; 4580 break; 4581 case 6: 4582 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4583 break; 4584 case 8: 4585 ct = DM_POLYTOPE_HEXAHEDRON; 4586 break; 4587 default: 4588 break; 4589 } 4590 } 4591 } else { 4592 if (pdepth == 0) { 4593 ct = DM_POLYTOPE_POINT; 4594 } else if (pheight == 0) { 4595 switch (dim) { 4596 case 1: 4597 switch (coneSize) { 4598 case 2: 4599 ct = DM_POLYTOPE_SEGMENT; 4600 break; 4601 default: 4602 break; 4603 } 4604 break; 4605 case 2: 4606 switch (coneSize) { 4607 case 3: 4608 ct = DM_POLYTOPE_TRIANGLE; 4609 break; 4610 case 4: 4611 ct = DM_POLYTOPE_QUADRILATERAL; 4612 break; 4613 default: 4614 break; 4615 } 4616 break; 4617 case 3: 4618 switch (coneSize) { 4619 case 4: 4620 ct = DM_POLYTOPE_TETRAHEDRON; 4621 break; 4622 case 5: { 4623 const PetscInt *cone; 4624 PetscInt faceConeSize; 4625 4626 PetscCall(DMPlexGetCone(dm, p, &cone)); 4627 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4628 switch (faceConeSize) { 4629 case 3: 4630 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4631 break; 4632 case 4: 4633 ct = DM_POLYTOPE_PYRAMID; 4634 break; 4635 } 4636 } break; 4637 case 6: 4638 ct = DM_POLYTOPE_HEXAHEDRON; 4639 break; 4640 default: 4641 break; 4642 } 4643 break; 4644 default: 4645 break; 4646 } 4647 } else if (pheight > 0) { 4648 switch (coneSize) { 4649 case 2: 4650 ct = DM_POLYTOPE_SEGMENT; 4651 break; 4652 case 3: 4653 ct = DM_POLYTOPE_TRIANGLE; 4654 break; 4655 case 4: 4656 ct = DM_POLYTOPE_QUADRILATERAL; 4657 break; 4658 default: 4659 break; 4660 } 4661 } 4662 } 4663 *pt = ct; 4664 PetscFunctionReturn(PETSC_SUCCESS); 4665 } 4666 4667 /*@ 4668 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4669 4670 Collective 4671 4672 Input Parameter: 4673 . dm - The `DMPLEX` 4674 4675 Level: developer 4676 4677 Note: 4678 This function is normally called automatically when a cell type is requested. It creates an 4679 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4680 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4681 4682 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4683 4684 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4685 @*/ 4686 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4687 { 4688 DM_Plex *mesh; 4689 DMLabel ctLabel; 4690 PetscInt pStart, pEnd, p; 4691 4692 PetscFunctionBegin; 4693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4694 mesh = (DM_Plex *)dm->data; 4695 PetscCall(DMCreateLabel(dm, "celltype")); 4696 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4697 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4698 PetscCall(PetscFree(mesh->cellTypes)); 4699 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4700 for (p = pStart; p < pEnd; ++p) { 4701 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4702 PetscInt pdepth; 4703 4704 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4705 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4706 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]); 4707 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4708 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4709 } 4710 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4711 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4712 PetscFunctionReturn(PETSC_SUCCESS); 4713 } 4714 4715 /*@C 4716 DMPlexGetJoin - Get an array for the join of the set of points 4717 4718 Not Collective 4719 4720 Input Parameters: 4721 + dm - The `DMPLEX` object 4722 . numPoints - The number of input points for the join 4723 - points - The input points 4724 4725 Output Parameters: 4726 + numCoveredPoints - The number of points in the join 4727 - coveredPoints - The points in the join 4728 4729 Level: intermediate 4730 4731 Note: 4732 Currently, this is restricted to a single level join 4733 4734 Fortran Notes: 4735 `converedPoints` must be declared with 4736 .vb 4737 PetscInt, pointer :: coveredPints(:) 4738 .ve 4739 4740 The `numCoveredPoints` argument is not present in the Fortran binding. 4741 4742 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4743 @*/ 4744 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4745 { 4746 DM_Plex *mesh = (DM_Plex *)dm->data; 4747 PetscInt *join[2]; 4748 PetscInt joinSize, i = 0; 4749 PetscInt dof, off, p, c, m; 4750 PetscInt maxSupportSize; 4751 4752 PetscFunctionBegin; 4753 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4754 PetscAssertPointer(points, 3); 4755 PetscAssertPointer(numCoveredPoints, 4); 4756 PetscAssertPointer(coveredPoints, 5); 4757 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4758 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4759 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4760 /* Copy in support of first point */ 4761 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4762 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4763 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4764 /* Check each successive support */ 4765 for (p = 1; p < numPoints; ++p) { 4766 PetscInt newJoinSize = 0; 4767 4768 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4769 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4770 for (c = 0; c < dof; ++c) { 4771 const PetscInt point = mesh->supports[off + c]; 4772 4773 for (m = 0; m < joinSize; ++m) { 4774 if (point == join[i][m]) { 4775 join[1 - i][newJoinSize++] = point; 4776 break; 4777 } 4778 } 4779 } 4780 joinSize = newJoinSize; 4781 i = 1 - i; 4782 } 4783 *numCoveredPoints = joinSize; 4784 *coveredPoints = join[i]; 4785 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4786 PetscFunctionReturn(PETSC_SUCCESS); 4787 } 4788 4789 /*@C 4790 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4791 4792 Not Collective 4793 4794 Input Parameters: 4795 + dm - The `DMPLEX` object 4796 . numPoints - The number of input points for the join 4797 - points - The input points 4798 4799 Output Parameters: 4800 + numCoveredPoints - The number of points in the join 4801 - coveredPoints - The points in the join 4802 4803 Level: intermediate 4804 4805 Fortran Notes: 4806 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4807 4808 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4809 @*/ 4810 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4811 { 4812 PetscFunctionBegin; 4813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4814 if (points) PetscAssertPointer(points, 3); 4815 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4816 PetscAssertPointer(coveredPoints, 5); 4817 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4818 if (numCoveredPoints) *numCoveredPoints = 0; 4819 PetscFunctionReturn(PETSC_SUCCESS); 4820 } 4821 4822 /*@C 4823 DMPlexGetFullJoin - Get an array for the join of the set of points 4824 4825 Not Collective 4826 4827 Input Parameters: 4828 + dm - The `DMPLEX` object 4829 . numPoints - The number of input points for the join 4830 - points - The input points, its length is `numPoints` 4831 4832 Output Parameters: 4833 + numCoveredPoints - The number of points in the join 4834 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4835 4836 Level: intermediate 4837 4838 Fortran Notes: 4839 `points` and `converedPoints` must be declared with 4840 .vb 4841 PetscInt, pointer :: points(:) 4842 PetscInt, pointer :: coveredPints(:) 4843 .ve 4844 4845 The `numCoveredPoints` argument is not present in the Fortran binding. 4846 4847 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4848 @*/ 4849 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4850 { 4851 PetscInt *offsets, **closures; 4852 PetscInt *join[2]; 4853 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4854 PetscInt p, d, c, m, ms; 4855 4856 PetscFunctionBegin; 4857 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4858 PetscAssertPointer(points, 3); 4859 PetscAssertPointer(numCoveredPoints, 4); 4860 PetscAssertPointer(coveredPoints, 5); 4861 4862 PetscCall(DMPlexGetDepth(dm, &depth)); 4863 PetscCall(PetscCalloc1(numPoints, &closures)); 4864 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4865 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4866 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4867 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4868 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4869 4870 for (p = 0; p < numPoints; ++p) { 4871 PetscInt closureSize; 4872 4873 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4874 4875 offsets[p * (depth + 2) + 0] = 0; 4876 for (d = 0; d < depth + 1; ++d) { 4877 PetscInt pStart, pEnd, i; 4878 4879 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4880 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4881 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4882 offsets[p * (depth + 2) + d + 1] = i; 4883 break; 4884 } 4885 } 4886 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4887 } 4888 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); 4889 } 4890 for (d = 0; d < depth + 1; ++d) { 4891 PetscInt dof; 4892 4893 /* Copy in support of first point */ 4894 dof = offsets[d + 1] - offsets[d]; 4895 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4896 /* Check each successive cone */ 4897 for (p = 1; p < numPoints && joinSize; ++p) { 4898 PetscInt newJoinSize = 0; 4899 4900 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4901 for (c = 0; c < dof; ++c) { 4902 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4903 4904 for (m = 0; m < joinSize; ++m) { 4905 if (point == join[i][m]) { 4906 join[1 - i][newJoinSize++] = point; 4907 break; 4908 } 4909 } 4910 } 4911 joinSize = newJoinSize; 4912 i = 1 - i; 4913 } 4914 if (joinSize) break; 4915 } 4916 *numCoveredPoints = joinSize; 4917 *coveredPoints = join[i]; 4918 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4919 PetscCall(PetscFree(closures)); 4920 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4921 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4922 PetscFunctionReturn(PETSC_SUCCESS); 4923 } 4924 4925 /*@C 4926 DMPlexGetMeet - Get an array for the meet of the set of points 4927 4928 Not Collective 4929 4930 Input Parameters: 4931 + dm - The `DMPLEX` object 4932 . numPoints - The number of input points for the meet 4933 - points - The input points, of length `numPoints` 4934 4935 Output Parameters: 4936 + numCoveringPoints - The number of points in the meet 4937 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4938 4939 Level: intermediate 4940 4941 Note: 4942 Currently, this is restricted to a single level meet 4943 4944 Fortran Notes: 4945 `coveringPoints` must be declared with 4946 .vb 4947 PetscInt, pointer :: coveringPoints(:) 4948 .ve 4949 4950 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4951 4952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4953 @*/ 4954 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4955 { 4956 DM_Plex *mesh = (DM_Plex *)dm->data; 4957 PetscInt *meet[2]; 4958 PetscInt meetSize, i = 0; 4959 PetscInt dof, off, p, c, m; 4960 PetscInt maxConeSize; 4961 4962 PetscFunctionBegin; 4963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4964 PetscAssertPointer(points, 3); 4965 PetscAssertPointer(numCoveringPoints, 4); 4966 PetscAssertPointer(coveringPoints, 5); 4967 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4968 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4969 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4970 /* Copy in cone of first point */ 4971 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4972 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4973 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4974 /* Check each successive cone */ 4975 for (p = 1; p < numPoints; ++p) { 4976 PetscInt newMeetSize = 0; 4977 4978 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4979 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4980 for (c = 0; c < dof; ++c) { 4981 const PetscInt point = mesh->cones[off + c]; 4982 4983 for (m = 0; m < meetSize; ++m) { 4984 if (point == meet[i][m]) { 4985 meet[1 - i][newMeetSize++] = point; 4986 break; 4987 } 4988 } 4989 } 4990 meetSize = newMeetSize; 4991 i = 1 - i; 4992 } 4993 *numCoveringPoints = meetSize; 4994 *coveringPoints = meet[i]; 4995 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4996 PetscFunctionReturn(PETSC_SUCCESS); 4997 } 4998 4999 /*@C 5000 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5001 5002 Not Collective 5003 5004 Input Parameters: 5005 + dm - The `DMPLEX` object 5006 . numPoints - The number of input points for the meet 5007 - points - The input points 5008 5009 Output Parameters: 5010 + numCoveredPoints - The number of points in the meet 5011 - coveredPoints - The points in the meet 5012 5013 Level: intermediate 5014 5015 Fortran Notes: 5016 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5017 5018 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5019 @*/ 5020 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5021 { 5022 PetscFunctionBegin; 5023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5024 if (points) PetscAssertPointer(points, 3); 5025 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5026 PetscAssertPointer(coveredPoints, 5); 5027 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5028 if (numCoveredPoints) *numCoveredPoints = 0; 5029 PetscFunctionReturn(PETSC_SUCCESS); 5030 } 5031 5032 /*@C 5033 DMPlexGetFullMeet - Get an array for the meet of the set of points 5034 5035 Not Collective 5036 5037 Input Parameters: 5038 + dm - The `DMPLEX` object 5039 . numPoints - The number of input points for the meet 5040 - points - The input points, of length `numPoints` 5041 5042 Output Parameters: 5043 + numCoveredPoints - The number of points in the meet 5044 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5045 5046 Level: intermediate 5047 5048 Fortran Notes: 5049 `points` and `coveredPoints` must be declared with 5050 .vb 5051 PetscInt, pointer :: points(:) 5052 PetscInt, pointer :: coveredPoints(:) 5053 .ve 5054 5055 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5056 5057 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5058 @*/ 5059 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5060 { 5061 PetscInt *offsets, **closures; 5062 PetscInt *meet[2]; 5063 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5064 PetscInt p, h, c, m, mc; 5065 5066 PetscFunctionBegin; 5067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5068 PetscAssertPointer(points, 3); 5069 PetscAssertPointer(numCoveredPoints, 4); 5070 PetscAssertPointer(coveredPoints, 5); 5071 5072 PetscCall(DMPlexGetDepth(dm, &height)); 5073 PetscCall(PetscMalloc1(numPoints, &closures)); 5074 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5075 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5076 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5077 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5078 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5079 5080 for (p = 0; p < numPoints; ++p) { 5081 PetscInt closureSize; 5082 5083 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5084 5085 offsets[p * (height + 2) + 0] = 0; 5086 for (h = 0; h < height + 1; ++h) { 5087 PetscInt pStart, pEnd, i; 5088 5089 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5090 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5091 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5092 offsets[p * (height + 2) + h + 1] = i; 5093 break; 5094 } 5095 } 5096 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5097 } 5098 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); 5099 } 5100 for (h = 0; h < height + 1; ++h) { 5101 PetscInt dof; 5102 5103 /* Copy in cone of first point */ 5104 dof = offsets[h + 1] - offsets[h]; 5105 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5106 /* Check each successive cone */ 5107 for (p = 1; p < numPoints && meetSize; ++p) { 5108 PetscInt newMeetSize = 0; 5109 5110 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5111 for (c = 0; c < dof; ++c) { 5112 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5113 5114 for (m = 0; m < meetSize; ++m) { 5115 if (point == meet[i][m]) { 5116 meet[1 - i][newMeetSize++] = point; 5117 break; 5118 } 5119 } 5120 } 5121 meetSize = newMeetSize; 5122 i = 1 - i; 5123 } 5124 if (meetSize) break; 5125 } 5126 *numCoveredPoints = meetSize; 5127 *coveredPoints = meet[i]; 5128 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5129 PetscCall(PetscFree(closures)); 5130 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5131 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5132 PetscFunctionReturn(PETSC_SUCCESS); 5133 } 5134 5135 /*@ 5136 DMPlexEqual - Determine if two `DM` have the same topology 5137 5138 Not Collective 5139 5140 Input Parameters: 5141 + dmA - A `DMPLEX` object 5142 - dmB - A `DMPLEX` object 5143 5144 Output Parameter: 5145 . equal - `PETSC_TRUE` if the topologies are identical 5146 5147 Level: intermediate 5148 5149 Note: 5150 We are not solving graph isomorphism, so we do not permute. 5151 5152 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5153 @*/ 5154 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5155 { 5156 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5157 5158 PetscFunctionBegin; 5159 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5160 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5161 PetscAssertPointer(equal, 3); 5162 5163 *equal = PETSC_FALSE; 5164 PetscCall(DMPlexGetDepth(dmA, &depth)); 5165 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5166 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5167 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5168 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5169 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5170 for (p = pStart; p < pEnd; ++p) { 5171 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5172 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5173 5174 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5175 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5176 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5177 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5178 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5179 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5180 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5181 for (c = 0; c < coneSize; ++c) { 5182 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5183 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5184 } 5185 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5186 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5187 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5188 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5189 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5190 for (s = 0; s < supportSize; ++s) { 5191 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5192 } 5193 } 5194 *equal = PETSC_TRUE; 5195 PetscFunctionReturn(PETSC_SUCCESS); 5196 } 5197 5198 /*@ 5199 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5200 5201 Not Collective 5202 5203 Input Parameters: 5204 + dm - The `DMPLEX` 5205 . cellDim - The cell dimension 5206 - numCorners - The number of vertices on a cell 5207 5208 Output Parameter: 5209 . numFaceVertices - The number of vertices on a face 5210 5211 Level: developer 5212 5213 Note: 5214 Of course this can only work for a restricted set of symmetric shapes 5215 5216 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5217 @*/ 5218 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5219 { 5220 MPI_Comm comm; 5221 5222 PetscFunctionBegin; 5223 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5224 PetscAssertPointer(numFaceVertices, 4); 5225 switch (cellDim) { 5226 case 0: 5227 *numFaceVertices = 0; 5228 break; 5229 case 1: 5230 *numFaceVertices = 1; 5231 break; 5232 case 2: 5233 switch (numCorners) { 5234 case 3: /* triangle */ 5235 *numFaceVertices = 2; /* Edge has 2 vertices */ 5236 break; 5237 case 4: /* quadrilateral */ 5238 *numFaceVertices = 2; /* Edge has 2 vertices */ 5239 break; 5240 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5241 *numFaceVertices = 3; /* Edge has 3 vertices */ 5242 break; 5243 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5244 *numFaceVertices = 3; /* Edge has 3 vertices */ 5245 break; 5246 default: 5247 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5248 } 5249 break; 5250 case 3: 5251 switch (numCorners) { 5252 case 4: /* tetradehdron */ 5253 *numFaceVertices = 3; /* Face has 3 vertices */ 5254 break; 5255 case 6: /* tet cohesive cells */ 5256 *numFaceVertices = 4; /* Face has 4 vertices */ 5257 break; 5258 case 8: /* hexahedron */ 5259 *numFaceVertices = 4; /* Face has 4 vertices */ 5260 break; 5261 case 9: /* tet cohesive Lagrange cells */ 5262 *numFaceVertices = 6; /* Face has 6 vertices */ 5263 break; 5264 case 10: /* quadratic tetrahedron */ 5265 *numFaceVertices = 6; /* Face has 6 vertices */ 5266 break; 5267 case 12: /* hex cohesive Lagrange cells */ 5268 *numFaceVertices = 6; /* Face has 6 vertices */ 5269 break; 5270 case 18: /* quadratic tet cohesive Lagrange cells */ 5271 *numFaceVertices = 6; /* Face has 6 vertices */ 5272 break; 5273 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5274 *numFaceVertices = 9; /* Face has 9 vertices */ 5275 break; 5276 default: 5277 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5278 } 5279 break; 5280 default: 5281 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5282 } 5283 PetscFunctionReturn(PETSC_SUCCESS); 5284 } 5285 5286 /*@ 5287 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5288 5289 Not Collective 5290 5291 Input Parameter: 5292 . dm - The `DMPLEX` object 5293 5294 Output Parameter: 5295 . depthLabel - The `DMLabel` recording point depth 5296 5297 Level: developer 5298 5299 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5300 @*/ 5301 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5302 { 5303 PetscFunctionBegin; 5304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5305 PetscAssertPointer(depthLabel, 2); 5306 *depthLabel = dm->depthLabel; 5307 PetscFunctionReturn(PETSC_SUCCESS); 5308 } 5309 5310 /*@ 5311 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5312 5313 Not Collective 5314 5315 Input Parameter: 5316 . dm - The `DMPLEX` object 5317 5318 Output Parameter: 5319 . depth - The number of strata (breadth first levels) in the DAG 5320 5321 Level: developer 5322 5323 Notes: 5324 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5325 5326 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5327 5328 An empty mesh gives -1. 5329 5330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5331 @*/ 5332 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5333 { 5334 DM_Plex *mesh = (DM_Plex *)dm->data; 5335 DMLabel label; 5336 PetscInt d = -1; 5337 5338 PetscFunctionBegin; 5339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5340 PetscAssertPointer(depth, 2); 5341 if (mesh->tr) { 5342 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5343 } else { 5344 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5345 // Allow missing depths 5346 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5347 *depth = d; 5348 } 5349 PetscFunctionReturn(PETSC_SUCCESS); 5350 } 5351 5352 /*@ 5353 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5354 5355 Not Collective 5356 5357 Input Parameters: 5358 + dm - The `DMPLEX` object 5359 - depth - The requested depth 5360 5361 Output Parameters: 5362 + start - The first point at this `depth` 5363 - end - One beyond the last point at this `depth` 5364 5365 Level: developer 5366 5367 Notes: 5368 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5369 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5370 higher dimension, e.g., "edges". 5371 5372 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5373 @*/ 5374 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5375 { 5376 DM_Plex *mesh = (DM_Plex *)dm->data; 5377 DMLabel label; 5378 PetscInt pStart, pEnd; 5379 5380 PetscFunctionBegin; 5381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5382 if (start) { 5383 PetscAssertPointer(start, 3); 5384 *start = 0; 5385 } 5386 if (end) { 5387 PetscAssertPointer(end, 4); 5388 *end = 0; 5389 } 5390 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5391 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5392 if (depth < 0) { 5393 if (start) *start = pStart; 5394 if (end) *end = pEnd; 5395 PetscFunctionReturn(PETSC_SUCCESS); 5396 } 5397 if (mesh->tr) { 5398 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5399 } else { 5400 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5401 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5402 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5403 } 5404 PetscFunctionReturn(PETSC_SUCCESS); 5405 } 5406 5407 /*@ 5408 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5409 5410 Not Collective 5411 5412 Input Parameters: 5413 + dm - The `DMPLEX` object 5414 - height - The requested height 5415 5416 Output Parameters: 5417 + start - The first point at this `height` 5418 - end - One beyond the last point at this `height` 5419 5420 Level: developer 5421 5422 Notes: 5423 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5424 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5425 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5426 5427 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5428 @*/ 5429 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5430 { 5431 DMLabel label; 5432 PetscInt depth, pStart, pEnd; 5433 5434 PetscFunctionBegin; 5435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5436 if (start) { 5437 PetscAssertPointer(start, 3); 5438 *start = 0; 5439 } 5440 if (end) { 5441 PetscAssertPointer(end, 4); 5442 *end = 0; 5443 } 5444 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5445 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5446 if (height < 0) { 5447 if (start) *start = pStart; 5448 if (end) *end = pEnd; 5449 PetscFunctionReturn(PETSC_SUCCESS); 5450 } 5451 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5452 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5453 else PetscCall(DMGetDimension(dm, &depth)); 5454 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5455 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5456 PetscFunctionReturn(PETSC_SUCCESS); 5457 } 5458 5459 /*@ 5460 DMPlexGetPointDepth - Get the `depth` of a given point 5461 5462 Not Collective 5463 5464 Input Parameters: 5465 + dm - The `DMPLEX` object 5466 - point - The point 5467 5468 Output Parameter: 5469 . depth - The depth of the `point` 5470 5471 Level: intermediate 5472 5473 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5474 @*/ 5475 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5476 { 5477 PetscFunctionBegin; 5478 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5479 PetscAssertPointer(depth, 3); 5480 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5481 PetscFunctionReturn(PETSC_SUCCESS); 5482 } 5483 5484 /*@ 5485 DMPlexGetPointHeight - Get the `height` of a given point 5486 5487 Not Collective 5488 5489 Input Parameters: 5490 + dm - The `DMPLEX` object 5491 - point - The point 5492 5493 Output Parameter: 5494 . height - The height of the `point` 5495 5496 Level: intermediate 5497 5498 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5499 @*/ 5500 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5501 { 5502 PetscInt n, pDepth; 5503 5504 PetscFunctionBegin; 5505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5506 PetscAssertPointer(height, 3); 5507 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5508 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5509 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5510 PetscFunctionReturn(PETSC_SUCCESS); 5511 } 5512 5513 /*@ 5514 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5515 5516 Not Collective 5517 5518 Input Parameter: 5519 . dm - The `DMPLEX` object 5520 5521 Output Parameter: 5522 . celltypeLabel - The `DMLabel` recording cell polytope type 5523 5524 Level: developer 5525 5526 Note: 5527 This function will trigger automatica computation of cell types. This can be disabled by calling 5528 `DMCreateLabel`(dm, "celltype") beforehand. 5529 5530 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5531 @*/ 5532 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5533 { 5534 PetscFunctionBegin; 5535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5536 PetscAssertPointer(celltypeLabel, 2); 5537 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5538 *celltypeLabel = dm->celltypeLabel; 5539 PetscFunctionReturn(PETSC_SUCCESS); 5540 } 5541 5542 /*@ 5543 DMPlexGetCellType - Get the polytope type of a given cell 5544 5545 Not Collective 5546 5547 Input Parameters: 5548 + dm - The `DMPLEX` object 5549 - cell - The cell 5550 5551 Output Parameter: 5552 . celltype - The polytope type of the cell 5553 5554 Level: intermediate 5555 5556 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5557 @*/ 5558 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5559 { 5560 DM_Plex *mesh = (DM_Plex *)dm->data; 5561 DMLabel label; 5562 PetscInt ct; 5563 5564 PetscFunctionBegin; 5565 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5566 PetscAssertPointer(celltype, 3); 5567 if (mesh->tr) { 5568 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5569 } else { 5570 PetscInt pStart, pEnd; 5571 5572 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5573 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5574 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5575 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5576 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5577 for (PetscInt p = pStart; p < pEnd; p++) { 5578 PetscCall(DMLabelGetValue(label, p, &ct)); 5579 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5580 } 5581 } 5582 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5583 if (PetscDefined(USE_DEBUG)) { 5584 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5585 PetscCall(DMLabelGetValue(label, cell, &ct)); 5586 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5587 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5588 } 5589 } 5590 PetscFunctionReturn(PETSC_SUCCESS); 5591 } 5592 5593 /*@ 5594 DMPlexSetCellType - Set the polytope type of a given cell 5595 5596 Not Collective 5597 5598 Input Parameters: 5599 + dm - The `DMPLEX` object 5600 . cell - The cell 5601 - celltype - The polytope type of the cell 5602 5603 Level: advanced 5604 5605 Note: 5606 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5607 is executed. This function will override the computed type. However, if automatic classification will not succeed 5608 and a user wants to manually specify all types, the classification must be disabled by calling 5609 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5610 5611 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5612 @*/ 5613 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5614 { 5615 DM_Plex *mesh = (DM_Plex *)dm->data; 5616 DMLabel label; 5617 PetscInt pStart, pEnd; 5618 5619 PetscFunctionBegin; 5620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5621 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5622 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5623 PetscCall(DMLabelSetValue(label, cell, celltype)); 5624 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5625 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5626 PetscFunctionReturn(PETSC_SUCCESS); 5627 } 5628 5629 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5630 { 5631 PetscSection section; 5632 PetscInt maxHeight; 5633 const char *prefix; 5634 5635 PetscFunctionBegin; 5636 PetscCall(DMClone(dm, cdm)); 5637 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5638 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5639 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5640 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5641 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5642 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5643 PetscCall(DMSetLocalSection(*cdm, section)); 5644 PetscCall(PetscSectionDestroy(§ion)); 5645 5646 PetscCall(DMSetNumFields(*cdm, 1)); 5647 PetscCall(DMCreateDS(*cdm)); 5648 (*cdm)->cloneOpts = PETSC_TRUE; 5649 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5650 PetscFunctionReturn(PETSC_SUCCESS); 5651 } 5652 5653 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5654 { 5655 Vec coordsLocal, cellCoordsLocal; 5656 DM coordsDM, cellCoordsDM; 5657 5658 PetscFunctionBegin; 5659 *field = NULL; 5660 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5661 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5662 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5663 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5664 if (coordsLocal && coordsDM) { 5665 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5666 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5667 } 5668 PetscFunctionReturn(PETSC_SUCCESS); 5669 } 5670 5671 /*@ 5672 DMPlexGetConeSection - Return a section which describes the layout of cone data 5673 5674 Not Collective 5675 5676 Input Parameter: 5677 . dm - The `DMPLEX` object 5678 5679 Output Parameter: 5680 . section - The `PetscSection` object 5681 5682 Level: developer 5683 5684 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5685 @*/ 5686 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5687 { 5688 DM_Plex *mesh = (DM_Plex *)dm->data; 5689 5690 PetscFunctionBegin; 5691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5692 if (section) *section = mesh->coneSection; 5693 PetscFunctionReturn(PETSC_SUCCESS); 5694 } 5695 5696 /*@ 5697 DMPlexGetSupportSection - Return a section which describes the layout of support data 5698 5699 Not Collective 5700 5701 Input Parameter: 5702 . dm - The `DMPLEX` object 5703 5704 Output Parameter: 5705 . section - The `PetscSection` object 5706 5707 Level: developer 5708 5709 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5710 @*/ 5711 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5712 { 5713 DM_Plex *mesh = (DM_Plex *)dm->data; 5714 5715 PetscFunctionBegin; 5716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5717 if (section) *section = mesh->supportSection; 5718 PetscFunctionReturn(PETSC_SUCCESS); 5719 } 5720 5721 /*@C 5722 DMPlexGetCones - Return cone data 5723 5724 Not Collective 5725 5726 Input Parameter: 5727 . dm - The `DMPLEX` object 5728 5729 Output Parameter: 5730 . cones - The cone for each point 5731 5732 Level: developer 5733 5734 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5735 @*/ 5736 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5737 { 5738 DM_Plex *mesh = (DM_Plex *)dm->data; 5739 5740 PetscFunctionBegin; 5741 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5742 if (cones) *cones = mesh->cones; 5743 PetscFunctionReturn(PETSC_SUCCESS); 5744 } 5745 5746 /*@C 5747 DMPlexGetConeOrientations - Return cone orientation data 5748 5749 Not Collective 5750 5751 Input Parameter: 5752 . dm - The `DMPLEX` object 5753 5754 Output Parameter: 5755 . coneOrientations - The array of cone orientations for all points 5756 5757 Level: developer 5758 5759 Notes: 5760 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5761 as returned by `DMPlexGetConeOrientation()`. 5762 5763 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5764 5765 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5766 @*/ 5767 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5768 { 5769 DM_Plex *mesh = (DM_Plex *)dm->data; 5770 5771 PetscFunctionBegin; 5772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5773 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5774 PetscFunctionReturn(PETSC_SUCCESS); 5775 } 5776 5777 /******************************** FEM Support **********************************/ 5778 5779 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5780 { 5781 PetscInt depth; 5782 5783 PetscFunctionBegin; 5784 PetscCall(DMPlexGetDepth(plex, &depth)); 5785 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5786 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5787 PetscFunctionReturn(PETSC_SUCCESS); 5788 } 5789 5790 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5791 { 5792 PetscInt depth; 5793 5794 PetscFunctionBegin; 5795 PetscCall(DMPlexGetDepth(plex, &depth)); 5796 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5797 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5798 PetscFunctionReturn(PETSC_SUCCESS); 5799 } 5800 5801 /* 5802 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5803 representing a line in the section. 5804 */ 5805 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5806 { 5807 PetscObject obj; 5808 PetscClassId id; 5809 PetscFE fe = NULL; 5810 5811 PetscFunctionBeginHot; 5812 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5813 PetscCall(DMGetField(dm, field, NULL, &obj)); 5814 PetscCall(PetscObjectGetClassId(obj, &id)); 5815 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5816 5817 if (!fe) { 5818 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5819 /* An order k SEM disc has k-1 dofs on an edge */ 5820 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5821 *k = *k / *Nc + 1; 5822 } else { 5823 PetscInt dual_space_size, dim; 5824 PetscDualSpace dsp; 5825 5826 PetscCall(DMGetDimension(dm, &dim)); 5827 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5828 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5829 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5830 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5831 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5832 } 5833 PetscFunctionReturn(PETSC_SUCCESS); 5834 } 5835 5836 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5837 { 5838 PetscFunctionBeginHot; 5839 if (tensor) { 5840 *dof = PetscPowInt(k + 1, dim); 5841 } else { 5842 switch (dim) { 5843 case 1: 5844 *dof = k + 1; 5845 break; 5846 case 2: 5847 *dof = ((k + 1) * (k + 2)) / 2; 5848 break; 5849 case 3: 5850 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5851 break; 5852 default: 5853 *dof = 0; 5854 } 5855 } 5856 PetscFunctionReturn(PETSC_SUCCESS); 5857 } 5858 5859 /*@ 5860 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5861 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5862 section provided (or the section of the `DM`). 5863 5864 Input Parameters: 5865 + dm - The `DM` 5866 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5867 - section - The `PetscSection` to reorder, or `NULL` for the default section 5868 5869 Example: 5870 A typical interpolated single-quad mesh might order points as 5871 .vb 5872 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5873 5874 v4 -- e6 -- v3 5875 | | 5876 e7 c0 e8 5877 | | 5878 v1 -- e5 -- v2 5879 .ve 5880 5881 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5882 dofs in the order of points, e.g., 5883 .vb 5884 c0 -> [0,1,2,3] 5885 v1 -> [4] 5886 ... 5887 e5 -> [8, 9] 5888 .ve 5889 5890 which corresponds to the dofs 5891 .vb 5892 6 10 11 7 5893 13 2 3 15 5894 12 0 1 14 5895 4 8 9 5 5896 .ve 5897 5898 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5899 .vb 5900 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5901 .ve 5902 5903 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5904 .vb 5905 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5906 .ve 5907 5908 Level: developer 5909 5910 Notes: 5911 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5912 degree of the basis. 5913 5914 This is required to run with libCEED. 5915 5916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5917 @*/ 5918 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5919 { 5920 DMLabel label; 5921 PetscInt dim, depth = -1, eStart = -1, Nf; 5922 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5923 5924 PetscFunctionBegin; 5925 PetscCall(DMGetDimension(dm, &dim)); 5926 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5927 if (point < 0) { 5928 PetscInt sStart, sEnd; 5929 5930 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5931 point = sEnd - sStart ? sStart : point; 5932 } 5933 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5934 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5935 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5936 if (depth == 1) { 5937 eStart = point; 5938 } else if (depth == dim) { 5939 const PetscInt *cone; 5940 5941 PetscCall(DMPlexGetCone(dm, point, &cone)); 5942 if (dim == 2) eStart = cone[0]; 5943 else if (dim == 3) { 5944 const PetscInt *cone2; 5945 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5946 eStart = cone2[0]; 5947 } 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); 5948 } 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); 5949 5950 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5951 for (PetscInt d = 1; d <= dim; d++) { 5952 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5953 PetscInt *perm; 5954 5955 for (f = 0; f < Nf; ++f) { 5956 PetscInt dof; 5957 5958 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5959 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5960 if (!continuous && d < dim) continue; 5961 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5962 size += dof * Nc; 5963 } 5964 PetscCall(PetscMalloc1(size, &perm)); 5965 for (f = 0; f < Nf; ++f) { 5966 switch (d) { 5967 case 1: 5968 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5969 if (!continuous && d < dim) continue; 5970 /* 5971 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5972 We want [ vtx0; edge of length k-1; vtx1 ] 5973 */ 5974 if (continuous) { 5975 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5976 for (i = 0; i < k - 1; i++) 5977 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5978 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5979 foffset = offset; 5980 } else { 5981 PetscInt dof; 5982 5983 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5984 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5985 foffset = offset; 5986 } 5987 break; 5988 case 2: 5989 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5990 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5991 if (!continuous && d < dim) continue; 5992 /* The SEM order is 5993 5994 v_lb, {e_b}, v_rb, 5995 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5996 v_lt, reverse {e_t}, v_rt 5997 */ 5998 if (continuous) { 5999 const PetscInt of = 0; 6000 const PetscInt oeb = of + PetscSqr(k - 1); 6001 const PetscInt oer = oeb + (k - 1); 6002 const PetscInt oet = oer + (k - 1); 6003 const PetscInt oel = oet + (k - 1); 6004 const PetscInt ovlb = oel + (k - 1); 6005 const PetscInt ovrb = ovlb + 1; 6006 const PetscInt ovrt = ovrb + 1; 6007 const PetscInt ovlt = ovrt + 1; 6008 PetscInt o; 6009 6010 /* bottom */ 6011 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6012 for (o = oeb; o < oer; ++o) 6013 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6014 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6015 /* middle */ 6016 for (i = 0; i < k - 1; ++i) { 6017 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6018 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6019 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6020 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6021 } 6022 /* top */ 6023 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6024 for (o = oel - 1; o >= oet; --o) 6025 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6026 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6027 foffset = offset; 6028 } else { 6029 PetscInt dof; 6030 6031 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6032 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6033 foffset = offset; 6034 } 6035 break; 6036 case 3: 6037 /* The original hex closure is 6038 6039 {c, 6040 f_b, f_t, f_f, f_b, f_r, f_l, 6041 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6042 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6043 */ 6044 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6045 if (!continuous && d < dim) continue; 6046 /* The SEM order is 6047 Bottom Slice 6048 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6049 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6050 v_blb, {e_bb}, v_brb, 6051 6052 Middle Slice (j) 6053 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6054 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6055 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6056 6057 Top Slice 6058 v_tlf, {e_tf}, v_trf, 6059 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6060 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6061 */ 6062 if (continuous) { 6063 const PetscInt oc = 0; 6064 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6065 const PetscInt oft = ofb + PetscSqr(k - 1); 6066 const PetscInt off = oft + PetscSqr(k - 1); 6067 const PetscInt ofk = off + PetscSqr(k - 1); 6068 const PetscInt ofr = ofk + PetscSqr(k - 1); 6069 const PetscInt ofl = ofr + PetscSqr(k - 1); 6070 const PetscInt oebl = ofl + PetscSqr(k - 1); 6071 const PetscInt oebb = oebl + (k - 1); 6072 const PetscInt oebr = oebb + (k - 1); 6073 const PetscInt oebf = oebr + (k - 1); 6074 const PetscInt oetf = oebf + (k - 1); 6075 const PetscInt oetr = oetf + (k - 1); 6076 const PetscInt oetb = oetr + (k - 1); 6077 const PetscInt oetl = oetb + (k - 1); 6078 const PetscInt oerf = oetl + (k - 1); 6079 const PetscInt oelf = oerf + (k - 1); 6080 const PetscInt oelb = oelf + (k - 1); 6081 const PetscInt oerb = oelb + (k - 1); 6082 const PetscInt ovblf = oerb + (k - 1); 6083 const PetscInt ovblb = ovblf + 1; 6084 const PetscInt ovbrb = ovblb + 1; 6085 const PetscInt ovbrf = ovbrb + 1; 6086 const PetscInt ovtlf = ovbrf + 1; 6087 const PetscInt ovtrf = ovtlf + 1; 6088 const PetscInt ovtrb = ovtrf + 1; 6089 const PetscInt ovtlb = ovtrb + 1; 6090 PetscInt o, n; 6091 6092 /* Bottom Slice */ 6093 /* bottom */ 6094 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6095 for (o = oetf - 1; o >= oebf; --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] = ovbrf * Nc + c + foffset; 6098 /* middle */ 6099 for (i = 0; i < k - 1; ++i) { 6100 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6101 for (n = 0; n < k - 1; ++n) { 6102 o = ofb + n * (k - 1) + i; 6103 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6104 } 6105 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6106 } 6107 /* top */ 6108 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6109 for (o = oebb; o < oebr; ++o) 6110 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6111 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6112 6113 /* Middle Slice */ 6114 for (j = 0; j < k - 1; ++j) { 6115 /* bottom */ 6116 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6117 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6118 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6119 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6120 /* middle */ 6121 for (i = 0; i < k - 1; ++i) { 6122 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6123 for (n = 0; n < k - 1; ++n) 6124 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6126 } 6127 /* top */ 6128 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6129 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6131 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6132 } 6133 6134 /* Top Slice */ 6135 /* bottom */ 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6137 for (o = oetf; o < oetr; ++o) 6138 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6139 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6140 /* middle */ 6141 for (i = 0; i < k - 1; ++i) { 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6143 for (n = 0; n < k - 1; ++n) 6144 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6146 } 6147 /* top */ 6148 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6149 for (o = oetl - 1; o >= oetb; --o) 6150 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6151 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6152 6153 foffset = offset; 6154 } else { 6155 PetscInt dof; 6156 6157 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6158 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6159 foffset = offset; 6160 } 6161 break; 6162 default: 6163 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6164 } 6165 } 6166 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6167 /* Check permutation */ 6168 { 6169 PetscInt *check; 6170 6171 PetscCall(PetscMalloc1(size, &check)); 6172 for (i = 0; i < size; ++i) { 6173 check[i] = -1; 6174 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6175 } 6176 for (i = 0; i < size; ++i) check[perm[i]] = i; 6177 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6178 PetscCall(PetscFree(check)); 6179 } 6180 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6181 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6182 PetscInt *loc_perm; 6183 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6184 for (PetscInt i = 0; i < size; i++) { 6185 loc_perm[i] = perm[i]; 6186 loc_perm[size + i] = size + perm[i]; 6187 } 6188 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6189 } 6190 } 6191 PetscFunctionReturn(PETSC_SUCCESS); 6192 } 6193 6194 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6195 { 6196 PetscDS prob; 6197 PetscInt depth, Nf, h; 6198 DMLabel label; 6199 6200 PetscFunctionBeginHot; 6201 PetscCall(DMGetDS(dm, &prob)); 6202 Nf = prob->Nf; 6203 label = dm->depthLabel; 6204 *dspace = NULL; 6205 if (field < Nf) { 6206 PetscObject disc = prob->disc[field]; 6207 6208 if (disc->classid == PETSCFE_CLASSID) { 6209 PetscDualSpace dsp; 6210 6211 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6212 PetscCall(DMLabelGetNumValues(label, &depth)); 6213 PetscCall(DMLabelGetValue(label, point, &h)); 6214 h = depth - 1 - h; 6215 if (h) { 6216 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6217 } else { 6218 *dspace = dsp; 6219 } 6220 } 6221 } 6222 PetscFunctionReturn(PETSC_SUCCESS); 6223 } 6224 6225 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6226 { 6227 PetscScalar *array; 6228 const PetscScalar *vArray; 6229 const PetscInt *cone, *coneO; 6230 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6231 6232 PetscFunctionBeginHot; 6233 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6234 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6235 PetscCall(DMPlexGetCone(dm, point, &cone)); 6236 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6237 if (!values || !*values) { 6238 if ((point >= pStart) && (point < pEnd)) { 6239 PetscInt dof; 6240 6241 PetscCall(PetscSectionGetDof(section, point, &dof)); 6242 size += dof; 6243 } 6244 for (p = 0; p < numPoints; ++p) { 6245 const PetscInt cp = cone[p]; 6246 PetscInt dof; 6247 6248 if ((cp < pStart) || (cp >= pEnd)) continue; 6249 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6250 size += dof; 6251 } 6252 if (!values) { 6253 if (csize) *csize = size; 6254 PetscFunctionReturn(PETSC_SUCCESS); 6255 } 6256 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6257 } else { 6258 array = *values; 6259 } 6260 size = 0; 6261 PetscCall(VecGetArrayRead(v, &vArray)); 6262 if ((point >= pStart) && (point < pEnd)) { 6263 PetscInt dof, off, d; 6264 const PetscScalar *varr; 6265 6266 PetscCall(PetscSectionGetDof(section, point, &dof)); 6267 PetscCall(PetscSectionGetOffset(section, point, &off)); 6268 varr = PetscSafePointerPlusOffset(vArray, off); 6269 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6270 size += dof; 6271 } 6272 for (p = 0; p < numPoints; ++p) { 6273 const PetscInt cp = cone[p]; 6274 PetscInt o = coneO[p]; 6275 PetscInt dof, off, d; 6276 const PetscScalar *varr; 6277 6278 if ((cp < pStart) || (cp >= pEnd)) continue; 6279 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6280 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6281 varr = PetscSafePointerPlusOffset(vArray, off); 6282 if (o >= 0) { 6283 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6284 } else { 6285 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6286 } 6287 size += dof; 6288 } 6289 PetscCall(VecRestoreArrayRead(v, &vArray)); 6290 if (!*values) { 6291 if (csize) *csize = size; 6292 *values = array; 6293 } else { 6294 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6295 *csize = size; 6296 } 6297 PetscFunctionReturn(PETSC_SUCCESS); 6298 } 6299 6300 /* Compress out points not in the section */ 6301 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6302 { 6303 const PetscInt np = *numPoints; 6304 PetscInt pStart, pEnd, p, q; 6305 6306 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6307 for (p = 0, q = 0; p < np; ++p) { 6308 const PetscInt r = points[p * 2]; 6309 if ((r >= pStart) && (r < pEnd)) { 6310 points[q * 2] = r; 6311 points[q * 2 + 1] = points[p * 2 + 1]; 6312 ++q; 6313 } 6314 } 6315 *numPoints = q; 6316 return PETSC_SUCCESS; 6317 } 6318 6319 /* Compressed closure does not apply closure permutation */ 6320 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6321 { 6322 const PetscInt *cla = NULL; 6323 PetscInt np, *pts = NULL; 6324 6325 PetscFunctionBeginHot; 6326 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6327 if (!ornt && *clPoints) { 6328 PetscInt dof, off; 6329 6330 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6331 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6332 PetscCall(ISGetIndices(*clPoints, &cla)); 6333 np = dof / 2; 6334 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6335 } else { 6336 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6337 PetscCall(CompressPoints_Private(section, &np, pts)); 6338 } 6339 *numPoints = np; 6340 *points = pts; 6341 *clp = cla; 6342 PetscFunctionReturn(PETSC_SUCCESS); 6343 } 6344 6345 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6346 { 6347 PetscFunctionBeginHot; 6348 if (!*clPoints) { 6349 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6350 } else { 6351 PetscCall(ISRestoreIndices(*clPoints, clp)); 6352 } 6353 *numPoints = 0; 6354 *points = NULL; 6355 *clSec = NULL; 6356 *clPoints = NULL; 6357 *clp = NULL; 6358 PetscFunctionReturn(PETSC_SUCCESS); 6359 } 6360 6361 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6362 { 6363 PetscInt offset = 0, p; 6364 const PetscInt **perms = NULL; 6365 const PetscScalar **flips = NULL; 6366 6367 PetscFunctionBeginHot; 6368 *size = 0; 6369 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6370 for (p = 0; p < numPoints; p++) { 6371 const PetscInt point = points[2 * p]; 6372 const PetscInt *perm = perms ? perms[p] : NULL; 6373 const PetscScalar *flip = flips ? flips[p] : NULL; 6374 PetscInt dof, off, d; 6375 const PetscScalar *varr; 6376 6377 PetscCall(PetscSectionGetDof(section, point, &dof)); 6378 PetscCall(PetscSectionGetOffset(section, point, &off)); 6379 varr = PetscSafePointerPlusOffset(vArray, off); 6380 if (clperm) { 6381 if (perm) { 6382 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6383 } else { 6384 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6385 } 6386 if (flip) { 6387 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6388 } 6389 } else { 6390 if (perm) { 6391 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6392 } else { 6393 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6394 } 6395 if (flip) { 6396 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6397 } 6398 } 6399 offset += dof; 6400 } 6401 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6402 *size = offset; 6403 PetscFunctionReturn(PETSC_SUCCESS); 6404 } 6405 6406 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[]) 6407 { 6408 PetscInt offset = 0, f; 6409 6410 PetscFunctionBeginHot; 6411 *size = 0; 6412 for (f = 0; f < numFields; ++f) { 6413 PetscInt p; 6414 const PetscInt **perms = NULL; 6415 const PetscScalar **flips = NULL; 6416 6417 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6418 for (p = 0; p < numPoints; p++) { 6419 const PetscInt point = points[2 * p]; 6420 PetscInt fdof, foff, b; 6421 const PetscScalar *varr; 6422 const PetscInt *perm = perms ? perms[p] : NULL; 6423 const PetscScalar *flip = flips ? flips[p] : NULL; 6424 6425 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6426 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6427 varr = &vArray[foff]; 6428 if (clperm) { 6429 if (perm) { 6430 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6431 } else { 6432 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6433 } 6434 if (flip) { 6435 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6436 } 6437 } else { 6438 if (perm) { 6439 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6440 } else { 6441 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6442 } 6443 if (flip) { 6444 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6445 } 6446 } 6447 offset += fdof; 6448 } 6449 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6450 } 6451 *size = offset; 6452 PetscFunctionReturn(PETSC_SUCCESS); 6453 } 6454 6455 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6456 { 6457 PetscSection clSection; 6458 IS clPoints; 6459 PetscInt *points = NULL; 6460 const PetscInt *clp, *perm = NULL; 6461 PetscInt depth, numFields, numPoints, asize; 6462 6463 PetscFunctionBeginHot; 6464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6465 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6466 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6467 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6468 PetscCall(DMPlexGetDepth(dm, &depth)); 6469 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6470 if (depth == 1 && numFields < 2) { 6471 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6472 PetscFunctionReturn(PETSC_SUCCESS); 6473 } 6474 /* Get points */ 6475 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6476 /* Get sizes */ 6477 asize = 0; 6478 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6479 PetscInt dof; 6480 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6481 asize += dof; 6482 } 6483 if (values) { 6484 const PetscScalar *vArray; 6485 PetscInt size; 6486 6487 if (*values) { 6488 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); 6489 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6490 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6491 PetscCall(VecGetArrayRead(v, &vArray)); 6492 /* Get values */ 6493 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6494 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6495 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6496 /* Cleanup array */ 6497 PetscCall(VecRestoreArrayRead(v, &vArray)); 6498 } 6499 if (csize) *csize = asize; 6500 /* Cleanup points */ 6501 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6502 PetscFunctionReturn(PETSC_SUCCESS); 6503 } 6504 6505 /*@C 6506 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6507 6508 Not collective 6509 6510 Input Parameters: 6511 + dm - The `DM` 6512 . section - The section describing the layout in `v`, or `NULL` to use the default section 6513 . v - The local vector 6514 - point - The point in the `DM` 6515 6516 Input/Output Parameters: 6517 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6518 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6519 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6520 6521 Level: intermediate 6522 6523 Notes: 6524 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6525 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6526 assembly function, and a user may already have allocated storage for this operation. 6527 6528 A typical use could be 6529 .vb 6530 values = NULL; 6531 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6532 for (cl = 0; cl < clSize; ++cl) { 6533 <Compute on closure> 6534 } 6535 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6536 .ve 6537 or 6538 .vb 6539 PetscMalloc1(clMaxSize, &values); 6540 for (p = pStart; p < pEnd; ++p) { 6541 clSize = clMaxSize; 6542 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6543 for (cl = 0; cl < clSize; ++cl) { 6544 <Compute on closure> 6545 } 6546 } 6547 PetscFree(values); 6548 .ve 6549 6550 Fortran Notes: 6551 The `csize` argument is not present in the Fortran binding. 6552 6553 `values` must be declared with 6554 .vb 6555 PetscScalar,dimension(:),pointer :: values 6556 .ve 6557 and it will be allocated internally by PETSc to hold the values returned 6558 6559 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6560 @*/ 6561 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6562 { 6563 PetscFunctionBeginHot; 6564 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6565 PetscFunctionReturn(PETSC_SUCCESS); 6566 } 6567 6568 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6569 { 6570 DMLabel depthLabel; 6571 PetscSection clSection; 6572 IS clPoints; 6573 PetscScalar *array; 6574 const PetscScalar *vArray; 6575 PetscInt *points = NULL; 6576 const PetscInt *clp, *perm = NULL; 6577 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6578 6579 PetscFunctionBeginHot; 6580 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6581 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6582 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6583 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6584 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6585 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6586 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6587 if (mdepth == 1 && numFields < 2) { 6588 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6589 PetscFunctionReturn(PETSC_SUCCESS); 6590 } 6591 /* Get points */ 6592 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6593 for (clsize = 0, p = 0; p < Np; p++) { 6594 PetscInt dof; 6595 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6596 clsize += dof; 6597 } 6598 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6599 /* Filter points */ 6600 for (p = 0; p < numPoints * 2; p += 2) { 6601 PetscInt dep; 6602 6603 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6604 if (dep != depth) continue; 6605 points[Np * 2 + 0] = points[p]; 6606 points[Np * 2 + 1] = points[p + 1]; 6607 ++Np; 6608 } 6609 /* Get array */ 6610 if (!values || !*values) { 6611 PetscInt asize = 0, dof; 6612 6613 for (p = 0; p < Np * 2; p += 2) { 6614 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6615 asize += dof; 6616 } 6617 if (!values) { 6618 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6619 if (csize) *csize = asize; 6620 PetscFunctionReturn(PETSC_SUCCESS); 6621 } 6622 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6623 } else { 6624 array = *values; 6625 } 6626 PetscCall(VecGetArrayRead(v, &vArray)); 6627 /* Get values */ 6628 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6629 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6630 /* Cleanup points */ 6631 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6632 /* Cleanup array */ 6633 PetscCall(VecRestoreArrayRead(v, &vArray)); 6634 if (!*values) { 6635 if (csize) *csize = size; 6636 *values = array; 6637 } else { 6638 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6639 *csize = size; 6640 } 6641 PetscFunctionReturn(PETSC_SUCCESS); 6642 } 6643 6644 /*@C 6645 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6646 6647 Not collective 6648 6649 Input Parameters: 6650 + dm - The `DM` 6651 . section - The section describing the layout in `v`, or `NULL` to use the default section 6652 . v - The local vector 6653 . point - The point in the `DM` 6654 . csize - The number of values in the closure, or `NULL` 6655 - values - The array of values 6656 6657 Level: intermediate 6658 6659 Note: 6660 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6661 6662 Fortran Note: 6663 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6664 6665 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6666 @*/ 6667 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6668 { 6669 PetscInt size = 0; 6670 6671 PetscFunctionBegin; 6672 /* Should work without recalculating size */ 6673 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6674 *values = NULL; 6675 PetscFunctionReturn(PETSC_SUCCESS); 6676 } 6677 6678 static inline void add(PetscScalar *x, PetscScalar y) 6679 { 6680 *x += y; 6681 } 6682 static inline void insert(PetscScalar *x, PetscScalar y) 6683 { 6684 *x = y; 6685 } 6686 6687 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[]) 6688 { 6689 PetscInt cdof; /* The number of constraints on this point */ 6690 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6691 PetscScalar *a; 6692 PetscInt off, cind = 0, k; 6693 6694 PetscFunctionBegin; 6695 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6696 PetscCall(PetscSectionGetOffset(section, point, &off)); 6697 a = &array[off]; 6698 if (!cdof || setBC) { 6699 if (clperm) { 6700 if (perm) { 6701 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6702 } else { 6703 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6704 } 6705 } else { 6706 if (perm) { 6707 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6708 } else { 6709 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6710 } 6711 } 6712 } else { 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 ++cind; 6719 continue; 6720 } 6721 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6722 } 6723 } else { 6724 for (k = 0; k < dof; ++k) { 6725 if ((cind < cdof) && (k == cdofs[cind])) { 6726 ++cind; 6727 continue; 6728 } 6729 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6730 } 6731 } 6732 } else { 6733 if (perm) { 6734 for (k = 0; k < dof; ++k) { 6735 if ((cind < cdof) && (k == cdofs[cind])) { 6736 ++cind; 6737 continue; 6738 } 6739 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6740 } 6741 } else { 6742 for (k = 0; k < dof; ++k) { 6743 if ((cind < cdof) && (k == cdofs[cind])) { 6744 ++cind; 6745 continue; 6746 } 6747 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6748 } 6749 } 6750 } 6751 } 6752 PetscFunctionReturn(PETSC_SUCCESS); 6753 } 6754 6755 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[]) 6756 { 6757 PetscInt cdof; /* The number of constraints on this point */ 6758 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6759 PetscScalar *a; 6760 PetscInt off, cind = 0, k; 6761 6762 PetscFunctionBegin; 6763 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6764 PetscCall(PetscSectionGetOffset(section, point, &off)); 6765 a = &array[off]; 6766 if (cdof) { 6767 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6768 if (clperm) { 6769 if (perm) { 6770 for (k = 0; k < dof; ++k) { 6771 if ((cind < cdof) && (k == cdofs[cind])) { 6772 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6773 cind++; 6774 } 6775 } 6776 } else { 6777 for (k = 0; k < dof; ++k) { 6778 if ((cind < cdof) && (k == cdofs[cind])) { 6779 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6780 cind++; 6781 } 6782 } 6783 } 6784 } else { 6785 if (perm) { 6786 for (k = 0; k < dof; ++k) { 6787 if ((cind < cdof) && (k == cdofs[cind])) { 6788 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6789 cind++; 6790 } 6791 } 6792 } else { 6793 for (k = 0; k < dof; ++k) { 6794 if ((cind < cdof) && (k == cdofs[cind])) { 6795 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6796 cind++; 6797 } 6798 } 6799 } 6800 } 6801 } 6802 PetscFunctionReturn(PETSC_SUCCESS); 6803 } 6804 6805 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[]) 6806 { 6807 PetscScalar *a; 6808 PetscInt fdof, foff, fcdof, foffset = *offset; 6809 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6810 PetscInt cind = 0, b; 6811 6812 PetscFunctionBegin; 6813 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6814 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6815 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6816 a = &array[foff]; 6817 if (!fcdof || setBC) { 6818 if (clperm) { 6819 if (perm) { 6820 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6821 } else { 6822 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6823 } 6824 } else { 6825 if (perm) { 6826 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6827 } else { 6828 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6829 } 6830 } 6831 } else { 6832 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6833 if (clperm) { 6834 if (perm) { 6835 for (b = 0; b < fdof; b++) { 6836 if ((cind < fcdof) && (b == fcdofs[cind])) { 6837 ++cind; 6838 continue; 6839 } 6840 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6841 } 6842 } else { 6843 for (b = 0; b < fdof; b++) { 6844 if ((cind < fcdof) && (b == fcdofs[cind])) { 6845 ++cind; 6846 continue; 6847 } 6848 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6849 } 6850 } 6851 } else { 6852 if (perm) { 6853 for (b = 0; b < fdof; b++) { 6854 if ((cind < fcdof) && (b == fcdofs[cind])) { 6855 ++cind; 6856 continue; 6857 } 6858 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6859 } 6860 } else { 6861 for (b = 0; b < fdof; b++) { 6862 if ((cind < fcdof) && (b == fcdofs[cind])) { 6863 ++cind; 6864 continue; 6865 } 6866 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6867 } 6868 } 6869 } 6870 } 6871 *offset += fdof; 6872 PetscFunctionReturn(PETSC_SUCCESS); 6873 } 6874 6875 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[]) 6876 { 6877 PetscScalar *a; 6878 PetscInt fdof, foff, fcdof, foffset = *offset; 6879 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6880 PetscInt Nc, cind = 0, ncind = 0, b; 6881 PetscBool ncSet, fcSet; 6882 6883 PetscFunctionBegin; 6884 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6885 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6886 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6887 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6888 a = &array[foff]; 6889 if (fcdof) { 6890 /* We just override fcdof and fcdofs with Ncc and comps */ 6891 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6892 if (clperm) { 6893 if (perm) { 6894 if (comps) { 6895 for (b = 0; b < fdof; b++) { 6896 ncSet = fcSet = PETSC_FALSE; 6897 if (b % Nc == comps[ncind]) { 6898 ncind = (ncind + 1) % Ncc; 6899 ncSet = PETSC_TRUE; 6900 } 6901 if ((cind < fcdof) && (b == fcdofs[cind])) { 6902 ++cind; 6903 fcSet = PETSC_TRUE; 6904 } 6905 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6906 } 6907 } else { 6908 for (b = 0; b < fdof; b++) { 6909 if ((cind < fcdof) && (b == fcdofs[cind])) { 6910 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6911 ++cind; 6912 } 6913 } 6914 } 6915 } else { 6916 if (comps) { 6917 for (b = 0; b < fdof; b++) { 6918 ncSet = fcSet = PETSC_FALSE; 6919 if (b % Nc == comps[ncind]) { 6920 ncind = (ncind + 1) % Ncc; 6921 ncSet = PETSC_TRUE; 6922 } 6923 if ((cind < fcdof) && (b == fcdofs[cind])) { 6924 ++cind; 6925 fcSet = PETSC_TRUE; 6926 } 6927 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6928 } 6929 } else { 6930 for (b = 0; b < fdof; b++) { 6931 if ((cind < fcdof) && (b == fcdofs[cind])) { 6932 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6933 ++cind; 6934 } 6935 } 6936 } 6937 } 6938 } else { 6939 if (perm) { 6940 if (comps) { 6941 for (b = 0; b < fdof; b++) { 6942 ncSet = fcSet = PETSC_FALSE; 6943 if (b % Nc == comps[ncind]) { 6944 ncind = (ncind + 1) % Ncc; 6945 ncSet = PETSC_TRUE; 6946 } 6947 if ((cind < fcdof) && (b == fcdofs[cind])) { 6948 ++cind; 6949 fcSet = PETSC_TRUE; 6950 } 6951 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6952 } 6953 } else { 6954 for (b = 0; b < fdof; b++) { 6955 if ((cind < fcdof) && (b == fcdofs[cind])) { 6956 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6957 ++cind; 6958 } 6959 } 6960 } 6961 } else { 6962 if (comps) { 6963 for (b = 0; b < fdof; b++) { 6964 ncSet = fcSet = PETSC_FALSE; 6965 if (b % Nc == comps[ncind]) { 6966 ncind = (ncind + 1) % Ncc; 6967 ncSet = PETSC_TRUE; 6968 } 6969 if ((cind < fcdof) && (b == fcdofs[cind])) { 6970 ++cind; 6971 fcSet = PETSC_TRUE; 6972 } 6973 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6974 } 6975 } else { 6976 for (b = 0; b < fdof; b++) { 6977 if ((cind < fcdof) && (b == fcdofs[cind])) { 6978 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6979 ++cind; 6980 } 6981 } 6982 } 6983 } 6984 } 6985 } 6986 *offset += fdof; 6987 PetscFunctionReturn(PETSC_SUCCESS); 6988 } 6989 6990 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6991 { 6992 PetscScalar *array; 6993 const PetscInt *cone, *coneO; 6994 PetscInt pStart, pEnd, p, numPoints, off, dof; 6995 6996 PetscFunctionBeginHot; 6997 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6998 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6999 PetscCall(DMPlexGetCone(dm, point, &cone)); 7000 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7001 PetscCall(VecGetArray(v, &array)); 7002 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7003 const PetscInt cp = !p ? point : cone[p - 1]; 7004 const PetscInt o = !p ? 0 : coneO[p - 1]; 7005 7006 if ((cp < pStart) || (cp >= pEnd)) { 7007 dof = 0; 7008 continue; 7009 } 7010 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7011 /* ADD_VALUES */ 7012 { 7013 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7014 PetscScalar *a; 7015 PetscInt cdof, coff, cind = 0, k; 7016 7017 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7018 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7019 a = &array[coff]; 7020 if (!cdof) { 7021 if (o >= 0) { 7022 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7023 } else { 7024 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7025 } 7026 } else { 7027 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7028 if (o >= 0) { 7029 for (k = 0; k < dof; ++k) { 7030 if ((cind < cdof) && (k == cdofs[cind])) { 7031 ++cind; 7032 continue; 7033 } 7034 a[k] += values[off + k]; 7035 } 7036 } else { 7037 for (k = 0; k < dof; ++k) { 7038 if ((cind < cdof) && (k == cdofs[cind])) { 7039 ++cind; 7040 continue; 7041 } 7042 a[k] += values[off + dof - k - 1]; 7043 } 7044 } 7045 } 7046 } 7047 } 7048 PetscCall(VecRestoreArray(v, &array)); 7049 PetscFunctionReturn(PETSC_SUCCESS); 7050 } 7051 7052 /*@C 7053 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7054 7055 Not collective 7056 7057 Input Parameters: 7058 + dm - The `DM` 7059 . section - The section describing the layout in `v`, or `NULL` to use the default section 7060 . v - The local vector 7061 . point - The point in the `DM` 7062 . values - The array of values 7063 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7064 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7065 7066 Level: intermediate 7067 7068 Note: 7069 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7070 7071 Fortran Note: 7072 `values` must be declared with 7073 .vb 7074 PetscScalar,dimension(:),pointer :: values 7075 .ve 7076 7077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7078 @*/ 7079 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7080 { 7081 PetscSection clSection; 7082 IS clPoints; 7083 PetscScalar *array; 7084 PetscInt *points = NULL; 7085 const PetscInt *clp, *clperm = NULL; 7086 PetscInt depth, numFields, numPoints, p, clsize; 7087 7088 PetscFunctionBeginHot; 7089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7090 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7091 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7092 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7093 PetscCall(DMPlexGetDepth(dm, &depth)); 7094 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7095 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7096 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7097 PetscFunctionReturn(PETSC_SUCCESS); 7098 } 7099 /* Get points */ 7100 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7101 for (clsize = 0, p = 0; p < numPoints; p++) { 7102 PetscInt dof; 7103 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7104 clsize += dof; 7105 } 7106 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7107 /* Get array */ 7108 PetscCall(VecGetArray(v, &array)); 7109 /* Get values */ 7110 if (numFields > 0) { 7111 PetscInt offset = 0, f; 7112 for (f = 0; f < numFields; ++f) { 7113 const PetscInt **perms = NULL; 7114 const PetscScalar **flips = NULL; 7115 7116 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7117 switch (mode) { 7118 case INSERT_VALUES: 7119 for (p = 0; p < numPoints; p++) { 7120 const PetscInt point = points[2 * p]; 7121 const PetscInt *perm = perms ? perms[p] : NULL; 7122 const PetscScalar *flip = flips ? flips[p] : NULL; 7123 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7124 } 7125 break; 7126 case INSERT_ALL_VALUES: 7127 for (p = 0; p < numPoints; p++) { 7128 const PetscInt point = points[2 * p]; 7129 const PetscInt *perm = perms ? perms[p] : NULL; 7130 const PetscScalar *flip = flips ? flips[p] : NULL; 7131 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7132 } 7133 break; 7134 case INSERT_BC_VALUES: 7135 for (p = 0; p < numPoints; p++) { 7136 const PetscInt point = points[2 * p]; 7137 const PetscInt *perm = perms ? perms[p] : NULL; 7138 const PetscScalar *flip = flips ? flips[p] : NULL; 7139 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7140 } 7141 break; 7142 case ADD_VALUES: 7143 for (p = 0; p < numPoints; p++) { 7144 const PetscInt point = points[2 * p]; 7145 const PetscInt *perm = perms ? perms[p] : NULL; 7146 const PetscScalar *flip = flips ? flips[p] : NULL; 7147 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7148 } 7149 break; 7150 case ADD_ALL_VALUES: 7151 for (p = 0; p < numPoints; p++) { 7152 const PetscInt point = points[2 * p]; 7153 const PetscInt *perm = perms ? perms[p] : NULL; 7154 const PetscScalar *flip = flips ? flips[p] : NULL; 7155 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7156 } 7157 break; 7158 case ADD_BC_VALUES: 7159 for (p = 0; p < numPoints; p++) { 7160 const PetscInt point = points[2 * p]; 7161 const PetscInt *perm = perms ? perms[p] : NULL; 7162 const PetscScalar *flip = flips ? flips[p] : NULL; 7163 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7164 } 7165 break; 7166 default: 7167 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7168 } 7169 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7170 } 7171 } else { 7172 PetscInt dof, off; 7173 const PetscInt **perms = NULL; 7174 const PetscScalar **flips = NULL; 7175 7176 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7177 switch (mode) { 7178 case INSERT_VALUES: 7179 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7180 const PetscInt point = points[2 * p]; 7181 const PetscInt *perm = perms ? perms[p] : NULL; 7182 const PetscScalar *flip = flips ? flips[p] : NULL; 7183 PetscCall(PetscSectionGetDof(section, point, &dof)); 7184 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7185 } 7186 break; 7187 case INSERT_ALL_VALUES: 7188 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7189 const PetscInt point = points[2 * p]; 7190 const PetscInt *perm = perms ? perms[p] : NULL; 7191 const PetscScalar *flip = flips ? flips[p] : NULL; 7192 PetscCall(PetscSectionGetDof(section, point, &dof)); 7193 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7194 } 7195 break; 7196 case INSERT_BC_VALUES: 7197 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7198 const PetscInt point = points[2 * p]; 7199 const PetscInt *perm = perms ? perms[p] : NULL; 7200 const PetscScalar *flip = flips ? flips[p] : NULL; 7201 PetscCall(PetscSectionGetDof(section, point, &dof)); 7202 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7203 } 7204 break; 7205 case ADD_VALUES: 7206 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7207 const PetscInt point = points[2 * p]; 7208 const PetscInt *perm = perms ? perms[p] : NULL; 7209 const PetscScalar *flip = flips ? flips[p] : NULL; 7210 PetscCall(PetscSectionGetDof(section, point, &dof)); 7211 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7212 } 7213 break; 7214 case ADD_ALL_VALUES: 7215 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7216 const PetscInt point = points[2 * p]; 7217 const PetscInt *perm = perms ? perms[p] : NULL; 7218 const PetscScalar *flip = flips ? flips[p] : NULL; 7219 PetscCall(PetscSectionGetDof(section, point, &dof)); 7220 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7221 } 7222 break; 7223 case ADD_BC_VALUES: 7224 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7225 const PetscInt point = points[2 * p]; 7226 const PetscInt *perm = perms ? perms[p] : NULL; 7227 const PetscScalar *flip = flips ? flips[p] : NULL; 7228 PetscCall(PetscSectionGetDof(section, point, &dof)); 7229 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7230 } 7231 break; 7232 default: 7233 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7234 } 7235 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7236 } 7237 /* Cleanup points */ 7238 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7239 /* Cleanup array */ 7240 PetscCall(VecRestoreArray(v, &array)); 7241 PetscFunctionReturn(PETSC_SUCCESS); 7242 } 7243 7244 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7245 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7246 { 7247 PetscFunctionBegin; 7248 *contains = PETSC_TRUE; 7249 if (label) { 7250 PetscInt fdof; 7251 7252 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7253 if (!*contains) { 7254 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7255 *offset += fdof; 7256 PetscFunctionReturn(PETSC_SUCCESS); 7257 } 7258 } 7259 PetscFunctionReturn(PETSC_SUCCESS); 7260 } 7261 7262 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7263 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) 7264 { 7265 PetscSection clSection; 7266 IS clPoints; 7267 PetscScalar *array; 7268 PetscInt *points = NULL; 7269 const PetscInt *clp; 7270 PetscInt numFields, numPoints, p; 7271 PetscInt offset = 0, f; 7272 7273 PetscFunctionBeginHot; 7274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7275 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7276 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7277 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7278 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7279 /* Get points */ 7280 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7281 /* Get array */ 7282 PetscCall(VecGetArray(v, &array)); 7283 /* Get values */ 7284 for (f = 0; f < numFields; ++f) { 7285 const PetscInt **perms = NULL; 7286 const PetscScalar **flips = NULL; 7287 PetscBool contains; 7288 7289 if (!fieldActive[f]) { 7290 for (p = 0; p < numPoints * 2; p += 2) { 7291 PetscInt fdof; 7292 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7293 offset += fdof; 7294 } 7295 continue; 7296 } 7297 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7298 switch (mode) { 7299 case INSERT_VALUES: 7300 for (p = 0; p < numPoints; p++) { 7301 const PetscInt point = points[2 * p]; 7302 const PetscInt *perm = perms ? perms[p] : NULL; 7303 const PetscScalar *flip = flips ? flips[p] : NULL; 7304 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7305 if (!contains) continue; 7306 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7307 } 7308 break; 7309 case INSERT_ALL_VALUES: 7310 for (p = 0; p < numPoints; p++) { 7311 const PetscInt point = points[2 * p]; 7312 const PetscInt *perm = perms ? perms[p] : NULL; 7313 const PetscScalar *flip = flips ? flips[p] : NULL; 7314 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7315 if (!contains) continue; 7316 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7317 } 7318 break; 7319 case INSERT_BC_VALUES: 7320 for (p = 0; p < numPoints; p++) { 7321 const PetscInt point = points[2 * p]; 7322 const PetscInt *perm = perms ? perms[p] : NULL; 7323 const PetscScalar *flip = flips ? flips[p] : NULL; 7324 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7325 if (!contains) continue; 7326 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7327 } 7328 break; 7329 case ADD_VALUES: 7330 for (p = 0; p < numPoints; p++) { 7331 const PetscInt point = points[2 * p]; 7332 const PetscInt *perm = perms ? perms[p] : NULL; 7333 const PetscScalar *flip = flips ? flips[p] : NULL; 7334 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7335 if (!contains) continue; 7336 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7337 } 7338 break; 7339 case ADD_ALL_VALUES: 7340 for (p = 0; p < numPoints; p++) { 7341 const PetscInt point = points[2 * p]; 7342 const PetscInt *perm = perms ? perms[p] : NULL; 7343 const PetscScalar *flip = flips ? flips[p] : NULL; 7344 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7345 if (!contains) continue; 7346 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7347 } 7348 break; 7349 default: 7350 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7351 } 7352 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7353 } 7354 /* Cleanup points */ 7355 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7356 /* Cleanup array */ 7357 PetscCall(VecRestoreArray(v, &array)); 7358 PetscFunctionReturn(PETSC_SUCCESS); 7359 } 7360 7361 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7362 { 7363 PetscMPIInt rank; 7364 PetscInt i, j; 7365 7366 PetscFunctionBegin; 7367 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7368 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7369 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7370 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7371 numCIndices = numCIndices ? numCIndices : numRIndices; 7372 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7373 for (i = 0; i < numRIndices; i++) { 7374 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7375 for (j = 0; j < numCIndices; j++) { 7376 #if defined(PETSC_USE_COMPLEX) 7377 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7378 #else 7379 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7380 #endif 7381 } 7382 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7383 } 7384 PetscFunctionReturn(PETSC_SUCCESS); 7385 } 7386 7387 /* 7388 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7389 7390 Input Parameters: 7391 + section - The section for this data layout 7392 . islocal - Is the section (and thus indices being requested) local or global? 7393 . point - The point contributing dofs with these indices 7394 . off - The global offset of this point 7395 . loff - The local offset of each field 7396 . setBC - The flag determining whether to include indices of boundary values 7397 . perm - A permutation of the dofs on this point, or NULL 7398 - indperm - A permutation of the entire indices array, or NULL 7399 7400 Output Parameter: 7401 . indices - Indices for dofs on this point 7402 7403 Level: developer 7404 7405 Note: The indices could be local or global, depending on the value of 'off'. 7406 */ 7407 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7408 { 7409 PetscInt dof; /* The number of unknowns on this point */ 7410 PetscInt cdof; /* The number of constraints on this point */ 7411 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7412 PetscInt cind = 0, k; 7413 7414 PetscFunctionBegin; 7415 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7416 PetscCall(PetscSectionGetDof(section, point, &dof)); 7417 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7418 if (!cdof || setBC) { 7419 for (k = 0; k < dof; ++k) { 7420 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7421 const PetscInt ind = indperm ? indperm[preind] : preind; 7422 7423 indices[ind] = off + k; 7424 } 7425 } else { 7426 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7427 for (k = 0; k < dof; ++k) { 7428 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7429 const PetscInt ind = indperm ? indperm[preind] : preind; 7430 7431 if ((cind < cdof) && (k == cdofs[cind])) { 7432 /* Insert check for returning constrained indices */ 7433 indices[ind] = -(off + k + 1); 7434 ++cind; 7435 } else { 7436 indices[ind] = off + k - (islocal ? 0 : cind); 7437 } 7438 } 7439 } 7440 *loff += dof; 7441 PetscFunctionReturn(PETSC_SUCCESS); 7442 } 7443 7444 /* 7445 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7446 7447 Input Parameters: 7448 + section - a section (global or local) 7449 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7450 . point - point within section 7451 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7452 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7453 . setBC - identify constrained (boundary condition) points via involution. 7454 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7455 . permsoff - offset 7456 - indperm - index permutation 7457 7458 Output Parameter: 7459 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7460 . indices - array to hold indices (as defined by section) of each dof associated with point 7461 7462 Notes: 7463 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7464 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7465 in the local vector. 7466 7467 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7468 significant). It is invalid to call with a global section and setBC=true. 7469 7470 Developer Note: 7471 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7472 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7473 offset could be obtained from the section instead of passing it explicitly as we do now. 7474 7475 Example: 7476 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7477 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7478 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7479 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. 7480 7481 Level: developer 7482 */ 7483 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[]) 7484 { 7485 PetscInt numFields, foff, f; 7486 7487 PetscFunctionBegin; 7488 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7489 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7490 for (f = 0, foff = 0; f < numFields; ++f) { 7491 PetscInt fdof, cfdof; 7492 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7493 PetscInt cind = 0, b; 7494 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7495 7496 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7497 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7498 if (!cfdof || setBC) { 7499 for (b = 0; b < fdof; ++b) { 7500 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7501 const PetscInt ind = indperm ? indperm[preind] : preind; 7502 7503 indices[ind] = off + foff + b; 7504 } 7505 } else { 7506 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7507 for (b = 0; b < fdof; ++b) { 7508 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7509 const PetscInt ind = indperm ? indperm[preind] : preind; 7510 7511 if ((cind < cfdof) && (b == fcdofs[cind])) { 7512 indices[ind] = -(off + foff + b + 1); 7513 ++cind; 7514 } else { 7515 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7516 } 7517 } 7518 } 7519 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7520 foffs[f] += fdof; 7521 } 7522 PetscFunctionReturn(PETSC_SUCCESS); 7523 } 7524 7525 /* 7526 This version believes the globalSection offsets for each field, rather than just the point offset 7527 7528 . foffs - The offset into 'indices' for each field, since it is segregated by field 7529 7530 Notes: 7531 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7532 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7533 */ 7534 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7535 { 7536 PetscInt numFields, foff, f; 7537 7538 PetscFunctionBegin; 7539 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7540 for (f = 0; f < numFields; ++f) { 7541 PetscInt fdof, cfdof; 7542 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7543 PetscInt cind = 0, b; 7544 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7545 7546 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7547 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7548 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7549 if (!cfdof) { 7550 for (b = 0; b < fdof; ++b) { 7551 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7552 const PetscInt ind = indperm ? indperm[preind] : preind; 7553 7554 indices[ind] = foff + b; 7555 } 7556 } else { 7557 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7558 for (b = 0; b < fdof; ++b) { 7559 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7560 const PetscInt ind = indperm ? indperm[preind] : preind; 7561 7562 if ((cind < cfdof) && (b == fcdofs[cind])) { 7563 indices[ind] = -(foff + b + 1); 7564 ++cind; 7565 } else { 7566 indices[ind] = foff + b - cind; 7567 } 7568 } 7569 } 7570 foffs[f] += fdof; 7571 } 7572 PetscFunctionReturn(PETSC_SUCCESS); 7573 } 7574 7575 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7576 { 7577 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7578 7579 PetscFunctionBegin; 7580 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7581 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7582 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7583 for (PetscInt p = 0; p < nPoints; p++) { 7584 PetscInt b = pnts[2 * p]; 7585 PetscInt bSecDof = 0, bOff; 7586 PetscInt cSecDof = 0; 7587 PetscSection indices_section; 7588 7589 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7590 if (!bSecDof) continue; 7591 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7592 indices_section = cSecDof > 0 ? cSec : section; 7593 if (numFields) { 7594 PetscInt fStart[32], fEnd[32]; 7595 7596 fStart[0] = 0; 7597 fEnd[0] = 0; 7598 for (PetscInt f = 0; f < numFields; f++) { 7599 PetscInt fDof = 0; 7600 7601 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7602 fStart[f + 1] = fStart[f] + fDof; 7603 fEnd[f + 1] = fStart[f + 1]; 7604 } 7605 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7606 // only apply permutations on one side 7607 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7608 for (PetscInt f = 0; f < numFields; f++) { 7609 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7610 } 7611 } else { 7612 PetscInt bEnd = 0; 7613 7614 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7615 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7616 7617 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7618 } 7619 } 7620 PetscFunctionReturn(PETSC_SUCCESS); 7621 } 7622 7623 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[]) 7624 { 7625 Mat cMat; 7626 PetscSection aSec, cSec; 7627 IS aIS; 7628 PetscInt aStart = -1, aEnd = -1; 7629 PetscInt sStart = -1, sEnd = -1; 7630 PetscInt cStart = -1, cEnd = -1; 7631 const PetscInt *anchors; 7632 PetscInt numFields, p; 7633 PetscInt newNumPoints = 0, newNumIndices = 0; 7634 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7635 PetscInt oldOffsets[32]; 7636 PetscInt newOffsets[32]; 7637 PetscInt oldOffsetsCopy[32]; 7638 PetscInt newOffsetsCopy[32]; 7639 PetscScalar *modMat = NULL; 7640 PetscBool anyConstrained = PETSC_FALSE; 7641 7642 PetscFunctionBegin; 7643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7644 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7645 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7646 7647 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7648 /* if there are point-to-point constraints */ 7649 if (aSec) { 7650 PetscCall(PetscArrayzero(newOffsets, 32)); 7651 PetscCall(PetscArrayzero(oldOffsets, 32)); 7652 PetscCall(ISGetIndices(aIS, &anchors)); 7653 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7654 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7655 /* figure out how many points are going to be in the new element matrix 7656 * (we allow double counting, because it's all just going to be summed 7657 * into the global matrix anyway) */ 7658 for (p = 0; p < 2 * numPoints; p += 2) { 7659 PetscInt b = points[p]; 7660 PetscInt bDof = 0, bSecDof = 0; 7661 7662 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7663 if (!bSecDof) continue; 7664 7665 for (PetscInt f = 0; f < numFields; f++) { 7666 PetscInt fDof = 0; 7667 7668 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7669 oldOffsets[f + 1] += fDof; 7670 } 7671 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7672 if (bDof) { 7673 /* this point is constrained */ 7674 /* it is going to be replaced by its anchors */ 7675 PetscInt bOff, q; 7676 7677 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7678 for (q = 0; q < bDof; q++) { 7679 PetscInt a = anchors[bOff + q]; 7680 PetscInt aDof = 0; 7681 7682 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7683 if (aDof) { 7684 anyConstrained = PETSC_TRUE; 7685 newNumPoints += 1; 7686 } 7687 newNumIndices += aDof; 7688 for (PetscInt f = 0; f < numFields; ++f) { 7689 PetscInt fDof = 0; 7690 7691 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7692 newOffsets[f + 1] += fDof; 7693 } 7694 } 7695 } else { 7696 /* this point is not constrained */ 7697 newNumPoints++; 7698 newNumIndices += bSecDof; 7699 for (PetscInt f = 0; f < numFields; ++f) { 7700 PetscInt fDof; 7701 7702 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7703 newOffsets[f + 1] += fDof; 7704 } 7705 } 7706 } 7707 } 7708 if (!anyConstrained) { 7709 if (outNumPoints) *outNumPoints = 0; 7710 if (outNumIndices) *outNumIndices = 0; 7711 if (outPoints) *outPoints = NULL; 7712 if (outMat) *outMat = NULL; 7713 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7714 PetscFunctionReturn(PETSC_SUCCESS); 7715 } 7716 7717 if (outNumPoints) *outNumPoints = newNumPoints; 7718 if (outNumIndices) *outNumIndices = newNumIndices; 7719 7720 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7721 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7722 7723 if (!outPoints && !outMat) { 7724 if (offsets) { 7725 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7726 } 7727 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7728 PetscFunctionReturn(PETSC_SUCCESS); 7729 } 7730 7731 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7732 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7733 7734 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7735 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7736 7737 /* output arrays */ 7738 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7739 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7740 7741 // get the new Points 7742 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7743 PetscInt b = points[2 * p]; 7744 PetscInt bDof = 0, bSecDof = 0, bOff; 7745 7746 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7747 if (!bSecDof) continue; 7748 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7749 if (bDof) { 7750 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7751 for (PetscInt q = 0; q < bDof; q++) { 7752 PetscInt a = anchors[bOff + q], aDof = 0; 7753 7754 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7755 if (aDof) { 7756 newPoints[2 * newP] = a; 7757 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7758 newP++; 7759 } 7760 } 7761 } else { 7762 newPoints[2 * newP] = b; 7763 newPoints[2 * newP + 1] = points[2 * p + 1]; 7764 newP++; 7765 } 7766 } 7767 7768 if (outMat) { 7769 PetscScalar *tmpMat; 7770 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7771 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7772 7773 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7774 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7775 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7776 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7777 7778 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7779 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7780 7781 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7782 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7783 7784 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7785 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7786 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7787 // for each field, insert the anchor modification into modMat 7788 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7789 PetscInt fStart = oldOffsets[f]; 7790 PetscInt fNewStart = newOffsets[f]; 7791 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7792 PetscInt b = points[2 * p]; 7793 PetscInt bDof = 0, bSecDof = 0, bOff; 7794 7795 if (b >= sStart && b < sEnd) { 7796 if (numFields) { 7797 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7798 } else { 7799 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7800 } 7801 } 7802 if (!bSecDof) continue; 7803 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7804 if (bDof) { 7805 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7806 for (PetscInt q = 0; q < bDof; q++, newP++) { 7807 PetscInt a = anchors[bOff + q], aDof = 0; 7808 7809 if (a >= sStart && a < sEnd) { 7810 if (numFields) { 7811 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7812 } else { 7813 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7814 } 7815 } 7816 if (aDof) { 7817 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7818 for (PetscInt d = 0; d < bSecDof; d++) { 7819 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7820 } 7821 } 7822 oNew += aDof; 7823 } 7824 } else { 7825 // Insert the identity matrix in this block 7826 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7827 oNew += bSecDof; 7828 newP++; 7829 } 7830 o += bSecDof; 7831 } 7832 } 7833 7834 *outMat = modMat; 7835 7836 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7837 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7838 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7839 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7840 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7841 } 7842 PetscCall(ISRestoreIndices(aIS, &anchors)); 7843 7844 /* output */ 7845 if (outPoints) { 7846 *outPoints = newPoints; 7847 } else { 7848 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7849 } 7850 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7851 PetscFunctionReturn(PETSC_SUCCESS); 7852 } 7853 7854 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) 7855 { 7856 PetscScalar *modMat = NULL; 7857 PetscInt newNumIndices = -1; 7858 7859 PetscFunctionBegin; 7860 /* 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. 7861 modMat is that matrix C */ 7862 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7863 if (outNumIndices) *outNumIndices = newNumIndices; 7864 if (modMat) { 7865 const PetscScalar *newValues = values; 7866 7867 if (multiplyRight) { 7868 PetscScalar *newNewValues = NULL; 7869 PetscBLASInt M = newNumIndices; 7870 PetscBLASInt N = numRows; 7871 PetscBLASInt K = numIndices; 7872 PetscScalar a = 1.0, b = 0.0; 7873 7874 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); 7875 7876 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7877 // row-major to column-major conversion, right multiplication becomes left multiplication 7878 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7879 7880 numCols = newNumIndices; 7881 newValues = newNewValues; 7882 } 7883 7884 if (multiplyLeft) { 7885 PetscScalar *newNewValues = NULL; 7886 PetscBLASInt M = numCols; 7887 PetscBLASInt N = newNumIndices; 7888 PetscBLASInt K = numIndices; 7889 PetscScalar a = 1.0, b = 0.0; 7890 7891 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); 7892 7893 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7894 // row-major to column-major conversion, left multiplication becomes right multiplication 7895 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7896 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7897 newValues = newNewValues; 7898 } 7899 *outValues = (PetscScalar *)newValues; 7900 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7901 } 7902 PetscFunctionReturn(PETSC_SUCCESS); 7903 } 7904 7905 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) 7906 { 7907 PetscFunctionBegin; 7908 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7909 PetscFunctionReturn(PETSC_SUCCESS); 7910 } 7911 7912 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7913 { 7914 /* Closure ordering */ 7915 PetscSection clSection; 7916 IS clPoints; 7917 const PetscInt *clp; 7918 PetscInt *points; 7919 PetscInt Ncl, Ni = 0; 7920 7921 PetscFunctionBeginHot; 7922 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7923 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7924 PetscInt dof; 7925 7926 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7927 Ni += dof; 7928 } 7929 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7930 *closureSize = Ni; 7931 PetscFunctionReturn(PETSC_SUCCESS); 7932 } 7933 7934 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) 7935 { 7936 /* Closure ordering */ 7937 PetscSection clSection; 7938 IS clPoints; 7939 const PetscInt *clp; 7940 PetscInt *points; 7941 const PetscInt *clperm = NULL; 7942 /* Dof permutation and sign flips */ 7943 const PetscInt **perms[32] = {NULL}; 7944 const PetscScalar **flips[32] = {NULL}; 7945 PetscScalar *valCopy = NULL; 7946 /* Hanging node constraints */ 7947 PetscInt *pointsC = NULL; 7948 PetscScalar *valuesC = NULL; 7949 PetscInt NclC, NiC; 7950 7951 PetscInt *idx; 7952 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7953 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7954 PetscInt idxStart, idxEnd; 7955 PetscInt nRows, nCols; 7956 7957 PetscFunctionBeginHot; 7958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7959 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7960 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7961 PetscAssertPointer(numRows, 6); 7962 PetscAssertPointer(numCols, 7); 7963 if (indices) PetscAssertPointer(indices, 8); 7964 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7965 if (values) PetscAssertPointer(values, 10); 7966 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7967 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7968 PetscCall(PetscArrayzero(offsets, 32)); 7969 /* 1) Get points in closure */ 7970 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7971 if (useClPerm) { 7972 PetscInt depth, clsize; 7973 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7974 for (clsize = 0, p = 0; p < Ncl; p++) { 7975 PetscInt dof; 7976 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7977 clsize += dof; 7978 } 7979 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7980 } 7981 /* 2) Get number of indices on these points and field offsets from section */ 7982 for (p = 0; p < Ncl * 2; p += 2) { 7983 PetscInt dof, fdof; 7984 7985 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7986 for (f = 0; f < Nf; ++f) { 7987 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7988 offsets[f + 1] += fdof; 7989 } 7990 Ni += dof; 7991 } 7992 if (*numRows == -1) *numRows = Ni; 7993 if (*numCols == -1) *numCols = Ni; 7994 nRows = *numRows; 7995 nCols = *numCols; 7996 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7997 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7998 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7999 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8000 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8001 for (f = 0; f < PetscMax(1, Nf); ++f) { 8002 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8003 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8004 /* may need to apply sign changes to the element matrix */ 8005 if (values && flips[f]) { 8006 PetscInt foffset = offsets[f]; 8007 8008 for (p = 0; p < Ncl; ++p) { 8009 PetscInt pnt = points[2 * p], fdof; 8010 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8011 8012 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8013 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8014 if (flip) { 8015 PetscInt i, j, k; 8016 8017 if (!valCopy) { 8018 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8019 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8020 *values = valCopy; 8021 } 8022 for (i = 0; i < fdof; ++i) { 8023 PetscScalar fval = flip[i]; 8024 8025 if (multiplyRight) { 8026 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8027 } 8028 if (multiplyLeft) { 8029 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8030 } 8031 } 8032 } 8033 foffset += fdof; 8034 } 8035 } 8036 } 8037 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8038 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8039 if (NclC) { 8040 if (multiplyRight) { *numCols = nCols = NiC; } 8041 if (multiplyLeft) { *numRows = nRows = NiC; } 8042 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8043 for (f = 0; f < PetscMax(1, Nf); ++f) { 8044 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8045 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8046 } 8047 for (f = 0; f < PetscMax(1, Nf); ++f) { 8048 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8049 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8050 } 8051 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8052 Ncl = NclC; 8053 Ni = NiC; 8054 points = pointsC; 8055 if (values) *values = valuesC; 8056 } 8057 /* 5) Calculate indices */ 8058 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8059 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8060 if (Nf) { 8061 PetscInt idxOff; 8062 PetscBool useFieldOffsets; 8063 8064 if (outOffsets) { 8065 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8066 } 8067 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8068 if (useFieldOffsets) { 8069 for (p = 0; p < Ncl; ++p) { 8070 const PetscInt pnt = points[p * 2]; 8071 8072 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8073 } 8074 } else { 8075 for (p = 0; p < Ncl; ++p) { 8076 const PetscInt pnt = points[p * 2]; 8077 8078 if (pnt < idxStart || pnt >= idxEnd) continue; 8079 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8080 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8081 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8082 * global section. */ 8083 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8084 } 8085 } 8086 } else { 8087 PetscInt off = 0, idxOff; 8088 8089 for (p = 0; p < Ncl; ++p) { 8090 const PetscInt pnt = points[p * 2]; 8091 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8092 8093 if (pnt < idxStart || pnt >= idxEnd) continue; 8094 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8095 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8096 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8097 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8098 } 8099 } 8100 /* 6) Cleanup */ 8101 for (f = 0; f < PetscMax(1, Nf); ++f) { 8102 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8103 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8104 } 8105 if (NclC) { 8106 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8107 } else { 8108 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8109 } 8110 8111 if (indices) *indices = idx; 8112 PetscFunctionReturn(PETSC_SUCCESS); 8113 } 8114 8115 /*@C 8116 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8117 8118 Not collective 8119 8120 Input Parameters: 8121 + dm - The `DM` 8122 . section - The `PetscSection` describing the points (a local section) 8123 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8124 . point - The point defining the closure 8125 - useClPerm - Use the closure point permutation if available 8126 8127 Output Parameters: 8128 + numIndices - The number of dof indices in the closure of point with the input sections 8129 . indices - The dof indices 8130 . outOffsets - Array to write the field offsets into, or `NULL` 8131 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8132 8133 Level: advanced 8134 8135 Notes: 8136 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8137 8138 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8139 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8140 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8141 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8142 indices (with the above semantics) are implied. 8143 8144 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8145 `PetscSection`, `DMGetGlobalSection()` 8146 @*/ 8147 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8148 { 8149 PetscInt numRows = -1, numCols = -1; 8150 8151 PetscFunctionBeginHot; 8152 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8153 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8154 *numIndices = numRows; 8155 PetscFunctionReturn(PETSC_SUCCESS); 8156 } 8157 8158 /*@C 8159 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8160 8161 Not collective 8162 8163 Input Parameters: 8164 + dm - The `DM` 8165 . section - The `PetscSection` describing the points (a local section) 8166 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8167 . point - The point defining the closure 8168 - useClPerm - Use the closure point permutation if available 8169 8170 Output Parameters: 8171 + numIndices - The number of dof indices in the closure of point with the input sections 8172 . indices - The dof indices 8173 . outOffsets - Array to write the field offsets into, or `NULL` 8174 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8175 8176 Level: advanced 8177 8178 Notes: 8179 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8180 8181 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8182 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8183 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8184 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8185 indices (with the above semantics) are implied. 8186 8187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8188 @*/ 8189 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8190 { 8191 PetscFunctionBegin; 8192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8193 PetscAssertPointer(indices, 7); 8194 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8195 PetscFunctionReturn(PETSC_SUCCESS); 8196 } 8197 8198 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8199 { 8200 DM_Plex *mesh = (DM_Plex *)dm->data; 8201 PetscInt *indices; 8202 PetscInt numIndices; 8203 const PetscScalar *valuesOrig = values; 8204 PetscErrorCode ierr; 8205 8206 PetscFunctionBegin; 8207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8208 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8209 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8210 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8211 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8212 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8213 8214 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8215 8216 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8217 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8218 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8219 if (ierr) { 8220 PetscMPIInt rank; 8221 8222 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8223 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8224 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8225 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8226 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8227 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8228 } 8229 if (mesh->printFEM > 1) { 8230 PetscInt i; 8231 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8232 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8233 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8234 } 8235 8236 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8237 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8238 PetscFunctionReturn(PETSC_SUCCESS); 8239 } 8240 8241 /*@C 8242 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8243 8244 Not collective 8245 8246 Input Parameters: 8247 + dm - The `DM` 8248 . section - The section describing the layout in `v`, or `NULL` to use the default section 8249 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8250 . A - The matrix 8251 . point - The point in the `DM` 8252 . values - The array of values 8253 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8254 8255 Level: intermediate 8256 8257 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8258 @*/ 8259 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8260 { 8261 PetscFunctionBegin; 8262 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8263 PetscFunctionReturn(PETSC_SUCCESS); 8264 } 8265 8266 /*@C 8267 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8268 8269 Not collective 8270 8271 Input Parameters: 8272 + dmRow - The `DM` for the row fields 8273 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8274 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8275 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8276 . dmCol - The `DM` for the column fields 8277 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8278 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8279 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8280 . A - The matrix 8281 . point - The point in the `DM` 8282 . values - The array of values 8283 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8284 8285 Level: intermediate 8286 8287 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8288 @*/ 8289 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) 8290 { 8291 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8292 PetscInt *indicesRow, *indicesCol; 8293 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8294 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8295 8296 PetscErrorCode ierr; 8297 8298 PetscFunctionBegin; 8299 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8300 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8301 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8302 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8303 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8304 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8305 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8306 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8307 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8308 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8309 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8310 8311 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8312 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8313 valuesV1 = valuesV0; 8314 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8315 valuesV2 = valuesV1; 8316 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8317 8318 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8319 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8320 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8321 if (ierr) { 8322 PetscMPIInt rank; 8323 8324 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8325 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8326 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8327 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8328 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8329 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8330 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8331 } 8332 8333 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8334 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8335 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8336 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8337 PetscFunctionReturn(PETSC_SUCCESS); 8338 } 8339 8340 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8341 { 8342 DM_Plex *mesh = (DM_Plex *)dmf->data; 8343 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8344 PetscInt *cpoints = NULL; 8345 PetscInt *findices, *cindices; 8346 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8347 PetscInt foffsets[32], coffsets[32]; 8348 DMPolytopeType ct; 8349 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8350 PetscErrorCode ierr; 8351 8352 PetscFunctionBegin; 8353 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8354 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8355 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8356 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8357 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8358 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8359 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8360 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8361 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8362 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8363 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8364 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8365 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8366 PetscCall(PetscArrayzero(foffsets, 32)); 8367 PetscCall(PetscArrayzero(coffsets, 32)); 8368 /* Column indices */ 8369 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8370 maxFPoints = numCPoints; 8371 /* Compress out points not in the section */ 8372 /* TODO: Squeeze out points with 0 dof as well */ 8373 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8374 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8375 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8376 cpoints[q * 2] = cpoints[p]; 8377 cpoints[q * 2 + 1] = cpoints[p + 1]; 8378 ++q; 8379 } 8380 } 8381 numCPoints = q; 8382 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8383 PetscInt fdof; 8384 8385 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8386 if (!dof) continue; 8387 for (f = 0; f < numFields; ++f) { 8388 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8389 coffsets[f + 1] += fdof; 8390 } 8391 numCIndices += dof; 8392 } 8393 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8394 /* Row indices */ 8395 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8396 { 8397 DMPlexTransform tr; 8398 DMPolytopeType *rct; 8399 PetscInt *rsize, *rcone, *rornt, Nt; 8400 8401 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8402 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8403 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8404 numSubcells = rsize[Nt - 1]; 8405 PetscCall(DMPlexTransformDestroy(&tr)); 8406 } 8407 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8408 for (r = 0, q = 0; r < numSubcells; ++r) { 8409 /* TODO Map from coarse to fine cells */ 8410 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8411 /* Compress out points not in the section */ 8412 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8413 for (p = 0; p < numFPoints * 2; p += 2) { 8414 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8415 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8416 if (!dof) continue; 8417 for (s = 0; s < q; ++s) 8418 if (fpoints[p] == ftotpoints[s * 2]) break; 8419 if (s < q) continue; 8420 ftotpoints[q * 2] = fpoints[p]; 8421 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8422 ++q; 8423 } 8424 } 8425 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8426 } 8427 numFPoints = q; 8428 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8429 PetscInt fdof; 8430 8431 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8432 if (!dof) continue; 8433 for (f = 0; f < numFields; ++f) { 8434 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8435 foffsets[f + 1] += fdof; 8436 } 8437 numFIndices += dof; 8438 } 8439 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8440 8441 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8442 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8443 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8444 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8445 if (numFields) { 8446 const PetscInt **permsF[32] = {NULL}; 8447 const PetscInt **permsC[32] = {NULL}; 8448 8449 for (f = 0; f < numFields; f++) { 8450 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8451 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8452 } 8453 for (p = 0; p < numFPoints; p++) { 8454 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8455 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8456 } 8457 for (p = 0; p < numCPoints; p++) { 8458 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8459 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8460 } 8461 for (f = 0; f < numFields; f++) { 8462 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8463 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8464 } 8465 } else { 8466 const PetscInt **permsF = NULL; 8467 const PetscInt **permsC = NULL; 8468 8469 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8470 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8471 for (p = 0, off = 0; p < numFPoints; p++) { 8472 const PetscInt *perm = permsF ? permsF[p] : NULL; 8473 8474 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8475 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8476 } 8477 for (p = 0, off = 0; p < numCPoints; p++) { 8478 const PetscInt *perm = permsC ? permsC[p] : NULL; 8479 8480 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8481 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8482 } 8483 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8484 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8485 } 8486 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8487 /* TODO: flips */ 8488 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8489 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8490 if (ierr) { 8491 PetscMPIInt rank; 8492 8493 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8494 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8495 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8496 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8497 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8498 } 8499 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8500 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8501 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8502 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8503 PetscFunctionReturn(PETSC_SUCCESS); 8504 } 8505 8506 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8507 { 8508 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8509 PetscInt *cpoints = NULL; 8510 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8511 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8512 DMPolytopeType ct; 8513 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8514 8515 PetscFunctionBegin; 8516 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8517 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8518 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8519 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8520 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8521 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8522 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8523 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8524 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8525 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8526 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8527 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8528 /* Column indices */ 8529 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8530 maxFPoints = numCPoints; 8531 /* Compress out points not in the section */ 8532 /* TODO: Squeeze out points with 0 dof as well */ 8533 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8534 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8535 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8536 cpoints[q * 2] = cpoints[p]; 8537 cpoints[q * 2 + 1] = cpoints[p + 1]; 8538 ++q; 8539 } 8540 } 8541 numCPoints = q; 8542 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8543 PetscInt fdof; 8544 8545 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8546 if (!dof) continue; 8547 for (f = 0; f < numFields; ++f) { 8548 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8549 coffsets[f + 1] += fdof; 8550 } 8551 numCIndices += dof; 8552 } 8553 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8554 /* Row indices */ 8555 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8556 { 8557 DMPlexTransform tr; 8558 DMPolytopeType *rct; 8559 PetscInt *rsize, *rcone, *rornt, Nt; 8560 8561 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8562 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8563 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8564 numSubcells = rsize[Nt - 1]; 8565 PetscCall(DMPlexTransformDestroy(&tr)); 8566 } 8567 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8568 for (r = 0, q = 0; r < numSubcells; ++r) { 8569 /* TODO Map from coarse to fine cells */ 8570 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8571 /* Compress out points not in the section */ 8572 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8573 for (p = 0; p < numFPoints * 2; p += 2) { 8574 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8575 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8576 if (!dof) continue; 8577 for (s = 0; s < q; ++s) 8578 if (fpoints[p] == ftotpoints[s * 2]) break; 8579 if (s < q) continue; 8580 ftotpoints[q * 2] = fpoints[p]; 8581 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8582 ++q; 8583 } 8584 } 8585 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8586 } 8587 numFPoints = q; 8588 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8589 PetscInt fdof; 8590 8591 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8592 if (!dof) continue; 8593 for (f = 0; f < numFields; ++f) { 8594 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8595 foffsets[f + 1] += fdof; 8596 } 8597 numFIndices += dof; 8598 } 8599 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8600 8601 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8602 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8603 if (numFields) { 8604 const PetscInt **permsF[32] = {NULL}; 8605 const PetscInt **permsC[32] = {NULL}; 8606 8607 for (f = 0; f < numFields; f++) { 8608 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8609 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8610 } 8611 for (p = 0; p < numFPoints; p++) { 8612 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8613 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8614 } 8615 for (p = 0; p < numCPoints; p++) { 8616 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8617 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8618 } 8619 for (f = 0; f < numFields; f++) { 8620 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8621 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8622 } 8623 } else { 8624 const PetscInt **permsF = NULL; 8625 const PetscInt **permsC = NULL; 8626 8627 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8628 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8629 for (p = 0, off = 0; p < numFPoints; p++) { 8630 const PetscInt *perm = permsF ? permsF[p] : NULL; 8631 8632 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8633 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8634 } 8635 for (p = 0, off = 0; p < numCPoints; p++) { 8636 const PetscInt *perm = permsC ? permsC[p] : NULL; 8637 8638 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8639 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8640 } 8641 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8642 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8643 } 8644 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8645 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8646 PetscFunctionReturn(PETSC_SUCCESS); 8647 } 8648 8649 /*@ 8650 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8651 8652 Input Parameter: 8653 . dm - The `DMPLEX` object 8654 8655 Output Parameter: 8656 . cellHeight - The height of a cell 8657 8658 Level: developer 8659 8660 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8661 @*/ 8662 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8663 { 8664 DM_Plex *mesh = (DM_Plex *)dm->data; 8665 8666 PetscFunctionBegin; 8667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8668 PetscAssertPointer(cellHeight, 2); 8669 *cellHeight = mesh->vtkCellHeight; 8670 PetscFunctionReturn(PETSC_SUCCESS); 8671 } 8672 8673 /*@ 8674 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8675 8676 Input Parameters: 8677 + dm - The `DMPLEX` object 8678 - cellHeight - The height of a cell 8679 8680 Level: developer 8681 8682 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8683 @*/ 8684 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8685 { 8686 DM_Plex *mesh = (DM_Plex *)dm->data; 8687 8688 PetscFunctionBegin; 8689 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8690 mesh->vtkCellHeight = cellHeight; 8691 PetscFunctionReturn(PETSC_SUCCESS); 8692 } 8693 8694 /*@ 8695 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8696 8697 Input Parameters: 8698 + dm - The `DMPLEX` object 8699 - ct - The `DMPolytopeType` of the cell 8700 8701 Output Parameters: 8702 + start - The first cell of this type, or `NULL` 8703 - end - The upper bound on this celltype, or `NULL` 8704 8705 Level: advanced 8706 8707 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8708 @*/ 8709 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8710 { 8711 DM_Plex *mesh = (DM_Plex *)dm->data; 8712 DMLabel label; 8713 PetscInt pStart, pEnd; 8714 8715 PetscFunctionBegin; 8716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8717 if (start) { 8718 PetscAssertPointer(start, 3); 8719 *start = 0; 8720 } 8721 if (end) { 8722 PetscAssertPointer(end, 4); 8723 *end = 0; 8724 } 8725 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8726 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8727 if (mesh->tr) { 8728 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8729 } else { 8730 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8731 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8732 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8733 } 8734 PetscFunctionReturn(PETSC_SUCCESS); 8735 } 8736 8737 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8738 { 8739 PetscSection section, globalSection; 8740 PetscInt *numbers, p; 8741 8742 PetscFunctionBegin; 8743 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8744 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8745 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8746 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8747 PetscCall(PetscSectionSetUp(section)); 8748 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8749 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8750 for (p = pStart; p < pEnd; ++p) { 8751 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8752 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8753 else numbers[p - pStart] += shift; 8754 } 8755 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8756 if (globalSize) { 8757 PetscLayout layout; 8758 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8759 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8760 PetscCall(PetscLayoutDestroy(&layout)); 8761 } 8762 PetscCall(PetscSectionDestroy(§ion)); 8763 PetscCall(PetscSectionDestroy(&globalSection)); 8764 PetscFunctionReturn(PETSC_SUCCESS); 8765 } 8766 8767 /*@ 8768 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8769 8770 Input Parameters: 8771 + dm - The `DMPLEX` object 8772 - includeAll - Whether to include all cells, or just the simplex and box cells 8773 8774 Output Parameter: 8775 . globalCellNumbers - Global cell numbers for all cells on this process 8776 8777 Level: developer 8778 8779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8780 @*/ 8781 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8782 { 8783 PetscInt cellHeight, cStart, cEnd; 8784 8785 PetscFunctionBegin; 8786 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8787 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8788 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8789 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8790 PetscFunctionReturn(PETSC_SUCCESS); 8791 } 8792 8793 /*@ 8794 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8795 8796 Input Parameter: 8797 . dm - The `DMPLEX` object 8798 8799 Output Parameter: 8800 . globalCellNumbers - Global cell numbers for all cells on this process 8801 8802 Level: developer 8803 8804 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8805 @*/ 8806 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8807 { 8808 DM_Plex *mesh = (DM_Plex *)dm->data; 8809 8810 PetscFunctionBegin; 8811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8812 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8813 *globalCellNumbers = mesh->globalCellNumbers; 8814 PetscFunctionReturn(PETSC_SUCCESS); 8815 } 8816 8817 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8818 { 8819 PetscInt vStart, vEnd; 8820 8821 PetscFunctionBegin; 8822 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8823 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8824 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8825 PetscFunctionReturn(PETSC_SUCCESS); 8826 } 8827 8828 /*@ 8829 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8830 8831 Input Parameter: 8832 . dm - The `DMPLEX` object 8833 8834 Output Parameter: 8835 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8836 8837 Level: developer 8838 8839 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8840 @*/ 8841 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8842 { 8843 DM_Plex *mesh = (DM_Plex *)dm->data; 8844 8845 PetscFunctionBegin; 8846 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8847 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8848 *globalVertexNumbers = mesh->globalVertexNumbers; 8849 PetscFunctionReturn(PETSC_SUCCESS); 8850 } 8851 8852 /*@ 8853 DMPlexCreatePointNumbering - Create a global numbering for all points. 8854 8855 Collective 8856 8857 Input Parameter: 8858 . dm - The `DMPLEX` object 8859 8860 Output Parameter: 8861 . globalPointNumbers - Global numbers for all points on this process 8862 8863 Level: developer 8864 8865 Notes: 8866 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8867 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8868 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8869 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8870 8871 The partitioned mesh is 8872 ``` 8873 (2)--0--(3)--1--(4) (1)--0--(2) 8874 ``` 8875 and its global numbering is 8876 ``` 8877 (3)--0--(4)--1--(5)--2--(6) 8878 ``` 8879 Then the global numbering is provided as 8880 ``` 8881 [0] Number of indices in set 5 8882 [0] 0 0 8883 [0] 1 1 8884 [0] 2 3 8885 [0] 3 4 8886 [0] 4 -6 8887 [1] Number of indices in set 3 8888 [1] 0 2 8889 [1] 1 5 8890 [1] 2 6 8891 ``` 8892 8893 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8894 @*/ 8895 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8896 { 8897 IS nums[4]; 8898 PetscInt depths[4], gdepths[4], starts[4]; 8899 PetscInt depth, d, shift = 0; 8900 PetscBool empty = PETSC_FALSE; 8901 8902 PetscFunctionBegin; 8903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8904 PetscCall(DMPlexGetDepth(dm, &depth)); 8905 // For unstratified meshes use dim instead of depth 8906 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8907 // If any stratum is empty, we must mark all empty 8908 for (d = 0; d <= depth; ++d) { 8909 PetscInt end; 8910 8911 depths[d] = depth - d; 8912 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8913 if (!(starts[d] - end)) empty = PETSC_TRUE; 8914 } 8915 if (empty) 8916 for (d = 0; d <= depth; ++d) { 8917 depths[d] = -1; 8918 starts[d] = -1; 8919 } 8920 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8921 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8922 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]); 8923 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8924 for (d = 0; d <= depth; ++d) { 8925 PetscInt pStart, pEnd, gsize; 8926 8927 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8928 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8929 shift += gsize; 8930 } 8931 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8932 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8933 PetscFunctionReturn(PETSC_SUCCESS); 8934 } 8935 8936 /*@ 8937 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8938 8939 Collective 8940 8941 Input Parameter: 8942 . dm - The `DMPLEX` object 8943 8944 Output Parameter: 8945 . globalEdgeNumbers - Global numbers for all edges on this process 8946 8947 Level: developer 8948 8949 Notes: 8950 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). In the IS, owned edges will have their non-negative value while edges owned by different ranks will be involuted -(idx+1). 8951 8952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 8953 @*/ 8954 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 8955 { 8956 PetscSF sf; 8957 PetscInt eStart, eEnd; 8958 8959 PetscFunctionBegin; 8960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8961 PetscCall(DMGetPointSF(dm, &sf)); 8962 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8963 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 8964 PetscFunctionReturn(PETSC_SUCCESS); 8965 } 8966 8967 /*@ 8968 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8969 8970 Input Parameter: 8971 . dm - The `DMPLEX` object 8972 8973 Output Parameter: 8974 . ranks - The rank field 8975 8976 Options Database Key: 8977 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8978 8979 Level: intermediate 8980 8981 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8982 @*/ 8983 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8984 { 8985 DM rdm; 8986 PetscFE fe; 8987 PetscScalar *r; 8988 PetscMPIInt rank; 8989 DMPolytopeType ct; 8990 PetscInt dim, cStart, cEnd, c; 8991 PetscBool simplex; 8992 8993 PetscFunctionBeginUser; 8994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8995 PetscAssertPointer(ranks, 2); 8996 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8997 PetscCall(DMClone(dm, &rdm)); 8998 PetscCall(DMGetDimension(rdm, &dim)); 8999 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9000 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9001 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9002 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9003 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9004 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9005 PetscCall(PetscFEDestroy(&fe)); 9006 PetscCall(DMCreateDS(rdm)); 9007 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9008 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9009 PetscCall(VecGetArray(*ranks, &r)); 9010 for (c = cStart; c < cEnd; ++c) { 9011 PetscScalar *lr; 9012 9013 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9014 if (lr) *lr = rank; 9015 } 9016 PetscCall(VecRestoreArray(*ranks, &r)); 9017 PetscCall(DMDestroy(&rdm)); 9018 PetscFunctionReturn(PETSC_SUCCESS); 9019 } 9020 9021 /*@ 9022 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9023 9024 Input Parameters: 9025 + dm - The `DMPLEX` 9026 - label - The `DMLabel` 9027 9028 Output Parameter: 9029 . val - The label value field 9030 9031 Options Database Key: 9032 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9033 9034 Level: intermediate 9035 9036 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9037 @*/ 9038 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9039 { 9040 DM rdm, plex; 9041 Vec lval; 9042 PetscSection section; 9043 PetscFE fe; 9044 PetscScalar *v; 9045 PetscInt dim, pStart, pEnd, p, cStart; 9046 DMPolytopeType ct; 9047 char name[PETSC_MAX_PATH_LEN]; 9048 const char *lname, *prefix; 9049 9050 PetscFunctionBeginUser; 9051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9052 PetscAssertPointer(label, 2); 9053 PetscAssertPointer(val, 3); 9054 PetscCall(DMClone(dm, &rdm)); 9055 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9056 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9057 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9058 PetscCall(DMDestroy(&plex)); 9059 PetscCall(DMGetDimension(rdm, &dim)); 9060 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9061 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9062 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9063 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9064 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9065 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9066 PetscCall(PetscFEDestroy(&fe)); 9067 PetscCall(DMCreateDS(rdm)); 9068 PetscCall(DMCreateGlobalVector(rdm, val)); 9069 PetscCall(DMCreateLocalVector(rdm, &lval)); 9070 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9071 PetscCall(DMGetLocalSection(rdm, §ion)); 9072 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9073 PetscCall(VecGetArray(lval, &v)); 9074 for (p = pStart; p < pEnd; ++p) { 9075 PetscInt cval, dof, off; 9076 9077 PetscCall(PetscSectionGetDof(section, p, &dof)); 9078 if (!dof) continue; 9079 PetscCall(DMLabelGetValue(label, p, &cval)); 9080 PetscCall(PetscSectionGetOffset(section, p, &off)); 9081 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9082 } 9083 PetscCall(VecRestoreArray(lval, &v)); 9084 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9085 PetscCall(VecDestroy(&lval)); 9086 PetscCall(DMDestroy(&rdm)); 9087 PetscFunctionReturn(PETSC_SUCCESS); 9088 } 9089 9090 /*@ 9091 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9092 9093 Input Parameter: 9094 . dm - The `DMPLEX` object 9095 9096 Level: developer 9097 9098 Notes: 9099 This is a useful diagnostic when creating meshes programmatically. 9100 9101 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9102 9103 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9104 @*/ 9105 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9106 { 9107 PetscSection coneSection, supportSection; 9108 const PetscInt *cone, *support; 9109 PetscInt coneSize, c, supportSize, s; 9110 PetscInt pStart, pEnd, p, pp, csize, ssize; 9111 PetscBool storagecheck = PETSC_TRUE; 9112 9113 PetscFunctionBegin; 9114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9115 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9116 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9117 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9118 /* Check that point p is found in the support of its cone points, and vice versa */ 9119 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9120 for (p = pStart; p < pEnd; ++p) { 9121 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9122 PetscCall(DMPlexGetCone(dm, p, &cone)); 9123 for (c = 0; c < coneSize; ++c) { 9124 PetscBool dup = PETSC_FALSE; 9125 PetscInt d; 9126 for (d = c - 1; d >= 0; --d) { 9127 if (cone[c] == cone[d]) { 9128 dup = PETSC_TRUE; 9129 break; 9130 } 9131 } 9132 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9133 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9134 for (s = 0; s < supportSize; ++s) { 9135 if (support[s] == p) break; 9136 } 9137 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9138 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9139 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9140 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9141 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9142 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9143 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9144 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]); 9145 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9146 } 9147 } 9148 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9149 if (p != pp) { 9150 storagecheck = PETSC_FALSE; 9151 continue; 9152 } 9153 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9154 PetscCall(DMPlexGetSupport(dm, p, &support)); 9155 for (s = 0; s < supportSize; ++s) { 9156 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9157 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9158 for (c = 0; c < coneSize; ++c) { 9159 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9160 if (cone[c] != pp) { 9161 c = 0; 9162 break; 9163 } 9164 if (cone[c] == p) break; 9165 } 9166 if (c >= coneSize) { 9167 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9168 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9169 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9170 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9171 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9172 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9173 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9174 } 9175 } 9176 } 9177 if (storagecheck) { 9178 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9179 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9180 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9181 } 9182 PetscFunctionReturn(PETSC_SUCCESS); 9183 } 9184 9185 /* 9186 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. 9187 */ 9188 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9189 { 9190 DMPolytopeType cct; 9191 PetscInt ptpoints[4]; 9192 const PetscInt *cone, *ccone, *ptcone; 9193 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9194 9195 PetscFunctionBegin; 9196 *unsplit = 0; 9197 switch (ct) { 9198 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9199 ptpoints[npt++] = c; 9200 break; 9201 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9202 PetscCall(DMPlexGetCone(dm, c, &cone)); 9203 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9204 for (cp = 0; cp < coneSize; ++cp) { 9205 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9206 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9207 } 9208 break; 9209 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9210 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9211 PetscCall(DMPlexGetCone(dm, c, &cone)); 9212 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9213 for (cp = 0; cp < coneSize; ++cp) { 9214 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9215 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9216 for (ccp = 0; ccp < cconeSize; ++ccp) { 9217 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9218 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9219 PetscInt p; 9220 for (p = 0; p < npt; ++p) 9221 if (ptpoints[p] == ccone[ccp]) break; 9222 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9223 } 9224 } 9225 } 9226 break; 9227 default: 9228 break; 9229 } 9230 for (pt = 0; pt < npt; ++pt) { 9231 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9232 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9233 } 9234 PetscFunctionReturn(PETSC_SUCCESS); 9235 } 9236 9237 /*@ 9238 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9239 9240 Input Parameters: 9241 + dm - The `DMPLEX` object 9242 - cellHeight - Normally 0 9243 9244 Level: developer 9245 9246 Notes: 9247 This is a useful diagnostic when creating meshes programmatically. 9248 Currently applicable only to homogeneous simplex or tensor meshes. 9249 9250 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9251 9252 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9253 @*/ 9254 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9255 { 9256 DMPlexInterpolatedFlag interp; 9257 DMPolytopeType ct; 9258 PetscInt vStart, vEnd, cStart, cEnd, c; 9259 9260 PetscFunctionBegin; 9261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9262 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9263 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9264 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9265 for (c = cStart; c < cEnd; ++c) { 9266 PetscInt *closure = NULL; 9267 PetscInt coneSize, closureSize, cl, Nv = 0; 9268 9269 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9270 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9271 if (interp == DMPLEX_INTERPOLATED_FULL) { 9272 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9273 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)); 9274 } 9275 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9276 for (cl = 0; cl < closureSize * 2; cl += 2) { 9277 const PetscInt p = closure[cl]; 9278 if ((p >= vStart) && (p < vEnd)) ++Nv; 9279 } 9280 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9281 /* Special Case: Tensor faces with identified vertices */ 9282 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9283 PetscInt unsplit; 9284 9285 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9286 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9287 } 9288 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)); 9289 } 9290 PetscFunctionReturn(PETSC_SUCCESS); 9291 } 9292 9293 /*@ 9294 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9295 9296 Collective 9297 9298 Input Parameters: 9299 + dm - The `DMPLEX` object 9300 - cellHeight - Normally 0 9301 9302 Level: developer 9303 9304 Notes: 9305 This is a useful diagnostic when creating meshes programmatically. 9306 This routine is only relevant for meshes that are fully interpolated across all ranks. 9307 It will error out if a partially interpolated mesh is given on some rank. 9308 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9309 9310 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9311 9312 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9313 @*/ 9314 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9315 { 9316 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9317 DMPlexInterpolatedFlag interpEnum; 9318 9319 PetscFunctionBegin; 9320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9321 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9322 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9323 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9324 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9325 PetscFunctionReturn(PETSC_SUCCESS); 9326 } 9327 9328 PetscCall(DMGetDimension(dm, &dim)); 9329 PetscCall(DMPlexGetDepth(dm, &depth)); 9330 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9331 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9332 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9333 for (c = cStart; c < cEnd; ++c) { 9334 const PetscInt *cone, *ornt, *faceSizes, *faces; 9335 const DMPolytopeType *faceTypes; 9336 DMPolytopeType ct; 9337 PetscInt numFaces, coneSize, f; 9338 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9339 9340 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9341 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9342 if (unsplit) continue; 9343 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9344 PetscCall(DMPlexGetCone(dm, c, &cone)); 9345 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9346 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9347 for (cl = 0; cl < closureSize * 2; cl += 2) { 9348 const PetscInt p = closure[cl]; 9349 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9350 } 9351 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9352 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); 9353 for (f = 0; f < numFaces; ++f) { 9354 DMPolytopeType fct; 9355 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9356 9357 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9358 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9359 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9360 const PetscInt p = fclosure[cl]; 9361 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9362 } 9363 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]); 9364 for (v = 0; v < fnumCorners; ++v) { 9365 if (fclosure[v] != faces[fOff + v]) { 9366 PetscInt v1; 9367 9368 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9369 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9370 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9371 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9372 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9373 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]); 9374 } 9375 } 9376 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9377 fOff += faceSizes[f]; 9378 } 9379 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9380 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9381 } 9382 } 9383 PetscFunctionReturn(PETSC_SUCCESS); 9384 } 9385 9386 /*@ 9387 DMPlexCheckGeometry - Check the geometry of mesh cells 9388 9389 Input Parameter: 9390 . dm - The `DMPLEX` object 9391 9392 Level: developer 9393 9394 Notes: 9395 This is a useful diagnostic when creating meshes programmatically. 9396 9397 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9398 9399 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9400 @*/ 9401 PetscErrorCode DMPlexCheckGeometry(DM dm) 9402 { 9403 Vec coordinates; 9404 PetscReal detJ, J[9], refVol = 1.0; 9405 PetscReal vol; 9406 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9407 9408 PetscFunctionBegin; 9409 PetscCall(DMGetDimension(dm, &dim)); 9410 PetscCall(DMGetCoordinateDim(dm, &dE)); 9411 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9412 PetscCall(DMPlexGetDepth(dm, &depth)); 9413 for (d = 0; d < dim; ++d) refVol *= 2.0; 9414 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9415 /* Make sure local coordinates are created, because that step is collective */ 9416 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9417 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9418 for (c = cStart; c < cEnd; ++c) { 9419 DMPolytopeType ct; 9420 PetscInt unsplit; 9421 PetscBool ignoreZeroVol = PETSC_FALSE; 9422 9423 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9424 switch (ct) { 9425 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9426 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9427 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9428 ignoreZeroVol = PETSC_TRUE; 9429 break; 9430 default: 9431 break; 9432 } 9433 switch (ct) { 9434 case DM_POLYTOPE_TRI_PRISM: 9435 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9436 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9437 case DM_POLYTOPE_PYRAMID: 9438 continue; 9439 default: 9440 break; 9441 } 9442 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9443 if (unsplit) continue; 9444 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9445 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); 9446 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9447 /* This should work with periodicity since DG coordinates should be used */ 9448 if (depth > 1) { 9449 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9450 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); 9451 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9452 } 9453 } 9454 PetscFunctionReturn(PETSC_SUCCESS); 9455 } 9456 9457 /*@ 9458 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9459 9460 Collective 9461 9462 Input Parameters: 9463 + dm - The `DMPLEX` object 9464 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9465 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9466 9467 Level: developer 9468 9469 Notes: 9470 This is mainly intended for debugging/testing purposes. 9471 9472 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9473 9474 Extra roots can come from periodic cuts, where additional points appear on the boundary 9475 9476 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9477 @*/ 9478 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9479 { 9480 PetscInt l, nleaves, nroots, overlap; 9481 const PetscInt *locals; 9482 const PetscSFNode *remotes; 9483 PetscBool distributed; 9484 MPI_Comm comm; 9485 PetscMPIInt rank; 9486 9487 PetscFunctionBegin; 9488 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9489 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9490 else pointSF = dm->sf; 9491 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9492 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9493 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9494 { 9495 PetscMPIInt mpiFlag; 9496 9497 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9498 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9499 } 9500 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9501 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9502 if (!distributed) { 9503 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); 9504 PetscFunctionReturn(PETSC_SUCCESS); 9505 } 9506 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); 9507 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9508 9509 /* Check SF graph is compatible with DMPlex chart */ 9510 { 9511 PetscInt pStart, pEnd, maxLeaf; 9512 9513 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9514 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9515 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9516 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9517 } 9518 9519 /* Check Point SF has no local points referenced */ 9520 for (l = 0; l < nleaves; l++) { 9521 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); 9522 } 9523 9524 /* Check there are no cells in interface */ 9525 if (!overlap) { 9526 PetscInt cellHeight, cStart, cEnd; 9527 9528 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9529 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9530 for (l = 0; l < nleaves; ++l) { 9531 const PetscInt point = locals ? locals[l] : l; 9532 9533 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9534 } 9535 } 9536 9537 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9538 { 9539 const PetscInt *rootdegree; 9540 9541 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9542 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9543 for (l = 0; l < nleaves; ++l) { 9544 const PetscInt point = locals ? locals[l] : l; 9545 const PetscInt *cone; 9546 PetscInt coneSize, c, idx; 9547 9548 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9549 PetscCall(DMPlexGetCone(dm, point, &cone)); 9550 for (c = 0; c < coneSize; ++c) { 9551 if (!rootdegree[cone[c]]) { 9552 if (locals) { 9553 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9554 } else { 9555 idx = (cone[c] < nleaves) ? cone[c] : -1; 9556 } 9557 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9558 } 9559 } 9560 } 9561 } 9562 PetscFunctionReturn(PETSC_SUCCESS); 9563 } 9564 9565 /*@ 9566 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9567 9568 Collective 9569 9570 Input Parameter: 9571 . dm - The `DMPLEX` object 9572 9573 Level: developer 9574 9575 Notes: 9576 This is mainly intended for debugging/testing purposes. 9577 9578 Other cell types which are disconnected would be caught by the symmetry and face checks. 9579 9580 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9581 9582 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9583 @*/ 9584 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9585 { 9586 PetscInt pStart, pEnd, vStart, vEnd; 9587 9588 PetscFunctionBegin; 9589 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9590 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9591 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9592 for (PetscInt v = vStart; v < vEnd; ++v) { 9593 PetscInt suppSize; 9594 9595 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9596 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9597 } 9598 PetscFunctionReturn(PETSC_SUCCESS); 9599 } 9600 9601 /*@ 9602 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9603 9604 Input Parameter: 9605 . dm - The `DMPLEX` object 9606 9607 Level: developer 9608 9609 Notes: 9610 This is a useful diagnostic when creating meshes programmatically. 9611 9612 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9613 9614 Currently does not include `DMPlexCheckCellShape()`. 9615 9616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9617 @*/ 9618 PetscErrorCode DMPlexCheck(DM dm) 9619 { 9620 PetscInt cellHeight; 9621 9622 PetscFunctionBegin; 9623 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9624 PetscCall(DMPlexCheckSymmetry(dm)); 9625 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9626 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9627 PetscCall(DMPlexCheckGeometry(dm)); 9628 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9629 PetscCall(DMPlexCheckInterfaceCones(dm)); 9630 PetscCall(DMPlexCheckOrphanVertices(dm)); 9631 PetscFunctionReturn(PETSC_SUCCESS); 9632 } 9633 9634 typedef struct cell_stats { 9635 PetscReal min, max, sum, squaresum; 9636 PetscInt count; 9637 } cell_stats_t; 9638 9639 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9640 { 9641 PetscInt i, N = *len; 9642 9643 for (i = 0; i < N; i++) { 9644 cell_stats_t *A = (cell_stats_t *)a; 9645 cell_stats_t *B = (cell_stats_t *)b; 9646 9647 B->min = PetscMin(A->min, B->min); 9648 B->max = PetscMax(A->max, B->max); 9649 B->sum += A->sum; 9650 B->squaresum += A->squaresum; 9651 B->count += A->count; 9652 } 9653 } 9654 9655 /*@ 9656 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9657 9658 Collective 9659 9660 Input Parameters: 9661 + dm - The `DMPLEX` object 9662 . output - If true, statistics will be displayed on `stdout` 9663 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9664 9665 Level: developer 9666 9667 Notes: 9668 This is mainly intended for debugging/testing purposes. 9669 9670 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9671 9672 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9673 @*/ 9674 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9675 { 9676 DM dmCoarse; 9677 cell_stats_t stats, globalStats; 9678 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9679 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9680 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9681 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9682 PetscMPIInt rank, size; 9683 9684 PetscFunctionBegin; 9685 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9686 stats.min = PETSC_MAX_REAL; 9687 stats.max = PETSC_MIN_REAL; 9688 stats.sum = stats.squaresum = 0.; 9689 stats.count = 0; 9690 9691 PetscCallMPI(MPI_Comm_size(comm, &size)); 9692 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9693 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9694 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9695 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9696 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9697 for (c = cStart; c < cEnd; c++) { 9698 PetscInt i; 9699 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9700 9701 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9702 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9703 for (i = 0; i < PetscSqr(cdim); ++i) { 9704 frobJ += J[i] * J[i]; 9705 frobInvJ += invJ[i] * invJ[i]; 9706 } 9707 cond2 = frobJ * frobInvJ; 9708 cond = PetscSqrtReal(cond2); 9709 9710 stats.min = PetscMin(stats.min, cond); 9711 stats.max = PetscMax(stats.max, cond); 9712 stats.sum += cond; 9713 stats.squaresum += cond2; 9714 stats.count++; 9715 if (output && cond > limit) { 9716 PetscSection coordSection; 9717 Vec coordsLocal; 9718 PetscScalar *coords = NULL; 9719 PetscInt Nv, d, clSize, cl, *closure = NULL; 9720 9721 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9722 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9723 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9724 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9725 for (i = 0; i < Nv / cdim; ++i) { 9726 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9727 for (d = 0; d < cdim; ++d) { 9728 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9729 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9730 } 9731 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9732 } 9733 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9734 for (cl = 0; cl < clSize * 2; cl += 2) { 9735 const PetscInt edge = closure[cl]; 9736 9737 if ((edge >= eStart) && (edge < eEnd)) { 9738 PetscReal len; 9739 9740 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9741 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9742 } 9743 } 9744 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9745 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9746 } 9747 } 9748 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9749 9750 if (size > 1) { 9751 PetscMPIInt blockLengths[2] = {4, 1}; 9752 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9753 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9754 MPI_Op statReduce; 9755 9756 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9757 PetscCallMPI(MPI_Type_commit(&statType)); 9758 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9759 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9760 PetscCallMPI(MPI_Op_free(&statReduce)); 9761 PetscCallMPI(MPI_Type_free(&statType)); 9762 } else { 9763 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9764 } 9765 if (rank == 0) { 9766 count = globalStats.count; 9767 min = globalStats.min; 9768 max = globalStats.max; 9769 mean = globalStats.sum / globalStats.count; 9770 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9771 } 9772 9773 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)); 9774 PetscCall(PetscFree2(J, invJ)); 9775 9776 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9777 if (dmCoarse) { 9778 PetscBool isplex; 9779 9780 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9781 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9782 } 9783 PetscFunctionReturn(PETSC_SUCCESS); 9784 } 9785 9786 /*@ 9787 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9788 orthogonal quality below given tolerance. 9789 9790 Collective 9791 9792 Input Parameters: 9793 + dm - The `DMPLEX` object 9794 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9795 - atol - [0, 1] Absolute tolerance for tagging cells. 9796 9797 Output Parameters: 9798 + OrthQual - `Vec` containing orthogonal quality per cell 9799 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9800 9801 Options Database Keys: 9802 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9803 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9804 9805 Level: intermediate 9806 9807 Notes: 9808 Orthogonal quality is given by the following formula\: 9809 9810 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9811 9812 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 9813 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9814 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9815 calculating the cosine of the angle between these vectors. 9816 9817 Orthogonal quality ranges from 1 (best) to 0 (worst). 9818 9819 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9820 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9821 9822 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9823 9824 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9825 @*/ 9826 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9827 { 9828 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9829 PetscInt *idx; 9830 PetscScalar *oqVals; 9831 const PetscScalar *cellGeomArr, *faceGeomArr; 9832 PetscReal *ci, *fi, *Ai; 9833 MPI_Comm comm; 9834 Vec cellgeom, facegeom; 9835 DM dmFace, dmCell; 9836 IS glob; 9837 ISLocalToGlobalMapping ltog; 9838 PetscViewer vwr; 9839 9840 PetscFunctionBegin; 9841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9842 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9843 PetscAssertPointer(OrthQual, 4); 9844 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9845 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9846 PetscCall(DMGetDimension(dm, &nc)); 9847 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9848 { 9849 DMPlexInterpolatedFlag interpFlag; 9850 9851 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9852 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9853 PetscMPIInt rank; 9854 9855 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9856 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9857 } 9858 } 9859 if (OrthQualLabel) { 9860 PetscAssertPointer(OrthQualLabel, 5); 9861 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9862 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9863 } else { 9864 *OrthQualLabel = NULL; 9865 } 9866 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9867 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9868 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9869 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9870 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9871 PetscCall(VecCreate(comm, OrthQual)); 9872 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9873 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9874 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9875 PetscCall(VecSetUp(*OrthQual)); 9876 PetscCall(ISDestroy(&glob)); 9877 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9878 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9879 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9880 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9881 PetscCall(VecGetDM(cellgeom, &dmCell)); 9882 PetscCall(VecGetDM(facegeom, &dmFace)); 9883 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9884 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9885 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9886 PetscInt cellarr[2], *adj = NULL; 9887 PetscScalar *cArr, *fArr; 9888 PetscReal minvalc = 1.0, minvalf = 1.0; 9889 PetscFVCellGeom *cg; 9890 9891 idx[cellIter] = cell - cStart; 9892 cellarr[0] = cell; 9893 /* Make indexing into cellGeom easier */ 9894 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9895 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9896 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9897 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9898 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9899 PetscInt i; 9900 const PetscInt neigh = adj[cellneigh]; 9901 PetscReal normci = 0, normfi = 0, normai = 0; 9902 PetscFVCellGeom *cgneigh; 9903 PetscFVFaceGeom *fg; 9904 9905 /* Don't count ourselves in the neighbor list */ 9906 if (neigh == cell) continue; 9907 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9908 cellarr[1] = neigh; 9909 { 9910 PetscInt numcovpts; 9911 const PetscInt *covpts; 9912 9913 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9914 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9915 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9916 } 9917 9918 /* Compute c_i, f_i and their norms */ 9919 for (i = 0; i < nc; i++) { 9920 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9921 fi[i] = fg->centroid[i] - cg->centroid[i]; 9922 Ai[i] = fg->normal[i]; 9923 normci += PetscPowReal(ci[i], 2); 9924 normfi += PetscPowReal(fi[i], 2); 9925 normai += PetscPowReal(Ai[i], 2); 9926 } 9927 normci = PetscSqrtReal(normci); 9928 normfi = PetscSqrtReal(normfi); 9929 normai = PetscSqrtReal(normai); 9930 9931 /* Normalize and compute for each face-cell-normal pair */ 9932 for (i = 0; i < nc; i++) { 9933 ci[i] = ci[i] / normci; 9934 fi[i] = fi[i] / normfi; 9935 Ai[i] = Ai[i] / normai; 9936 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9937 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9938 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9939 } 9940 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9941 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9942 } 9943 PetscCall(PetscFree(adj)); 9944 PetscCall(PetscFree2(cArr, fArr)); 9945 /* Defer to cell if they're equal */ 9946 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9947 if (OrthQualLabel) { 9948 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9949 } 9950 } 9951 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9952 PetscCall(VecAssemblyBegin(*OrthQual)); 9953 PetscCall(VecAssemblyEnd(*OrthQual)); 9954 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9955 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9956 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9957 if (OrthQualLabel) { 9958 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9959 } 9960 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9961 PetscCall(PetscViewerDestroy(&vwr)); 9962 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9963 PetscFunctionReturn(PETSC_SUCCESS); 9964 } 9965 9966 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9967 * interpolator construction */ 9968 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9969 { 9970 PetscSection section, newSection, gsection; 9971 PetscSF sf; 9972 PetscBool hasConstraints, ghasConstraints; 9973 9974 PetscFunctionBegin; 9975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9976 PetscAssertPointer(odm, 2); 9977 PetscCall(DMGetLocalSection(dm, §ion)); 9978 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9979 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9980 if (!ghasConstraints) { 9981 PetscCall(PetscObjectReference((PetscObject)dm)); 9982 *odm = dm; 9983 PetscFunctionReturn(PETSC_SUCCESS); 9984 } 9985 PetscCall(DMClone(dm, odm)); 9986 PetscCall(DMCopyFields(dm, *odm)); 9987 PetscCall(DMGetLocalSection(*odm, &newSection)); 9988 PetscCall(DMGetPointSF(*odm, &sf)); 9989 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 9990 PetscCall(DMSetGlobalSection(*odm, gsection)); 9991 PetscCall(PetscSectionDestroy(&gsection)); 9992 PetscFunctionReturn(PETSC_SUCCESS); 9993 } 9994 9995 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9996 { 9997 DM dmco, dmfo; 9998 Mat interpo; 9999 Vec rscale; 10000 Vec cglobalo, clocal; 10001 Vec fglobal, fglobalo, flocal; 10002 PetscBool regular; 10003 10004 PetscFunctionBegin; 10005 PetscCall(DMGetFullDM(dmc, &dmco)); 10006 PetscCall(DMGetFullDM(dmf, &dmfo)); 10007 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10008 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10009 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10010 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10011 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10012 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10013 PetscCall(VecSet(cglobalo, 0.)); 10014 PetscCall(VecSet(clocal, 0.)); 10015 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10016 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10017 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10018 PetscCall(VecSet(fglobal, 0.)); 10019 PetscCall(VecSet(fglobalo, 0.)); 10020 PetscCall(VecSet(flocal, 0.)); 10021 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10022 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10023 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10024 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10025 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10026 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10027 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10028 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10029 *shift = fglobal; 10030 PetscCall(VecDestroy(&flocal)); 10031 PetscCall(VecDestroy(&fglobalo)); 10032 PetscCall(VecDestroy(&clocal)); 10033 PetscCall(VecDestroy(&cglobalo)); 10034 PetscCall(VecDestroy(&rscale)); 10035 PetscCall(MatDestroy(&interpo)); 10036 PetscCall(DMDestroy(&dmfo)); 10037 PetscCall(DMDestroy(&dmco)); 10038 PetscFunctionReturn(PETSC_SUCCESS); 10039 } 10040 10041 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10042 { 10043 PetscObject shifto; 10044 Vec shift; 10045 10046 PetscFunctionBegin; 10047 if (!interp) { 10048 Vec rscale; 10049 10050 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10051 PetscCall(VecDestroy(&rscale)); 10052 } else { 10053 PetscCall(PetscObjectReference((PetscObject)interp)); 10054 } 10055 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10056 if (!shifto) { 10057 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10058 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10059 shifto = (PetscObject)shift; 10060 PetscCall(VecDestroy(&shift)); 10061 } 10062 shift = (Vec)shifto; 10063 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10064 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10065 PetscCall(MatDestroy(&interp)); 10066 PetscFunctionReturn(PETSC_SUCCESS); 10067 } 10068 10069 /* Pointwise interpolation 10070 Just code FEM for now 10071 u^f = I u^c 10072 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10073 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10074 I_{ij} = psi^f_i phi^c_j 10075 */ 10076 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10077 { 10078 PetscSection gsc, gsf; 10079 PetscInt m, n; 10080 void *ctx; 10081 DM cdm; 10082 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10083 10084 PetscFunctionBegin; 10085 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10086 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10087 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10088 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10089 10090 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10091 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10092 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10093 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10094 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10095 10096 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10097 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10098 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10099 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10100 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10101 if (scaling) { 10102 /* Use naive scaling */ 10103 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10104 } 10105 PetscFunctionReturn(PETSC_SUCCESS); 10106 } 10107 10108 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10109 { 10110 VecScatter ctx; 10111 10112 PetscFunctionBegin; 10113 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10114 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10115 PetscCall(VecScatterDestroy(&ctx)); 10116 PetscFunctionReturn(PETSC_SUCCESS); 10117 } 10118 10119 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[]) 10120 { 10121 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10122 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10123 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10124 } 10125 10126 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10127 { 10128 DM dmc; 10129 PetscDS ds; 10130 Vec ones, locmass; 10131 IS cellIS; 10132 PetscFormKey key; 10133 PetscInt depth; 10134 10135 PetscFunctionBegin; 10136 PetscCall(DMClone(dm, &dmc)); 10137 PetscCall(DMCopyDisc(dm, dmc)); 10138 PetscCall(DMGetDS(dmc, &ds)); 10139 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10140 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10141 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10142 else PetscCall(DMGetLocalVector(dm, &locmass)); 10143 PetscCall(DMGetLocalVector(dm, &ones)); 10144 PetscCall(DMPlexGetDepth(dm, &depth)); 10145 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10146 PetscCall(VecSet(locmass, 0.0)); 10147 PetscCall(VecSet(ones, 1.0)); 10148 key.label = NULL; 10149 key.value = 0; 10150 key.field = 0; 10151 key.part = 0; 10152 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10153 PetscCall(ISDestroy(&cellIS)); 10154 if (mass) { 10155 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10156 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10157 } 10158 PetscCall(DMRestoreLocalVector(dm, &ones)); 10159 if (lmass) *lmass = locmass; 10160 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10161 PetscCall(DMDestroy(&dmc)); 10162 PetscFunctionReturn(PETSC_SUCCESS); 10163 } 10164 10165 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10166 { 10167 PetscSection gsc, gsf; 10168 PetscInt m, n; 10169 void *ctx; 10170 DM cdm; 10171 PetscBool regular; 10172 10173 PetscFunctionBegin; 10174 if (dmFine == dmCoarse) { 10175 DM dmc; 10176 PetscDS ds; 10177 PetscWeakForm wf; 10178 Vec u; 10179 IS cellIS; 10180 PetscFormKey key; 10181 PetscInt depth; 10182 10183 PetscCall(DMClone(dmFine, &dmc)); 10184 PetscCall(DMCopyDisc(dmFine, dmc)); 10185 PetscCall(DMGetDS(dmc, &ds)); 10186 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10187 PetscCall(PetscWeakFormClear(wf)); 10188 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10189 PetscCall(DMCreateMatrix(dmc, mass)); 10190 PetscCall(DMGetLocalVector(dmc, &u)); 10191 PetscCall(DMPlexGetDepth(dmc, &depth)); 10192 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10193 PetscCall(MatZeroEntries(*mass)); 10194 key.label = NULL; 10195 key.value = 0; 10196 key.field = 0; 10197 key.part = 0; 10198 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10199 PetscCall(ISDestroy(&cellIS)); 10200 PetscCall(DMRestoreLocalVector(dmc, &u)); 10201 PetscCall(DMDestroy(&dmc)); 10202 } else { 10203 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10204 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10205 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10206 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10207 10208 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10209 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10210 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10211 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10212 10213 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10214 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10215 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10216 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10217 } 10218 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10219 PetscFunctionReturn(PETSC_SUCCESS); 10220 } 10221 10222 /*@ 10223 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10224 10225 Input Parameter: 10226 . dm - The `DMPLEX` object 10227 10228 Output Parameter: 10229 . regular - The flag 10230 10231 Level: intermediate 10232 10233 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10234 @*/ 10235 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10236 { 10237 PetscFunctionBegin; 10238 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10239 PetscAssertPointer(regular, 2); 10240 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10241 PetscFunctionReturn(PETSC_SUCCESS); 10242 } 10243 10244 /*@ 10245 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10246 10247 Input Parameters: 10248 + dm - The `DMPLEX` object 10249 - regular - The flag 10250 10251 Level: intermediate 10252 10253 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10254 @*/ 10255 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10256 { 10257 PetscFunctionBegin; 10258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10259 ((DM_Plex *)dm->data)->regularRefinement = regular; 10260 PetscFunctionReturn(PETSC_SUCCESS); 10261 } 10262 10263 /*@ 10264 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10265 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10266 10267 Not Collective 10268 10269 Input Parameter: 10270 . dm - The `DMPLEX` object 10271 10272 Output Parameters: 10273 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10274 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10275 10276 Level: intermediate 10277 10278 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10279 @*/ 10280 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10281 { 10282 DM_Plex *plex = (DM_Plex *)dm->data; 10283 10284 PetscFunctionBegin; 10285 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10286 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10287 if (anchorSection) *anchorSection = plex->anchorSection; 10288 if (anchorIS) *anchorIS = plex->anchorIS; 10289 PetscFunctionReturn(PETSC_SUCCESS); 10290 } 10291 10292 /*@ 10293 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10294 10295 Collective 10296 10297 Input Parameters: 10298 + dm - The `DMPLEX` object 10299 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10300 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10301 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10302 10303 Level: intermediate 10304 10305 Notes: 10306 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10307 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10308 combination of other points' degrees of freedom. 10309 10310 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10311 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10312 10313 The reference counts of `anchorSection` and `anchorIS` are incremented. 10314 10315 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10316 @*/ 10317 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10318 { 10319 DM_Plex *plex = (DM_Plex *)dm->data; 10320 PetscMPIInt result; 10321 10322 PetscFunctionBegin; 10323 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10324 if (anchorSection) { 10325 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10326 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10327 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10328 } 10329 if (anchorIS) { 10330 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10331 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10332 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10333 } 10334 10335 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10336 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10337 plex->anchorSection = anchorSection; 10338 10339 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10340 PetscCall(ISDestroy(&plex->anchorIS)); 10341 plex->anchorIS = anchorIS; 10342 10343 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10344 PetscInt size, a, pStart, pEnd; 10345 const PetscInt *anchors; 10346 10347 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10348 PetscCall(ISGetLocalSize(anchorIS, &size)); 10349 PetscCall(ISGetIndices(anchorIS, &anchors)); 10350 for (a = 0; a < size; a++) { 10351 PetscInt p; 10352 10353 p = anchors[a]; 10354 if (p >= pStart && p < pEnd) { 10355 PetscInt dof; 10356 10357 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10358 if (dof) { 10359 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10360 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10361 } 10362 } 10363 } 10364 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10365 } 10366 /* reset the generic constraints */ 10367 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10368 PetscFunctionReturn(PETSC_SUCCESS); 10369 } 10370 10371 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10372 { 10373 PetscSection anchorSection; 10374 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10375 10376 PetscFunctionBegin; 10377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10378 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10379 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10380 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10381 if (numFields) { 10382 PetscInt f; 10383 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10384 10385 for (f = 0; f < numFields; f++) { 10386 PetscInt numComp; 10387 10388 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10389 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10390 } 10391 } 10392 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10393 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10394 pStart = PetscMax(pStart, sStart); 10395 pEnd = PetscMin(pEnd, sEnd); 10396 pEnd = PetscMax(pStart, pEnd); 10397 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10398 for (p = pStart; p < pEnd; p++) { 10399 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10400 if (dof) { 10401 PetscCall(PetscSectionGetDof(section, p, &dof)); 10402 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10403 for (f = 0; f < numFields; f++) { 10404 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10405 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10406 } 10407 } 10408 } 10409 PetscCall(PetscSectionSetUp(*cSec)); 10410 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10411 PetscFunctionReturn(PETSC_SUCCESS); 10412 } 10413 10414 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10415 { 10416 PetscSection aSec; 10417 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10418 const PetscInt *anchors; 10419 PetscInt numFields, f; 10420 IS aIS; 10421 MatType mtype; 10422 PetscBool iscuda, iskokkos; 10423 10424 PetscFunctionBegin; 10425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10426 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10427 PetscCall(PetscSectionGetStorageSize(section, &n)); 10428 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10429 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10430 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10431 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10432 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10433 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10434 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10435 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10436 else mtype = MATSEQAIJ; 10437 PetscCall(MatSetType(*cMat, mtype)); 10438 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10439 PetscCall(ISGetIndices(aIS, &anchors)); 10440 /* cSec will be a subset of aSec and section */ 10441 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10442 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10443 PetscCall(PetscMalloc1(m + 1, &i)); 10444 i[0] = 0; 10445 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10446 for (p = pStart; p < pEnd; p++) { 10447 PetscInt rDof, rOff, r; 10448 10449 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10450 if (!rDof) continue; 10451 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10452 if (numFields) { 10453 for (f = 0; f < numFields; f++) { 10454 annz = 0; 10455 for (r = 0; r < rDof; r++) { 10456 a = anchors[rOff + r]; 10457 if (a < sStart || a >= sEnd) continue; 10458 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10459 annz += aDof; 10460 } 10461 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10462 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10463 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10464 } 10465 } else { 10466 annz = 0; 10467 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10468 for (q = 0; q < dof; q++) { 10469 a = anchors[rOff + q]; 10470 if (a < sStart || a >= sEnd) continue; 10471 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10472 annz += aDof; 10473 } 10474 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10475 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10476 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10477 } 10478 } 10479 nnz = i[m]; 10480 PetscCall(PetscMalloc1(nnz, &j)); 10481 offset = 0; 10482 for (p = pStart; p < pEnd; p++) { 10483 if (numFields) { 10484 for (f = 0; f < numFields; f++) { 10485 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10486 for (q = 0; q < dof; q++) { 10487 PetscInt rDof, rOff, r; 10488 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10489 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10490 for (r = 0; r < rDof; r++) { 10491 PetscInt s; 10492 10493 a = anchors[rOff + r]; 10494 if (a < sStart || a >= sEnd) continue; 10495 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10496 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10497 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10498 } 10499 } 10500 } 10501 } else { 10502 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10503 for (q = 0; q < dof; q++) { 10504 PetscInt rDof, rOff, r; 10505 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10506 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10507 for (r = 0; r < rDof; r++) { 10508 PetscInt s; 10509 10510 a = anchors[rOff + r]; 10511 if (a < sStart || a >= sEnd) continue; 10512 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10513 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10514 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10515 } 10516 } 10517 } 10518 } 10519 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10520 PetscCall(PetscFree(i)); 10521 PetscCall(PetscFree(j)); 10522 PetscCall(ISRestoreIndices(aIS, &anchors)); 10523 PetscFunctionReturn(PETSC_SUCCESS); 10524 } 10525 10526 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10527 { 10528 DM_Plex *plex = (DM_Plex *)dm->data; 10529 PetscSection anchorSection, section, cSec; 10530 Mat cMat; 10531 10532 PetscFunctionBegin; 10533 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10534 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10535 if (anchorSection) { 10536 PetscInt Nf; 10537 10538 PetscCall(DMGetLocalSection(dm, §ion)); 10539 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10540 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10541 PetscCall(DMGetNumFields(dm, &Nf)); 10542 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10543 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10544 PetscCall(PetscSectionDestroy(&cSec)); 10545 PetscCall(MatDestroy(&cMat)); 10546 } 10547 PetscFunctionReturn(PETSC_SUCCESS); 10548 } 10549 10550 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10551 { 10552 IS subis; 10553 PetscSection section, subsection; 10554 10555 PetscFunctionBegin; 10556 PetscCall(DMGetLocalSection(dm, §ion)); 10557 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10558 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10559 /* Create subdomain */ 10560 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10561 /* Create submodel */ 10562 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10563 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10564 PetscCall(DMSetLocalSection(*subdm, subsection)); 10565 PetscCall(PetscSectionDestroy(&subsection)); 10566 PetscCall(DMCopyDisc(dm, *subdm)); 10567 /* Create map from submodel to global model */ 10568 if (is) { 10569 PetscSection sectionGlobal, subsectionGlobal; 10570 IS spIS; 10571 const PetscInt *spmap; 10572 PetscInt *subIndices; 10573 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10574 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10575 10576 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10577 PetscCall(ISGetIndices(spIS, &spmap)); 10578 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10579 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10580 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10581 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10582 for (p = pStart; p < pEnd; ++p) { 10583 PetscInt gdof, pSubSize = 0; 10584 10585 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10586 if (gdof > 0) { 10587 for (f = 0; f < Nf; ++f) { 10588 PetscInt fdof, fcdof; 10589 10590 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10591 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10592 pSubSize += fdof - fcdof; 10593 } 10594 subSize += pSubSize; 10595 if (pSubSize) { 10596 if (bs < 0) { 10597 bs = pSubSize; 10598 } else if (bs != pSubSize) { 10599 /* Layout does not admit a pointwise block size */ 10600 bs = 1; 10601 } 10602 } 10603 } 10604 } 10605 /* Must have same blocksize on all procs (some might have no points) */ 10606 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10607 bsLocal[1] = bs; 10608 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10609 if (bsMinMax[0] != bsMinMax[1]) { 10610 bs = 1; 10611 } else { 10612 bs = bsMinMax[0]; 10613 } 10614 PetscCall(PetscMalloc1(subSize, &subIndices)); 10615 for (p = pStart; p < pEnd; ++p) { 10616 PetscInt gdof, goff; 10617 10618 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10619 if (gdof > 0) { 10620 const PetscInt point = spmap[p]; 10621 10622 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10623 for (f = 0; f < Nf; ++f) { 10624 PetscInt fdof, fcdof, fc, f2, poff = 0; 10625 10626 /* Can get rid of this loop by storing field information in the global section */ 10627 for (f2 = 0; f2 < f; ++f2) { 10628 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10629 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10630 poff += fdof - fcdof; 10631 } 10632 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10633 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10634 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10635 } 10636 } 10637 } 10638 PetscCall(ISRestoreIndices(spIS, &spmap)); 10639 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10640 if (bs > 1) { 10641 /* We need to check that the block size does not come from non-contiguous fields */ 10642 PetscInt i, j, set = 1; 10643 for (i = 0; i < subSize; i += bs) { 10644 for (j = 0; j < bs; ++j) { 10645 if (subIndices[i + j] != subIndices[i] + j) { 10646 set = 0; 10647 break; 10648 } 10649 } 10650 } 10651 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10652 } 10653 /* Attach nullspace */ 10654 for (f = 0; f < Nf; ++f) { 10655 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10656 if ((*subdm)->nullspaceConstructors[f]) break; 10657 } 10658 if (f < Nf) { 10659 MatNullSpace nullSpace; 10660 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10661 10662 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10663 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10664 } 10665 } 10666 PetscFunctionReturn(PETSC_SUCCESS); 10667 } 10668 10669 /*@ 10670 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10671 10672 Input Parameters: 10673 + dm - The `DM` 10674 - dummy - unused argument 10675 10676 Options Database Key: 10677 . -dm_plex_monitor_throughput - Activate the monitor 10678 10679 Level: developer 10680 10681 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10682 @*/ 10683 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10684 { 10685 PetscLogHandler default_handler; 10686 10687 PetscFunctionBegin; 10688 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10689 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10690 if (default_handler) { 10691 PetscLogEvent event; 10692 PetscEventPerfInfo eventInfo; 10693 PetscReal cellRate, flopRate; 10694 PetscInt cStart, cEnd, Nf, N; 10695 const char *name; 10696 10697 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10698 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10699 PetscCall(DMGetNumFields(dm, &Nf)); 10700 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10701 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10702 N = (cEnd - cStart) * Nf * eventInfo.count; 10703 flopRate = eventInfo.flops / eventInfo.time; 10704 cellRate = N / eventInfo.time; 10705 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))); 10706 } else { 10707 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."); 10708 } 10709 PetscFunctionReturn(PETSC_SUCCESS); 10710 } 10711