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_INT_MAX, 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 PetscCallMPI(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 PetscCallMPI(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 236 if (globalvcdof[0]) { 237 *sStart = vStart; 238 *sEnd = vEnd; 239 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 240 else *ft = PETSC_VTK_POINT_FIELD; 241 } else if (globalvcdof[1]) { 242 *sStart = cStart; 243 *sEnd = cEnd; 244 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 245 else *ft = PETSC_VTK_CELL_FIELD; 246 } else { 247 if (field >= 0) { 248 const char *fieldname; 249 250 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 251 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 252 } else { 253 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 254 } 255 } 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 DMPlexVecView1D - Plot many 1D solutions on the same line graph 261 262 Collective 263 264 Input Parameters: 265 + dm - The `DMPLEX` object 266 . n - The number of vectors 267 . u - The array of local vectors 268 - viewer - The `PetscViewer` 269 270 Level: advanced 271 272 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 273 @*/ 274 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 275 { 276 PetscDS ds; 277 PetscDraw draw = NULL; 278 PetscDrawLG lg; 279 Vec coordinates; 280 const PetscScalar *coords, **sol; 281 PetscReal *vals; 282 PetscInt *Nc; 283 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 284 char **names; 285 286 PetscFunctionBegin; 287 PetscCall(DMGetDS(dm, &ds)); 288 PetscCall(PetscDSGetNumFields(ds, &Nf)); 289 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 290 PetscCall(PetscDSGetComponents(ds, &Nc)); 291 292 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 293 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 294 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 295 296 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 297 for (i = 0, l = 0; i < n; ++i) { 298 const char *vname; 299 300 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 301 for (f = 0; f < Nf; ++f) { 302 PetscObject disc; 303 const char *fname; 304 char tmpname[PETSC_MAX_PATH_LEN]; 305 306 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 307 /* TODO Create names for components */ 308 for (c = 0; c < Nc[f]; ++c, ++l) { 309 PetscCall(PetscObjectGetName(disc, &fname)); 310 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 312 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 313 PetscCall(PetscStrallocpy(tmpname, &names[l])); 314 } 315 } 316 } 317 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 318 /* Just add P_1 support for now */ 319 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 for (v = vStart; v < vEnd; ++v) { 324 PetscScalar *x, *svals; 325 326 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 327 for (i = 0; i < n; ++i) { 328 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 329 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 330 } 331 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 332 } 333 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 334 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 335 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 336 PetscCall(PetscFree3(sol, names, vals)); 337 338 PetscCall(PetscDrawLGDraw(lg)); 339 PetscCall(PetscDrawLGDestroy(&lg)); 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 343 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 344 { 345 DM dm; 346 347 PetscFunctionBegin; 348 PetscCall(VecGetDM(u, &dm)); 349 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 350 PetscFunctionReturn(PETSC_SUCCESS); 351 } 352 353 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 354 { 355 DM dm; 356 PetscSection s; 357 PetscDraw draw, popup; 358 DM cdm; 359 PetscSection coordSection; 360 Vec coordinates; 361 const PetscScalar *array; 362 PetscReal lbound[3], ubound[3]; 363 PetscReal vbound[2], time; 364 PetscBool flg; 365 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 366 const char *name; 367 char title[PETSC_MAX_PATH_LEN]; 368 369 PetscFunctionBegin; 370 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 371 PetscCall(VecGetDM(v, &dm)); 372 PetscCall(DMGetCoordinateDim(dm, &dim)); 373 PetscCall(DMGetLocalSection(dm, &s)); 374 PetscCall(PetscSectionGetNumFields(s, &Nf)); 375 PetscCall(DMGetCoarsenLevel(dm, &level)); 376 PetscCall(DMGetCoordinateDM(dm, &cdm)); 377 PetscCall(DMGetLocalSection(cdm, &coordSection)); 378 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 379 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 380 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 381 382 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 383 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 384 385 PetscCall(VecGetLocalSize(coordinates, &N)); 386 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 387 PetscCall(PetscDrawClear(draw)); 388 389 /* Could implement something like DMDASelectFields() */ 390 for (f = 0; f < Nf; ++f) { 391 DM fdm = dm; 392 Vec fv = v; 393 IS fis; 394 char prefix[PETSC_MAX_PATH_LEN]; 395 const char *fname; 396 397 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 398 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 399 400 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 401 else prefix[0] = '\0'; 402 if (Nf > 1) { 403 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 404 PetscCall(VecGetSubVector(v, fis, &fv)); 405 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 406 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 407 } 408 for (comp = 0; comp < Nc; ++comp, ++w) { 409 PetscInt nmax = 2; 410 411 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 412 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 413 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 414 PetscCall(PetscDrawSetTitle(draw, title)); 415 416 /* TODO Get max and min only for this component */ 417 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 418 if (!flg) { 419 PetscCall(VecMin(fv, NULL, &vbound[0])); 420 PetscCall(VecMax(fv, NULL, &vbound[1])); 421 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 422 } 423 424 PetscCall(PetscDrawGetPopup(draw, &popup)); 425 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 426 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 427 PetscCall(VecGetArrayRead(fv, &array)); 428 for (c = cStart; c < cEnd; ++c) { 429 DMPolytopeType ct; 430 PetscScalar *coords = NULL, *a = NULL; 431 const PetscScalar *coords_arr; 432 PetscBool isDG; 433 PetscInt numCoords; 434 int color[4] = {-1, -1, -1, -1}; 435 436 PetscCall(DMPlexGetCellType(dm, c, &ct)); 437 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 438 if (a) { 439 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 440 color[1] = color[2] = color[3] = color[0]; 441 } else { 442 PetscScalar *vals = NULL; 443 PetscInt numVals, va; 444 445 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 446 if (!numVals) { 447 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 448 continue; 449 } 450 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); 451 switch (numVals / Nc) { 452 case 1: /* P1 Clamped Segment Prism */ 453 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 454 PetscCheck(ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a tensor segment, but it is a %s", DMPolytopeTypes[ct]); 455 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 456 break; 457 case 3: /* P1 Triangle */ 458 case 4: /* P1 Quadrangle */ 459 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 460 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 461 break; 462 case 6: /* P2 Triangle */ 463 case 8: /* P2 Quadrangle */ 464 PetscCheck(ct == DM_POLYTOPE_TRIANGLE || ct == DM_POLYTOPE_QUADRILATERAL || ct == DM_POLYTOPE_SEG_PRISM_TENSOR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell should be a triangle or quad, but it is a %s", DMPolytopeTypes[ct]); 465 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 466 break; 467 default: 468 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 469 } 470 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 471 } 472 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 473 switch (numCoords) { 474 case 6: 475 case 12: /* Localized triangle */ 476 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])); 477 break; 478 case 8: 479 case 16: /* Localized quadrilateral */ 480 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 481 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 482 } else { 483 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])); 484 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])); 485 } 486 break; 487 default: 488 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 489 } 490 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 491 } 492 PetscCall(VecRestoreArrayRead(fv, &array)); 493 PetscCall(PetscDrawFlush(draw)); 494 PetscCall(PetscDrawPause(draw)); 495 PetscCall(PetscDrawSave(draw)); 496 } 497 if (Nf > 1) { 498 PetscCall(VecRestoreSubVector(v, fis, &fv)); 499 PetscCall(ISDestroy(&fis)); 500 PetscCall(DMDestroy(&fdm)); 501 } 502 } 503 PetscFunctionReturn(PETSC_SUCCESS); 504 } 505 506 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 507 { 508 DM dm; 509 PetscDraw draw; 510 PetscInt dim; 511 PetscBool isnull; 512 513 PetscFunctionBegin; 514 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 515 PetscCall(PetscDrawIsNull(draw, &isnull)); 516 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 517 518 PetscCall(VecGetDM(v, &dm)); 519 PetscCall(DMGetCoordinateDim(dm, &dim)); 520 switch (dim) { 521 case 1: 522 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 523 break; 524 case 2: 525 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 526 break; 527 default: 528 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 529 } 530 PetscFunctionReturn(PETSC_SUCCESS); 531 } 532 533 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 534 { 535 DM dm; 536 Vec locv; 537 const char *name; 538 PetscSection section; 539 PetscInt pStart, pEnd; 540 PetscInt numFields; 541 PetscViewerVTKFieldType ft; 542 543 PetscFunctionBegin; 544 PetscCall(VecGetDM(v, &dm)); 545 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 546 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 547 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 548 PetscCall(VecCopy(v, locv)); 549 PetscCall(DMGetLocalSection(dm, §ion)); 550 PetscCall(PetscSectionGetNumFields(section, &numFields)); 551 if (!numFields) { 552 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 553 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 554 } else { 555 PetscInt f; 556 557 for (f = 0; f < numFields; f++) { 558 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 559 if (ft == PETSC_VTK_INVALID) continue; 560 PetscCall(PetscObjectReference((PetscObject)locv)); 561 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 562 } 563 PetscCall(VecDestroy(&locv)); 564 } 565 PetscFunctionReturn(PETSC_SUCCESS); 566 } 567 568 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 569 { 570 DM dm; 571 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 572 573 PetscFunctionBegin; 574 PetscCall(VecGetDM(v, &dm)); 575 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 576 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 577 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 578 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 579 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 580 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 581 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 582 PetscInt i, numFields; 583 PetscObject fe; 584 PetscBool fem = PETSC_FALSE; 585 Vec locv = v; 586 const char *name; 587 PetscInt step; 588 PetscReal time; 589 590 PetscCall(DMGetNumFields(dm, &numFields)); 591 for (i = 0; i < numFields; i++) { 592 PetscCall(DMGetField(dm, i, NULL, &fe)); 593 if (fe->classid == PETSCFE_CLASSID) { 594 fem = PETSC_TRUE; 595 break; 596 } 597 } 598 if (fem) { 599 PetscObject isZero; 600 601 PetscCall(DMGetLocalVector(dm, &locv)); 602 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 603 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 604 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 605 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 606 PetscCall(VecCopy(v, locv)); 607 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 608 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 609 } 610 if (isvtk) { 611 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 612 } else if (ishdf5) { 613 #if defined(PETSC_HAVE_HDF5) 614 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 615 #else 616 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 617 #endif 618 } else if (isdraw) { 619 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 620 } else if (isglvis) { 621 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 622 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 623 PetscCall(VecView_GLVis(locv, viewer)); 624 } else if (iscgns) { 625 #if defined(PETSC_HAVE_CGNS) 626 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 627 #else 628 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 629 #endif 630 } 631 if (fem) { 632 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 633 PetscCall(DMRestoreLocalVector(dm, &locv)); 634 } 635 } else { 636 PetscBool isseq; 637 638 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 639 if (isseq) PetscCall(VecView_Seq(v, viewer)); 640 else PetscCall(VecView_MPI(v, viewer)); 641 } 642 PetscFunctionReturn(PETSC_SUCCESS); 643 } 644 645 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 646 { 647 DM dm; 648 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 649 650 PetscFunctionBegin; 651 PetscCall(VecGetDM(v, &dm)); 652 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 653 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 654 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 655 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 657 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 658 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 659 if (isvtk || isdraw || isglvis || iscgns) { 660 Vec locv; 661 PetscObject isZero; 662 const char *name; 663 664 PetscCall(DMGetLocalVector(dm, &locv)); 665 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 666 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 667 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 668 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 669 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 670 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 671 PetscCall(VecView_Plex_Local(locv, viewer)); 672 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 673 PetscCall(DMRestoreLocalVector(dm, &locv)); 674 /* Call flush for proper logging of VecView timings */ 675 if (isvtk) PetscCall(PetscViewerFlush(viewer)); 676 } else if (ishdf5) { 677 #if defined(PETSC_HAVE_HDF5) 678 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 679 #else 680 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 681 #endif 682 } else if (isexodusii) { 683 #if defined(PETSC_HAVE_EXODUSII) 684 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 685 #else 686 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 687 #endif 688 } else { 689 PetscBool isseq; 690 691 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 692 if (isseq) PetscCall(VecView_Seq(v, viewer)); 693 else PetscCall(VecView_MPI(v, viewer)); 694 } 695 PetscFunctionReturn(PETSC_SUCCESS); 696 } 697 698 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 699 { 700 DM dm; 701 MPI_Comm comm; 702 PetscViewerFormat format; 703 Vec v; 704 PetscBool isvtk, ishdf5; 705 706 PetscFunctionBegin; 707 PetscCall(VecGetDM(originalv, &dm)); 708 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 709 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 710 PetscCall(PetscViewerGetFormat(viewer, &format)); 711 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 712 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 713 if (format == PETSC_VIEWER_NATIVE) { 714 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 715 /* this need a better fix */ 716 if (dm->useNatural) { 717 if (dm->sfNatural) { 718 const char *vecname; 719 PetscInt n, nroots; 720 721 PetscCall(VecGetLocalSize(originalv, &n)); 722 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 723 if (n == nroots) { 724 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 725 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 726 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 727 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 728 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 729 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 730 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 731 } else v = originalv; 732 } else v = originalv; 733 734 if (ishdf5) { 735 #if defined(PETSC_HAVE_HDF5) 736 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 737 #else 738 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 739 #endif 740 } else if (isvtk) { 741 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 742 } else { 743 PetscBool isseq; 744 745 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 746 if (isseq) PetscCall(VecView_Seq(v, viewer)); 747 else PetscCall(VecView_MPI(v, viewer)); 748 } 749 if (v != originalv) PetscCall(VecDestroy(&v)); 750 PetscFunctionReturn(PETSC_SUCCESS); 751 } 752 753 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 754 { 755 DM dm; 756 PetscBool ishdf5; 757 758 PetscFunctionBegin; 759 PetscCall(VecGetDM(v, &dm)); 760 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 761 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 762 if (ishdf5) { 763 DM dmBC; 764 Vec gv; 765 const char *name; 766 767 PetscCall(DMGetOutputDM(dm, &dmBC)); 768 PetscCall(DMGetGlobalVector(dmBC, &gv)); 769 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 770 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 771 PetscCall(VecLoad_Default(gv, viewer)); 772 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 773 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 774 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 775 } else PetscCall(VecLoad_Default(v, viewer)); 776 PetscFunctionReturn(PETSC_SUCCESS); 777 } 778 779 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 780 { 781 DM dm; 782 PetscBool ishdf5, isexodusii, iscgns; 783 784 PetscFunctionBegin; 785 PetscCall(VecGetDM(v, &dm)); 786 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 787 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 788 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 789 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 790 if (ishdf5) { 791 #if defined(PETSC_HAVE_HDF5) 792 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 793 #else 794 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 795 #endif 796 } else if (isexodusii) { 797 #if defined(PETSC_HAVE_EXODUSII) 798 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 799 #else 800 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 801 #endif 802 } else if (iscgns) { 803 #if defined(PETSC_HAVE_CGNS) 804 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 805 #else 806 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 807 #endif 808 } else PetscCall(VecLoad_Default(v, viewer)); 809 PetscFunctionReturn(PETSC_SUCCESS); 810 } 811 812 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 813 { 814 DM dm; 815 PetscViewerFormat format; 816 PetscBool ishdf5; 817 818 PetscFunctionBegin; 819 PetscCall(VecGetDM(originalv, &dm)); 820 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 821 PetscCall(PetscViewerGetFormat(viewer, &format)); 822 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 823 if (format == PETSC_VIEWER_NATIVE) { 824 if (dm->useNatural) { 825 if (dm->sfNatural) { 826 if (ishdf5) { 827 #if defined(PETSC_HAVE_HDF5) 828 Vec v; 829 const char *vecname; 830 831 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 832 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 833 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 834 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 835 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 836 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 837 PetscCall(VecDestroy(&v)); 838 #else 839 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 840 #endif 841 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 842 } 843 } else PetscCall(VecLoad_Default(originalv, viewer)); 844 } 845 PetscFunctionReturn(PETSC_SUCCESS); 846 } 847 848 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 849 { 850 PetscSection coordSection; 851 Vec coordinates; 852 DMLabel depthLabel, celltypeLabel; 853 const char *name[4]; 854 const PetscScalar *a; 855 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 856 857 PetscFunctionBegin; 858 PetscCall(DMGetDimension(dm, &dim)); 859 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 860 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 861 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 862 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 863 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 864 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 865 PetscCall(VecGetArrayRead(coordinates, &a)); 866 name[0] = "vertex"; 867 name[1] = "edge"; 868 name[dim - 1] = "face"; 869 name[dim] = "cell"; 870 for (c = cStart; c < cEnd; ++c) { 871 PetscInt *closure = NULL; 872 PetscInt closureSize, cl, ct; 873 874 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 875 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 876 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 877 PetscCall(PetscViewerASCIIPushTab(viewer)); 878 for (cl = 0; cl < closureSize * 2; cl += 2) { 879 PetscInt point = closure[cl], depth, dof, off, d, p; 880 881 if ((point < pStart) || (point >= pEnd)) continue; 882 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 883 if (!dof) continue; 884 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 885 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 886 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 887 for (p = 0; p < dof / dim; ++p) { 888 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 889 for (d = 0; d < dim; ++d) { 890 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 891 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 892 } 893 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 894 } 895 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 896 } 897 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 898 PetscCall(PetscViewerASCIIPopTab(viewer)); 899 } 900 PetscCall(VecRestoreArrayRead(coordinates, &a)); 901 PetscFunctionReturn(PETSC_SUCCESS); 902 } 903 904 typedef enum { 905 CS_CARTESIAN, 906 CS_POLAR, 907 CS_CYLINDRICAL, 908 CS_SPHERICAL 909 } CoordSystem; 910 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 911 912 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 913 { 914 PetscInt i; 915 916 PetscFunctionBegin; 917 if (dim > 3) { 918 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 919 } else { 920 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 921 922 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 923 switch (cs) { 924 case CS_CARTESIAN: 925 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 926 break; 927 case CS_POLAR: 928 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 929 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 930 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 931 break; 932 case CS_CYLINDRICAL: 933 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 934 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 935 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 936 trcoords[2] = coords[2]; 937 break; 938 case CS_SPHERICAL: 939 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 940 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 941 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 942 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 943 break; 944 } 945 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 946 } 947 PetscFunctionReturn(PETSC_SUCCESS); 948 } 949 950 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 951 { 952 DM_Plex *mesh = (DM_Plex *)dm->data; 953 DM cdm, cdmCell; 954 PetscSection coordSection, coordSectionCell; 955 Vec coordinates, coordinatesCell; 956 PetscViewerFormat format; 957 958 PetscFunctionBegin; 959 PetscCall(PetscViewerGetFormat(viewer, &format)); 960 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 961 const char *name; 962 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 963 PetscInt pStart, pEnd, p, numLabels, l; 964 PetscMPIInt rank, size; 965 966 PetscCall(DMGetCoordinateDM(dm, &cdm)); 967 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 968 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 969 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 970 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 971 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 972 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 973 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 974 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 975 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 976 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 977 PetscCall(DMGetDimension(dm, &dim)); 978 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 979 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 980 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 981 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 982 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 983 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 984 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 985 for (p = pStart; p < pEnd; ++p) { 986 PetscInt dof, off, s; 987 988 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 989 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 990 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 991 } 992 PetscCall(PetscViewerFlush(viewer)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 994 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 995 for (p = pStart; p < pEnd; ++p) { 996 PetscInt dof, off, c; 997 998 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 999 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1000 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])); 1001 } 1002 PetscCall(PetscViewerFlush(viewer)); 1003 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1004 if (coordSection && coordinates) { 1005 CoordSystem cs = CS_CARTESIAN; 1006 const PetscScalar *array, *arrayCell = NULL; 1007 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1008 PetscMPIInt rank; 1009 const char *name; 1010 1011 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1012 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1013 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1014 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1015 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1016 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1017 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1018 pStart = PetscMin(pvStart, pcStart); 1019 pEnd = PetscMax(pvEnd, pcEnd); 1020 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1023 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1024 1025 PetscCall(VecGetArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1027 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1028 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1029 for (p = pStart; p < pEnd; ++p) { 1030 PetscInt dof, off; 1031 1032 if (p >= pvStart && p < pvEnd) { 1033 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1034 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1035 if (dof) { 1036 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1037 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1038 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1039 } 1040 } 1041 if (cdmCell && p >= pcStart && p < pcEnd) { 1042 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1043 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1044 if (dof) { 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1046 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1048 } 1049 } 1050 } 1051 PetscCall(PetscViewerFlush(viewer)); 1052 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1053 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1054 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1055 } 1056 PetscCall(DMGetNumLabels(dm, &numLabels)); 1057 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1058 for (l = 0; l < numLabels; ++l) { 1059 DMLabel label; 1060 PetscBool isdepth; 1061 const char *name; 1062 1063 PetscCall(DMGetLabelName(dm, l, &name)); 1064 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1065 if (isdepth) continue; 1066 PetscCall(DMGetLabel(dm, name, &label)); 1067 PetscCall(DMLabelView(label, viewer)); 1068 } 1069 if (size > 1) { 1070 PetscSF sf; 1071 1072 PetscCall(DMGetPointSF(dm, &sf)); 1073 PetscCall(PetscSFView(sf, viewer)); 1074 } 1075 if (mesh->periodic.face_sfs) 1076 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1077 PetscCall(PetscViewerFlush(viewer)); 1078 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1079 const char *name, *color; 1080 const char *defcolors[3] = {"gray", "orange", "green"}; 1081 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1082 char lname[PETSC_MAX_PATH_LEN]; 1083 PetscReal scale = 2.0; 1084 PetscReal tikzscale = 1.0; 1085 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1086 double tcoords[3]; 1087 PetscScalar *coords; 1088 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; 1089 PetscMPIInt rank, size; 1090 char **names, **colors, **lcolors; 1091 PetscBool flg, lflg; 1092 PetscBT wp = NULL; 1093 PetscInt pEnd, pStart; 1094 1095 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1096 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1097 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1098 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1099 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1100 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1101 PetscCall(DMGetDimension(dm, &dim)); 1102 PetscCall(DMPlexGetDepth(dm, &depth)); 1103 PetscCall(DMGetNumLabels(dm, &numLabels)); 1104 numLabels = PetscMax(numLabels, 10); 1105 numColors = 10; 1106 numLColors = 10; 1107 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1108 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1109 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1110 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1111 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1112 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1113 n = 4; 1114 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1115 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1116 n = 4; 1117 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1118 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1119 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1120 if (!useLabels) numLabels = 0; 1121 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1122 if (!useColors) { 1123 numColors = 3; 1124 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1125 } 1126 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1127 if (!useColors) { 1128 numLColors = 4; 1129 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1130 } 1131 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1132 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1133 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1134 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1135 if (depth < dim) plotEdges = PETSC_FALSE; 1136 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1137 1138 /* filter points with labelvalue != labeldefaultvalue */ 1139 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1140 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1141 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1142 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1143 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1144 if (lflg) { 1145 DMLabel lbl; 1146 1147 PetscCall(DMGetLabel(dm, lname, &lbl)); 1148 if (lbl) { 1149 PetscInt val, defval; 1150 1151 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1152 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1153 for (c = pStart; c < pEnd; c++) { 1154 PetscInt *closure = NULL; 1155 PetscInt closureSize; 1156 1157 PetscCall(DMLabelGetValue(lbl, c, &val)); 1158 if (val == defval) continue; 1159 1160 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1161 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1162 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1163 } 1164 } 1165 } 1166 1167 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1168 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1169 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1171 \\documentclass[tikz]{standalone}\n\n\ 1172 \\usepackage{pgflibraryshapes}\n\ 1173 \\usetikzlibrary{backgrounds}\n\ 1174 \\usetikzlibrary{arrows}\n\ 1175 \\begin{document}\n")); 1176 if (size > 1) { 1177 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1178 for (p = 0; p < size; ++p) { 1179 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1180 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1181 } 1182 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1183 } 1184 if (drawHasse) { 1185 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1186 1187 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1188 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1189 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1190 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1191 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1192 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1193 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1194 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1195 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1196 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1197 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1198 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1199 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1200 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1201 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1202 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1203 } 1204 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1205 1206 /* Plot vertices */ 1207 PetscCall(VecGetArray(coordinates, &coords)); 1208 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1209 for (v = vStart; v < vEnd; ++v) { 1210 PetscInt off, dof, d; 1211 PetscBool isLabeled = PETSC_FALSE; 1212 1213 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1214 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1215 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1216 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1217 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1218 for (d = 0; d < dof; ++d) { 1219 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1220 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1221 } 1222 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1223 if (dim == 3) { 1224 PetscReal tmp = tcoords[1]; 1225 tcoords[1] = tcoords[2]; 1226 tcoords[2] = -tmp; 1227 } 1228 for (d = 0; d < dof; ++d) { 1229 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1230 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1231 } 1232 if (drawHasse) color = colors[0 % numColors]; 1233 else color = colors[rank % numColors]; 1234 for (l = 0; l < numLabels; ++l) { 1235 PetscInt val; 1236 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1237 if (val >= 0) { 1238 color = lcolors[l % numLColors]; 1239 isLabeled = PETSC_TRUE; 1240 break; 1241 } 1242 } 1243 if (drawNumbers[0]) { 1244 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1245 } else if (drawColors[0]) { 1246 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1247 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1248 } 1249 PetscCall(VecRestoreArray(coordinates, &coords)); 1250 PetscCall(PetscViewerFlush(viewer)); 1251 /* Plot edges */ 1252 if (plotEdges) { 1253 PetscCall(VecGetArray(coordinates, &coords)); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1255 for (e = eStart; e < eEnd; ++e) { 1256 const PetscInt *cone; 1257 PetscInt coneSize, offA, offB, dof, d; 1258 1259 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1260 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1261 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1262 PetscCall(DMPlexGetCone(dm, e, &cone)); 1263 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1264 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1265 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1266 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1267 for (d = 0; d < dof; ++d) { 1268 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1269 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1270 } 1271 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1272 if (dim == 3) { 1273 PetscReal tmp = tcoords[1]; 1274 tcoords[1] = tcoords[2]; 1275 tcoords[2] = -tmp; 1276 } 1277 for (d = 0; d < dof; ++d) { 1278 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1280 } 1281 if (drawHasse) color = colors[1 % numColors]; 1282 else color = colors[rank % numColors]; 1283 for (l = 0; l < numLabels; ++l) { 1284 PetscInt val; 1285 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1286 if (val >= 0) { 1287 color = lcolors[l % numLColors]; 1288 break; 1289 } 1290 } 1291 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1292 } 1293 PetscCall(VecRestoreArray(coordinates, &coords)); 1294 PetscCall(PetscViewerFlush(viewer)); 1295 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1296 } 1297 /* Plot cells */ 1298 if (dim == 3 || !drawNumbers[1]) { 1299 for (e = eStart; e < eEnd; ++e) { 1300 const PetscInt *cone; 1301 1302 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1303 color = colors[rank % numColors]; 1304 for (l = 0; l < numLabels; ++l) { 1305 PetscInt val; 1306 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1307 if (val >= 0) { 1308 color = lcolors[l % numLColors]; 1309 break; 1310 } 1311 } 1312 PetscCall(DMPlexGetCone(dm, e, &cone)); 1313 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1314 } 1315 } else { 1316 DMPolytopeType ct; 1317 1318 /* Drawing a 2D polygon */ 1319 for (c = cStart; c < cEnd; ++c) { 1320 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1321 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1322 if (DMPolytopeTypeIsHybrid(ct)) { 1323 const PetscInt *cone; 1324 PetscInt coneSize, e; 1325 1326 PetscCall(DMPlexGetCone(dm, c, &cone)); 1327 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1328 for (e = 0; e < coneSize; ++e) { 1329 const PetscInt *econe; 1330 1331 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1332 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)); 1333 } 1334 } else { 1335 PetscInt *closure = NULL; 1336 PetscInt closureSize, Nv = 0, v; 1337 1338 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1339 for (p = 0; p < closureSize * 2; p += 2) { 1340 const PetscInt point = closure[p]; 1341 1342 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1343 } 1344 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1345 for (v = 0; v <= Nv; ++v) { 1346 const PetscInt vertex = closure[v % Nv]; 1347 1348 if (v > 0) { 1349 if (plotEdges) { 1350 const PetscInt *edge; 1351 PetscInt endpoints[2], ne; 1352 1353 endpoints[0] = closure[v - 1]; 1354 endpoints[1] = vertex; 1355 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1356 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1357 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1358 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1359 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1360 } 1361 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1362 } 1363 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1364 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1365 } 1366 } 1367 } 1368 for (c = cStart; c < cEnd; ++c) { 1369 double ccoords[3] = {0.0, 0.0, 0.0}; 1370 PetscBool isLabeled = PETSC_FALSE; 1371 PetscScalar *cellCoords = NULL; 1372 const PetscScalar *array; 1373 PetscInt numCoords, cdim, d; 1374 PetscBool isDG; 1375 1376 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1377 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1378 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1379 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1381 for (p = 0; p < numCoords / cdim; ++p) { 1382 for (d = 0; d < cdim; ++d) { 1383 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1384 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1385 } 1386 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1387 if (cdim == 3) { 1388 PetscReal tmp = tcoords[1]; 1389 tcoords[1] = tcoords[2]; 1390 tcoords[2] = -tmp; 1391 } 1392 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1393 } 1394 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1395 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1396 for (d = 0; d < cdim; ++d) { 1397 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1398 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1399 } 1400 if (drawHasse) color = colors[depth % numColors]; 1401 else color = colors[rank % numColors]; 1402 for (l = 0; l < numLabels; ++l) { 1403 PetscInt val; 1404 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1405 if (val >= 0) { 1406 color = lcolors[l % numLColors]; 1407 isLabeled = PETSC_TRUE; 1408 break; 1409 } 1410 } 1411 if (drawNumbers[dim]) { 1412 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1413 } else if (drawColors[dim]) { 1414 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1415 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1416 } 1417 if (drawHasse) { 1418 int height = 0; 1419 1420 color = colors[depth % numColors]; 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1422 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1424 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1425 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1426 1427 if (depth > 2) { 1428 color = colors[1 % numColors]; 1429 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1430 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1431 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1432 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1433 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1434 } 1435 1436 color = colors[1 % numColors]; 1437 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1438 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1439 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1440 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1441 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1442 1443 color = colors[0 % numColors]; 1444 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1445 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1446 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1447 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1448 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1449 1450 for (p = pStart; p < pEnd; ++p) { 1451 const PetscInt *cone; 1452 PetscInt coneSize, cp; 1453 1454 PetscCall(DMPlexGetCone(dm, p, &cone)); 1455 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1456 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1457 } 1458 } 1459 PetscCall(PetscViewerFlush(viewer)); 1460 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1461 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1462 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1463 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1464 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1465 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1466 PetscCall(PetscFree3(names, colors, lcolors)); 1467 PetscCall(PetscBTDestroy(&wp)); 1468 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1469 Vec cown, acown; 1470 VecScatter sct; 1471 ISLocalToGlobalMapping g2l; 1472 IS gid, acis; 1473 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1474 MPI_Group ggroup, ngroup; 1475 PetscScalar *array, nid; 1476 const PetscInt *idxs; 1477 PetscInt *idxs2, *start, *adjacency, *work; 1478 PetscInt64 lm[3], gm[3]; 1479 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1480 PetscMPIInt d1, d2, rank; 1481 1482 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1483 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1484 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1485 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1486 #endif 1487 if (ncomm != MPI_COMM_NULL) { 1488 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1489 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1490 d1 = 0; 1491 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1492 nid = d2; 1493 PetscCallMPI(MPI_Group_free(&ggroup)); 1494 PetscCallMPI(MPI_Group_free(&ngroup)); 1495 PetscCallMPI(MPI_Comm_free(&ncomm)); 1496 } else nid = 0.0; 1497 1498 /* Get connectivity */ 1499 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1500 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1501 1502 /* filter overlapped local cells */ 1503 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1504 PetscCall(ISGetIndices(gid, &idxs)); 1505 PetscCall(ISGetLocalSize(gid, &cum)); 1506 PetscCall(PetscMalloc1(cum, &idxs2)); 1507 for (c = cStart, cum = 0; c < cEnd; c++) { 1508 if (idxs[c - cStart] < 0) continue; 1509 idxs2[cum++] = idxs[c - cStart]; 1510 } 1511 PetscCall(ISRestoreIndices(gid, &idxs)); 1512 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1513 PetscCall(ISDestroy(&gid)); 1514 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1515 1516 /* support for node-aware cell locality */ 1517 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1518 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1519 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1520 PetscCall(VecGetArray(cown, &array)); 1521 for (c = 0; c < numVertices; c++) array[c] = nid; 1522 PetscCall(VecRestoreArray(cown, &array)); 1523 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1524 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1525 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1526 PetscCall(ISDestroy(&acis)); 1527 PetscCall(VecScatterDestroy(&sct)); 1528 PetscCall(VecDestroy(&cown)); 1529 1530 /* compute edgeCut */ 1531 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1532 PetscCall(PetscMalloc1(cum, &work)); 1533 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1534 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1535 PetscCall(ISDestroy(&gid)); 1536 PetscCall(VecGetArray(acown, &array)); 1537 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1538 PetscInt totl; 1539 1540 totl = start[c + 1] - start[c]; 1541 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1542 for (i = 0; i < totl; i++) { 1543 if (work[i] < 0) { 1544 ect += 1; 1545 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1546 } 1547 } 1548 } 1549 PetscCall(PetscFree(work)); 1550 PetscCall(VecRestoreArray(acown, &array)); 1551 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1552 lm[1] = -numVertices; 1553 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1554 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1555 lm[0] = ect; /* edgeCut */ 1556 lm[1] = ectn; /* node-aware edgeCut */ 1557 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1558 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1559 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1560 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1561 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1562 #else 1563 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1564 #endif 1565 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1566 PetscCall(PetscFree(start)); 1567 PetscCall(PetscFree(adjacency)); 1568 PetscCall(VecDestroy(&acown)); 1569 } else { 1570 const char *name; 1571 PetscInt *sizes, *hybsizes, *ghostsizes; 1572 PetscInt locDepth, depth, cellHeight, dim, d; 1573 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1574 PetscInt numLabels, l, maxSize = 17; 1575 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1576 MPI_Comm comm; 1577 PetscMPIInt size, rank; 1578 1579 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1580 PetscCallMPI(MPI_Comm_size(comm, &size)); 1581 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1582 PetscCall(DMGetDimension(dm, &dim)); 1583 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1584 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1585 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1586 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1587 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1588 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1589 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1590 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1591 gcNum = gcEnd - gcStart; 1592 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1593 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1594 for (d = 0; d <= depth; d++) { 1595 PetscInt Nc[2] = {0, 0}, ict; 1596 1597 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1598 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1599 ict = ct0; 1600 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1601 ct0 = (DMPolytopeType)ict; 1602 for (p = pStart; p < pEnd; ++p) { 1603 DMPolytopeType ct; 1604 1605 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1606 if (ct == ct0) ++Nc[0]; 1607 else ++Nc[1]; 1608 } 1609 if (size < maxSize) { 1610 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1611 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1612 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1613 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1614 for (p = 0; p < size; ++p) { 1615 if (rank == 0) { 1616 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1617 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1618 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1619 } 1620 } 1621 } else { 1622 PetscInt locMinMax[2]; 1623 1624 locMinMax[0] = Nc[0] + Nc[1]; 1625 locMinMax[1] = Nc[0] + Nc[1]; 1626 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1627 locMinMax[0] = Nc[1]; 1628 locMinMax[1] = Nc[1]; 1629 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1630 if (d == depth) { 1631 locMinMax[0] = gcNum; 1632 locMinMax[1] = gcNum; 1633 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1634 } 1635 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1636 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1637 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1638 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1639 } 1640 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1641 } 1642 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1643 { 1644 const PetscReal *maxCell; 1645 const PetscReal *L; 1646 PetscBool localized; 1647 1648 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1649 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1650 if (L || localized) { 1651 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1652 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1653 if (L) { 1654 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1655 for (d = 0; d < dim; ++d) { 1656 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1657 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1658 } 1659 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1660 } 1661 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1662 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1663 } 1664 } 1665 PetscCall(DMGetNumLabels(dm, &numLabels)); 1666 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1667 for (l = 0; l < numLabels; ++l) { 1668 DMLabel label; 1669 const char *name; 1670 PetscInt *values; 1671 PetscInt numValues, v; 1672 1673 PetscCall(DMGetLabelName(dm, l, &name)); 1674 PetscCall(DMGetLabel(dm, name, &label)); 1675 PetscCall(DMLabelGetNumValues(label, &numValues)); 1676 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1677 1678 { // Extract array of DMLabel values so it can be sorted 1679 IS is_values; 1680 const PetscInt *is_values_local = NULL; 1681 1682 PetscCall(DMLabelGetValueIS(label, &is_values)); 1683 PetscCall(ISGetIndices(is_values, &is_values_local)); 1684 PetscCall(PetscMalloc1(numValues, &values)); 1685 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1686 PetscCall(PetscSortInt(numValues, values)); 1687 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1688 PetscCall(ISDestroy(&is_values)); 1689 } 1690 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1691 for (v = 0; v < numValues; ++v) { 1692 PetscInt size; 1693 1694 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1695 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1696 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1697 } 1698 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1699 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1700 PetscCall(PetscFree(values)); 1701 } 1702 { 1703 char **labelNames; 1704 PetscInt Nl = numLabels; 1705 PetscBool flg; 1706 1707 PetscCall(PetscMalloc1(Nl, &labelNames)); 1708 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1709 for (l = 0; l < Nl; ++l) { 1710 DMLabel label; 1711 1712 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1713 if (flg) { 1714 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1715 PetscCall(DMLabelView(label, viewer)); 1716 } 1717 PetscCall(PetscFree(labelNames[l])); 1718 } 1719 PetscCall(PetscFree(labelNames)); 1720 } 1721 /* If no fields are specified, people do not want to see adjacency */ 1722 if (dm->Nf) { 1723 PetscInt f; 1724 1725 for (f = 0; f < dm->Nf; ++f) { 1726 const char *name; 1727 1728 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1729 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1730 PetscCall(PetscViewerASCIIPushTab(viewer)); 1731 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1732 if (dm->fields[f].adjacency[0]) { 1733 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1734 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1735 } else { 1736 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1737 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1738 } 1739 PetscCall(PetscViewerASCIIPopTab(viewer)); 1740 } 1741 } 1742 PetscCall(DMGetCoarseDM(dm, &cdm)); 1743 if (cdm) { 1744 PetscCall(PetscViewerASCIIPushTab(viewer)); 1745 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1746 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1747 PetscCall(PetscViewerASCIIPopTab(viewer)); 1748 } 1749 } 1750 PetscFunctionReturn(PETSC_SUCCESS); 1751 } 1752 1753 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1754 { 1755 DMPolytopeType ct; 1756 PetscMPIInt rank; 1757 PetscInt cdim; 1758 1759 PetscFunctionBegin; 1760 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1761 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1762 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1763 switch (ct) { 1764 case DM_POLYTOPE_SEGMENT: 1765 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1766 switch (cdim) { 1767 case 1: { 1768 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1769 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1770 1771 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1772 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1773 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1774 } break; 1775 case 2: { 1776 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1777 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1778 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1779 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[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1782 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)); 1783 } break; 1784 default: 1785 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1786 } 1787 break; 1788 case DM_POLYTOPE_TRIANGLE: 1789 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)); 1790 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1791 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1792 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1793 break; 1794 case DM_POLYTOPE_QUADRILATERAL: 1795 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)); 1796 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)); 1797 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1798 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1799 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1800 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1801 break; 1802 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1803 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)); 1804 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)); 1805 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1806 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1807 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1808 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1809 break; 1810 case DM_POLYTOPE_FV_GHOST: 1811 break; 1812 default: 1813 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1814 } 1815 PetscFunctionReturn(PETSC_SUCCESS); 1816 } 1817 1818 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1819 { 1820 PetscReal centroid[2] = {0., 0.}; 1821 PetscMPIInt rank; 1822 PetscMPIInt fillColor; 1823 1824 PetscFunctionBegin; 1825 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1826 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1827 for (PetscInt v = 0; v < Nv; ++v) { 1828 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1829 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1830 } 1831 for (PetscInt e = 0; e < Nv; ++e) { 1832 refCoords[0] = refVertices[e * 2 + 0]; 1833 refCoords[1] = refVertices[e * 2 + 1]; 1834 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1835 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1836 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1837 } 1838 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1839 for (PetscInt d = 0; d < edgeDiv; ++d) { 1840 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)); 1841 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1842 } 1843 } 1844 PetscFunctionReturn(PETSC_SUCCESS); 1845 } 1846 1847 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1848 { 1849 DMPolytopeType ct; 1850 1851 PetscFunctionBegin; 1852 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1853 switch (ct) { 1854 case DM_POLYTOPE_TRIANGLE: { 1855 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1856 1857 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1858 } break; 1859 case DM_POLYTOPE_QUADRILATERAL: { 1860 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1861 1862 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1863 } break; 1864 default: 1865 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1866 } 1867 PetscFunctionReturn(PETSC_SUCCESS); 1868 } 1869 1870 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1871 { 1872 PetscDraw draw; 1873 DM cdm; 1874 PetscSection coordSection; 1875 Vec coordinates; 1876 PetscReal xyl[3], xyr[3]; 1877 PetscReal *refCoords, *edgeCoords; 1878 PetscBool isnull, drawAffine; 1879 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1880 1881 PetscFunctionBegin; 1882 PetscCall(DMGetCoordinateDim(dm, &dim)); 1883 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1884 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1885 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1886 edgeDiv = cDegree + 1; 1887 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1888 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1889 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1890 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1891 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1892 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1893 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1894 1895 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1896 PetscCall(PetscDrawIsNull(draw, &isnull)); 1897 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1898 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1899 1900 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1901 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1902 PetscCall(PetscDrawClear(draw)); 1903 1904 for (c = cStart; c < cEnd; ++c) { 1905 PetscScalar *coords = NULL; 1906 const PetscScalar *coords_arr; 1907 PetscInt numCoords; 1908 PetscBool isDG; 1909 1910 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1911 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1912 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1913 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1914 } 1915 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1916 PetscCall(PetscDrawFlush(draw)); 1917 PetscCall(PetscDrawPause(draw)); 1918 PetscCall(PetscDrawSave(draw)); 1919 PetscFunctionReturn(PETSC_SUCCESS); 1920 } 1921 1922 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1923 { 1924 DM odm = dm, rdm = dm, cdm; 1925 PetscFE fe; 1926 PetscSpace sp; 1927 PetscClassId id; 1928 PetscInt degree; 1929 PetscBool hoView = PETSC_TRUE; 1930 1931 PetscFunctionBegin; 1932 PetscObjectOptionsBegin((PetscObject)dm); 1933 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1934 PetscOptionsEnd(); 1935 PetscCall(PetscObjectReference((PetscObject)dm)); 1936 *hdm = dm; 1937 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1939 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1940 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1941 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1942 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1943 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1944 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1945 DM cdm, rcdm; 1946 Mat In; 1947 Vec cl, rcl; 1948 1949 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1950 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1951 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1952 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1953 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1954 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1955 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1956 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1957 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1958 PetscCall(MatMult(In, cl, rcl)); 1959 PetscCall(MatDestroy(&In)); 1960 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1961 PetscCall(DMDestroy(&odm)); 1962 odm = rdm; 1963 } 1964 *hdm = rdm; 1965 PetscFunctionReturn(PETSC_SUCCESS); 1966 } 1967 1968 #if defined(PETSC_HAVE_EXODUSII) 1969 #include <exodusII.h> 1970 #include <petscviewerexodusii.h> 1971 #endif 1972 1973 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1974 { 1975 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1976 char name[PETSC_MAX_PATH_LEN]; 1977 1978 PetscFunctionBegin; 1979 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1980 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1981 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1982 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1983 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1984 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1985 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1986 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1987 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1988 if (iascii) { 1989 PetscViewerFormat format; 1990 PetscCall(PetscViewerGetFormat(viewer, &format)); 1991 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1992 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1993 } else if (ishdf5) { 1994 #if defined(PETSC_HAVE_HDF5) 1995 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1996 #else 1997 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1998 #endif 1999 } else if (isvtk) { 2000 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2001 } else if (isdraw) { 2002 DM hdm; 2003 2004 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2005 PetscCall(DMPlexView_Draw(hdm, viewer)); 2006 PetscCall(DMDestroy(&hdm)); 2007 } else if (isglvis) { 2008 PetscCall(DMPlexView_GLVis(dm, viewer)); 2009 #if defined(PETSC_HAVE_EXODUSII) 2010 } else if (isexodus) { 2011 /* 2012 exodusII requires that all sets be part of exactly one cell set. 2013 If the dm does not have a "Cell Sets" label defined, we create one 2014 with ID 1, containing all cells. 2015 Note that if the Cell Sets label is defined but does not cover all cells, 2016 we may still have a problem. This should probably be checked here or in the viewer; 2017 */ 2018 PetscInt numCS; 2019 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2020 if (!numCS) { 2021 PetscInt cStart, cEnd, c; 2022 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2023 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2024 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2025 } 2026 PetscCall(DMView_PlexExodusII(dm, viewer)); 2027 #endif 2028 #if defined(PETSC_HAVE_CGNS) 2029 } else if (iscgns) { 2030 PetscCall(DMView_PlexCGNS(dm, viewer)); 2031 #endif 2032 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2033 /* Optionally view the partition */ 2034 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2035 if (flg) { 2036 Vec ranks; 2037 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2038 PetscCall(VecView(ranks, viewer)); 2039 PetscCall(VecDestroy(&ranks)); 2040 } 2041 /* Optionally view a label */ 2042 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2043 if (flg) { 2044 DMLabel label; 2045 Vec val; 2046 2047 PetscCall(DMGetLabel(dm, name, &label)); 2048 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2049 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2050 PetscCall(VecView(val, viewer)); 2051 PetscCall(VecDestroy(&val)); 2052 } 2053 PetscFunctionReturn(PETSC_SUCCESS); 2054 } 2055 2056 /*@ 2057 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2058 2059 Collective 2060 2061 Input Parameters: 2062 + dm - The `DM` whose topology is to be saved 2063 - viewer - The `PetscViewer` to save it in 2064 2065 Level: advanced 2066 2067 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2068 @*/ 2069 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2070 { 2071 PetscBool ishdf5; 2072 2073 PetscFunctionBegin; 2074 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2075 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2076 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2077 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2078 if (ishdf5) { 2079 #if defined(PETSC_HAVE_HDF5) 2080 PetscViewerFormat format; 2081 PetscCall(PetscViewerGetFormat(viewer, &format)); 2082 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2083 IS globalPointNumbering; 2084 2085 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2086 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2087 PetscCall(ISDestroy(&globalPointNumbering)); 2088 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2089 #else 2090 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2091 #endif 2092 } 2093 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2094 PetscFunctionReturn(PETSC_SUCCESS); 2095 } 2096 2097 /*@ 2098 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2099 2100 Collective 2101 2102 Input Parameters: 2103 + dm - The `DM` whose coordinates are to be saved 2104 - viewer - The `PetscViewer` for saving 2105 2106 Level: advanced 2107 2108 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2109 @*/ 2110 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2111 { 2112 PetscBool ishdf5; 2113 2114 PetscFunctionBegin; 2115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2116 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2117 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2118 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2119 if (ishdf5) { 2120 #if defined(PETSC_HAVE_HDF5) 2121 PetscViewerFormat format; 2122 PetscCall(PetscViewerGetFormat(viewer, &format)); 2123 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2124 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2125 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2126 #else 2127 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2128 #endif 2129 } 2130 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2131 PetscFunctionReturn(PETSC_SUCCESS); 2132 } 2133 2134 /*@ 2135 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2136 2137 Collective 2138 2139 Input Parameters: 2140 + dm - The `DM` whose labels are to be saved 2141 - viewer - The `PetscViewer` for saving 2142 2143 Level: advanced 2144 2145 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2146 @*/ 2147 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2148 { 2149 PetscBool ishdf5; 2150 2151 PetscFunctionBegin; 2152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2153 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2154 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2155 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2156 if (ishdf5) { 2157 #if defined(PETSC_HAVE_HDF5) 2158 IS globalPointNumbering; 2159 PetscViewerFormat format; 2160 2161 PetscCall(PetscViewerGetFormat(viewer, &format)); 2162 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2163 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2164 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2165 PetscCall(ISDestroy(&globalPointNumbering)); 2166 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2167 #else 2168 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2169 #endif 2170 } 2171 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2172 PetscFunctionReturn(PETSC_SUCCESS); 2173 } 2174 2175 /*@ 2176 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2177 2178 Collective 2179 2180 Input Parameters: 2181 + dm - The `DM` that contains the topology on which the section to be saved is defined 2182 . viewer - The `PetscViewer` for saving 2183 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2184 2185 Level: advanced 2186 2187 Notes: 2188 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. 2189 2190 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. 2191 2192 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2193 @*/ 2194 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2195 { 2196 PetscBool ishdf5; 2197 2198 PetscFunctionBegin; 2199 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2200 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2201 if (!sectiondm) sectiondm = dm; 2202 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2203 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2204 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2205 if (ishdf5) { 2206 #if defined(PETSC_HAVE_HDF5) 2207 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2208 #else 2209 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2210 #endif 2211 } 2212 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2213 PetscFunctionReturn(PETSC_SUCCESS); 2214 } 2215 2216 /*@ 2217 DMPlexGlobalVectorView - Saves a global vector 2218 2219 Collective 2220 2221 Input Parameters: 2222 + dm - The `DM` that represents the topology 2223 . viewer - The `PetscViewer` to save data with 2224 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2225 - vec - The global vector to be saved 2226 2227 Level: advanced 2228 2229 Notes: 2230 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. 2231 2232 Calling sequence: 2233 .vb 2234 DMCreate(PETSC_COMM_WORLD, &dm); 2235 DMSetType(dm, DMPLEX); 2236 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2237 DMClone(dm, §iondm); 2238 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2239 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2240 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2241 PetscSectionSetChart(section, pStart, pEnd); 2242 PetscSectionSetUp(section); 2243 DMSetLocalSection(sectiondm, section); 2244 PetscSectionDestroy(§ion); 2245 DMGetGlobalVector(sectiondm, &vec); 2246 PetscObjectSetName((PetscObject)vec, "vec_name"); 2247 DMPlexTopologyView(dm, viewer); 2248 DMPlexSectionView(dm, viewer, sectiondm); 2249 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2250 DMRestoreGlobalVector(sectiondm, &vec); 2251 DMDestroy(§iondm); 2252 DMDestroy(&dm); 2253 .ve 2254 2255 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2256 @*/ 2257 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2258 { 2259 PetscBool ishdf5; 2260 2261 PetscFunctionBegin; 2262 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2263 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2264 if (!sectiondm) sectiondm = dm; 2265 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2266 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2267 /* Check consistency */ 2268 { 2269 PetscSection section; 2270 PetscBool includesConstraints; 2271 PetscInt m, m1; 2272 2273 PetscCall(VecGetLocalSize(vec, &m1)); 2274 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2275 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2276 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2277 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2278 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2279 } 2280 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2281 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2282 if (ishdf5) { 2283 #if defined(PETSC_HAVE_HDF5) 2284 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2285 #else 2286 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2287 #endif 2288 } 2289 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2290 PetscFunctionReturn(PETSC_SUCCESS); 2291 } 2292 2293 /*@ 2294 DMPlexLocalVectorView - Saves a local vector 2295 2296 Collective 2297 2298 Input Parameters: 2299 + dm - The `DM` that represents the topology 2300 . viewer - The `PetscViewer` to save data with 2301 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2302 - vec - The local vector to be saved 2303 2304 Level: advanced 2305 2306 Note: 2307 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. 2308 2309 Calling sequence: 2310 .vb 2311 DMCreate(PETSC_COMM_WORLD, &dm); 2312 DMSetType(dm, DMPLEX); 2313 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2314 DMClone(dm, §iondm); 2315 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2316 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2317 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2318 PetscSectionSetChart(section, pStart, pEnd); 2319 PetscSectionSetUp(section); 2320 DMSetLocalSection(sectiondm, section); 2321 DMGetLocalVector(sectiondm, &vec); 2322 PetscObjectSetName((PetscObject)vec, "vec_name"); 2323 DMPlexTopologyView(dm, viewer); 2324 DMPlexSectionView(dm, viewer, sectiondm); 2325 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2326 DMRestoreLocalVector(sectiondm, &vec); 2327 DMDestroy(§iondm); 2328 DMDestroy(&dm); 2329 .ve 2330 2331 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2332 @*/ 2333 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2334 { 2335 PetscBool ishdf5; 2336 2337 PetscFunctionBegin; 2338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2339 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2340 if (!sectiondm) sectiondm = dm; 2341 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2342 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2343 /* Check consistency */ 2344 { 2345 PetscSection section; 2346 PetscBool includesConstraints; 2347 PetscInt m, m1; 2348 2349 PetscCall(VecGetLocalSize(vec, &m1)); 2350 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2351 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2352 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2353 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2354 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2355 } 2356 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2357 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2358 if (ishdf5) { 2359 #if defined(PETSC_HAVE_HDF5) 2360 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2361 #else 2362 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2363 #endif 2364 } 2365 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2366 PetscFunctionReturn(PETSC_SUCCESS); 2367 } 2368 2369 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2370 { 2371 PetscBool ishdf5; 2372 2373 PetscFunctionBegin; 2374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2375 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2376 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2377 if (ishdf5) { 2378 #if defined(PETSC_HAVE_HDF5) 2379 PetscViewerFormat format; 2380 PetscCall(PetscViewerGetFormat(viewer, &format)); 2381 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2382 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2383 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2384 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2385 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2386 PetscFunctionReturn(PETSC_SUCCESS); 2387 #else 2388 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2389 #endif 2390 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2391 } 2392 2393 /*@ 2394 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2395 2396 Collective 2397 2398 Input Parameters: 2399 + dm - The `DM` into which the topology is loaded 2400 - viewer - The `PetscViewer` for the saved topology 2401 2402 Output Parameter: 2403 . 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; 2404 `NULL` if unneeded 2405 2406 Level: advanced 2407 2408 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2409 `PetscViewer`, `PetscSF` 2410 @*/ 2411 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2412 { 2413 PetscBool ishdf5; 2414 2415 PetscFunctionBegin; 2416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2417 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2418 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2419 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2420 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2421 if (ishdf5) { 2422 #if defined(PETSC_HAVE_HDF5) 2423 PetscViewerFormat format; 2424 PetscCall(PetscViewerGetFormat(viewer, &format)); 2425 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2426 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2427 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2428 #else 2429 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2430 #endif 2431 } 2432 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2433 PetscFunctionReturn(PETSC_SUCCESS); 2434 } 2435 2436 /*@ 2437 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2438 2439 Collective 2440 2441 Input Parameters: 2442 + dm - The `DM` into which the coordinates are loaded 2443 . viewer - The `PetscViewer` for the saved coordinates 2444 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2445 2446 Level: advanced 2447 2448 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2449 `PetscSF`, `PetscViewer` 2450 @*/ 2451 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2452 { 2453 PetscBool ishdf5; 2454 2455 PetscFunctionBegin; 2456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2457 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2458 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2459 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2460 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2461 if (ishdf5) { 2462 #if defined(PETSC_HAVE_HDF5) 2463 PetscViewerFormat format; 2464 PetscCall(PetscViewerGetFormat(viewer, &format)); 2465 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2466 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2467 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2468 #else 2469 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2470 #endif 2471 } 2472 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2473 PetscFunctionReturn(PETSC_SUCCESS); 2474 } 2475 2476 /*@ 2477 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2478 2479 Collective 2480 2481 Input Parameters: 2482 + dm - The `DM` into which the labels are loaded 2483 . viewer - The `PetscViewer` for the saved labels 2484 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2485 2486 Level: advanced 2487 2488 Note: 2489 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2490 2491 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2492 `PetscSF`, `PetscViewer` 2493 @*/ 2494 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2495 { 2496 PetscBool ishdf5; 2497 2498 PetscFunctionBegin; 2499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2500 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2501 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2502 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2503 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2504 if (ishdf5) { 2505 #if defined(PETSC_HAVE_HDF5) 2506 PetscViewerFormat format; 2507 2508 PetscCall(PetscViewerGetFormat(viewer, &format)); 2509 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2510 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2511 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2512 #else 2513 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2514 #endif 2515 } 2516 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2517 PetscFunctionReturn(PETSC_SUCCESS); 2518 } 2519 2520 /*@ 2521 DMPlexSectionLoad - Loads section into a `DMPLEX` 2522 2523 Collective 2524 2525 Input Parameters: 2526 + dm - The `DM` that represents the topology 2527 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2528 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2529 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2530 2531 Output Parameters: 2532 + 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) 2533 - 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) 2534 2535 Level: advanced 2536 2537 Notes: 2538 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. 2539 2540 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. 2541 2542 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. 2543 2544 Example using 2 processes: 2545 .vb 2546 NX (number of points on dm): 4 2547 sectionA : the on-disk section 2548 vecA : a vector associated with sectionA 2549 sectionB : sectiondm's local section constructed in this function 2550 vecB (local) : a vector associated with sectiondm's local section 2551 vecB (global) : a vector associated with sectiondm's global section 2552 2553 rank 0 rank 1 2554 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2555 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2556 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2557 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2558 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2559 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2560 sectionB->atlasDof : 1 0 1 | 1 3 2561 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2562 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2563 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2564 .ve 2565 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2566 2567 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2568 @*/ 2569 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2570 { 2571 PetscBool ishdf5; 2572 2573 PetscFunctionBegin; 2574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2575 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2576 if (!sectiondm) sectiondm = dm; 2577 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2578 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2579 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2580 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2581 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2582 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2583 if (ishdf5) { 2584 #if defined(PETSC_HAVE_HDF5) 2585 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2586 #else 2587 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2588 #endif 2589 } 2590 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2591 PetscFunctionReturn(PETSC_SUCCESS); 2592 } 2593 2594 /*@ 2595 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2596 2597 Collective 2598 2599 Input Parameters: 2600 + dm - The `DM` that represents the topology 2601 . viewer - The `PetscViewer` that represents the on-disk vector data 2602 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2603 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2604 - vec - The global vector to set values of 2605 2606 Level: advanced 2607 2608 Notes: 2609 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. 2610 2611 Calling sequence: 2612 .vb 2613 DMCreate(PETSC_COMM_WORLD, &dm); 2614 DMSetType(dm, DMPLEX); 2615 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2616 DMPlexTopologyLoad(dm, viewer, &sfX); 2617 DMClone(dm, §iondm); 2618 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2619 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2620 DMGetGlobalVector(sectiondm, &vec); 2621 PetscObjectSetName((PetscObject)vec, "vec_name"); 2622 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2623 DMRestoreGlobalVector(sectiondm, &vec); 2624 PetscSFDestroy(&gsf); 2625 PetscSFDestroy(&sfX); 2626 DMDestroy(§iondm); 2627 DMDestroy(&dm); 2628 .ve 2629 2630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2631 `PetscSF`, `PetscViewer` 2632 @*/ 2633 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2634 { 2635 PetscBool ishdf5; 2636 2637 PetscFunctionBegin; 2638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2639 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2640 if (!sectiondm) sectiondm = dm; 2641 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2642 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2643 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2644 /* Check consistency */ 2645 { 2646 PetscSection section; 2647 PetscBool includesConstraints; 2648 PetscInt m, m1; 2649 2650 PetscCall(VecGetLocalSize(vec, &m1)); 2651 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2652 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2653 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2654 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2655 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2656 } 2657 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2658 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2659 if (ishdf5) { 2660 #if defined(PETSC_HAVE_HDF5) 2661 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2662 #else 2663 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2664 #endif 2665 } 2666 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2667 PetscFunctionReturn(PETSC_SUCCESS); 2668 } 2669 2670 /*@ 2671 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2672 2673 Collective 2674 2675 Input Parameters: 2676 + dm - The `DM` that represents the topology 2677 . viewer - The `PetscViewer` that represents the on-disk vector data 2678 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2679 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2680 - vec - The local vector to set values of 2681 2682 Level: advanced 2683 2684 Notes: 2685 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. 2686 2687 Calling sequence: 2688 .vb 2689 DMCreate(PETSC_COMM_WORLD, &dm); 2690 DMSetType(dm, DMPLEX); 2691 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2692 DMPlexTopologyLoad(dm, viewer, &sfX); 2693 DMClone(dm, §iondm); 2694 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2695 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2696 DMGetLocalVector(sectiondm, &vec); 2697 PetscObjectSetName((PetscObject)vec, "vec_name"); 2698 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2699 DMRestoreLocalVector(sectiondm, &vec); 2700 PetscSFDestroy(&lsf); 2701 PetscSFDestroy(&sfX); 2702 DMDestroy(§iondm); 2703 DMDestroy(&dm); 2704 .ve 2705 2706 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2707 `PetscSF`, `PetscViewer` 2708 @*/ 2709 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2710 { 2711 PetscBool ishdf5; 2712 2713 PetscFunctionBegin; 2714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2715 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2716 if (!sectiondm) sectiondm = dm; 2717 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2718 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2719 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2720 /* Check consistency */ 2721 { 2722 PetscSection section; 2723 PetscBool includesConstraints; 2724 PetscInt m, m1; 2725 2726 PetscCall(VecGetLocalSize(vec, &m1)); 2727 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2728 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2729 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2730 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2731 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2732 } 2733 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2734 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2735 if (ishdf5) { 2736 #if defined(PETSC_HAVE_HDF5) 2737 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2738 #else 2739 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2740 #endif 2741 } 2742 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2743 PetscFunctionReturn(PETSC_SUCCESS); 2744 } 2745 2746 PetscErrorCode DMDestroy_Plex(DM dm) 2747 { 2748 DM_Plex *mesh = (DM_Plex *)dm->data; 2749 2750 PetscFunctionBegin; 2751 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2753 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2754 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2755 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2756 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2757 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2758 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2759 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2760 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2761 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2762 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2763 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2764 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2765 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2766 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2767 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2768 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2769 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2770 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2771 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2772 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2773 PetscCall(PetscFree(mesh->cones)); 2774 PetscCall(PetscFree(mesh->coneOrientations)); 2775 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2776 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2777 PetscCall(PetscFree(mesh->supports)); 2778 PetscCall(PetscFree(mesh->cellTypes)); 2779 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2780 PetscCall(PetscFree(mesh->tetgenOpts)); 2781 PetscCall(PetscFree(mesh->triangleOpts)); 2782 PetscCall(PetscFree(mesh->transformType)); 2783 PetscCall(PetscFree(mesh->distributionName)); 2784 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2785 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2786 PetscCall(ISDestroy(&mesh->subpointIS)); 2787 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2788 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2789 if (mesh->periodic.face_sfs) { 2790 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2791 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2792 } 2793 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2794 if (mesh->periodic.periodic_points) { 2795 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2796 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2797 } 2798 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2799 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2800 PetscCall(ISDestroy(&mesh->anchorIS)); 2801 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2802 PetscCall(PetscFree(mesh->parents)); 2803 PetscCall(PetscFree(mesh->childIDs)); 2804 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2805 PetscCall(PetscFree(mesh->children)); 2806 PetscCall(DMDestroy(&mesh->referenceTree)); 2807 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2808 PetscCall(PetscFree(mesh->neighbors)); 2809 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2810 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2811 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2812 PetscCall(PetscFree(mesh)); 2813 PetscFunctionReturn(PETSC_SUCCESS); 2814 } 2815 2816 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2817 { 2818 PetscSection sectionGlobal, sectionLocal; 2819 PetscInt bs = -1, mbs; 2820 PetscInt localSize, localStart = 0; 2821 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2822 MatType mtype; 2823 ISLocalToGlobalMapping ltog; 2824 2825 PetscFunctionBegin; 2826 PetscCall(MatInitializePackage()); 2827 mtype = dm->mattype; 2828 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2829 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2830 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2831 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2832 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2833 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2834 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2835 PetscCall(MatSetType(*J, mtype)); 2836 PetscCall(MatSetFromOptions(*J)); 2837 PetscCall(MatGetBlockSize(*J, &mbs)); 2838 if (mbs > 1) bs = mbs; 2839 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2840 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2841 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2842 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2843 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2844 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2845 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2846 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2847 if (!isShell) { 2848 // There are three states with pblocks, since block starts can have no dofs: 2849 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2850 // TRUE) Block Start: The first entry in a block has been added 2851 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2852 PetscBT blst; 2853 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2854 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2855 const PetscInt *perm = NULL; 2856 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2857 PetscInt pStart, pEnd, dof, cdof, num_fields; 2858 2859 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2860 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2861 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2862 2863 PetscCall(PetscCalloc1(localSize, &pblocks)); 2864 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2865 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2866 // We need to process in the permuted order to get block sizes right 2867 for (PetscInt point = pStart; point < pEnd; ++point) { 2868 const PetscInt p = perm ? perm[point] : point; 2869 2870 switch (dm->blocking_type) { 2871 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2872 PetscInt bdof, offset; 2873 2874 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2875 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2876 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2877 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2878 if (dof > 0) { 2879 // State change 2880 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2881 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2882 2883 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2884 // Signal block concatenation 2885 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2886 } 2887 dof = dof < 0 ? -(dof + 1) : dof; 2888 bdof = cdof && (dof - cdof) ? 1 : dof; 2889 if (dof) { 2890 if (bs < 0) { 2891 bs = bdof; 2892 } else if (bs != bdof) { 2893 bs = 1; 2894 } 2895 } 2896 } break; 2897 case DM_BLOCKING_FIELD_NODE: { 2898 for (PetscInt field = 0; field < num_fields; field++) { 2899 PetscInt num_comp, bdof, offset; 2900 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2901 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2902 if (dof < 0) continue; 2903 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2904 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2905 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); 2906 PetscInt num_nodes = dof / num_comp; 2907 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2908 // Handle possibly constant block size (unlikely) 2909 bdof = cdof && (dof - cdof) ? 1 : dof; 2910 if (dof) { 2911 if (bs < 0) { 2912 bs = bdof; 2913 } else if (bs != bdof) { 2914 bs = 1; 2915 } 2916 } 2917 } 2918 } break; 2919 } 2920 } 2921 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2922 /* Must have same blocksize on all procs (some might have no points) */ 2923 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2924 bsLocal[1] = bs; 2925 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2926 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2927 else bs = bsMinMax[0]; 2928 bs = PetscMax(1, bs); 2929 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2930 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2931 PetscCall(MatSetBlockSize(*J, bs)); 2932 PetscCall(MatSetUp(*J)); 2933 } else { 2934 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2935 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2936 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2937 } 2938 if (pblocks) { // Consolidate blocks 2939 PetscInt nblocks = 0; 2940 pblocks[0] = PetscAbs(pblocks[0]); 2941 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2942 if (pblocks[i] == 0) continue; 2943 // Negative block size indicates the blocks should be concatenated 2944 if (pblocks[i] < 0) { 2945 pblocks[i] = -pblocks[i]; 2946 pblocks[nblocks - 1] += pblocks[i]; 2947 } else { 2948 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2949 } 2950 for (PetscInt j = 1; j < pblocks[i]; j++) 2951 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); 2952 } 2953 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2954 } 2955 PetscCall(PetscFree(pblocks)); 2956 } 2957 PetscCall(MatSetDM(*J, dm)); 2958 PetscFunctionReturn(PETSC_SUCCESS); 2959 } 2960 2961 /*@ 2962 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2963 2964 Not Collective 2965 2966 Input Parameter: 2967 . dm - The `DMPLEX` 2968 2969 Output Parameter: 2970 . subsection - The subdomain section 2971 2972 Level: developer 2973 2974 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2975 @*/ 2976 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2977 { 2978 DM_Plex *mesh = (DM_Plex *)dm->data; 2979 2980 PetscFunctionBegin; 2981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2982 if (!mesh->subdomainSection) { 2983 PetscSection section; 2984 PetscSF sf; 2985 2986 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2987 PetscCall(DMGetLocalSection(dm, §ion)); 2988 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2989 PetscCall(PetscSFDestroy(&sf)); 2990 } 2991 *subsection = mesh->subdomainSection; 2992 PetscFunctionReturn(PETSC_SUCCESS); 2993 } 2994 2995 /*@ 2996 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2997 2998 Not Collective 2999 3000 Input Parameter: 3001 . dm - The `DMPLEX` 3002 3003 Output Parameters: 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()`, `DMPlexSetChart()` 3010 @*/ 3011 PetscErrorCode DMPlexGetChart(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 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3018 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3019 PetscFunctionReturn(PETSC_SUCCESS); 3020 } 3021 3022 /*@ 3023 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3024 3025 Not Collective 3026 3027 Input Parameters: 3028 + dm - The `DMPLEX` 3029 . pStart - The first mesh point 3030 - pEnd - The upper bound for mesh points 3031 3032 Level: beginner 3033 3034 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3035 @*/ 3036 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3037 { 3038 DM_Plex *mesh = (DM_Plex *)dm->data; 3039 3040 PetscFunctionBegin; 3041 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3042 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3043 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3044 PetscCall(PetscFree(mesh->cellTypes)); 3045 PetscFunctionReturn(PETSC_SUCCESS); 3046 } 3047 3048 /*@ 3049 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3050 3051 Not Collective 3052 3053 Input Parameters: 3054 + dm - The `DMPLEX` 3055 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3056 3057 Output Parameter: 3058 . size - The cone size for point `p` 3059 3060 Level: beginner 3061 3062 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3063 @*/ 3064 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3065 { 3066 DM_Plex *mesh = (DM_Plex *)dm->data; 3067 3068 PetscFunctionBegin; 3069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3070 PetscAssertPointer(size, 3); 3071 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3072 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3073 PetscFunctionReturn(PETSC_SUCCESS); 3074 } 3075 3076 /*@ 3077 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3078 3079 Not Collective 3080 3081 Input Parameters: 3082 + dm - The `DMPLEX` 3083 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3084 - size - The cone size for point `p` 3085 3086 Level: beginner 3087 3088 Note: 3089 This should be called after `DMPlexSetChart()`. 3090 3091 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3092 @*/ 3093 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3094 { 3095 DM_Plex *mesh = (DM_Plex *)dm->data; 3096 3097 PetscFunctionBegin; 3098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3099 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3100 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3101 PetscFunctionReturn(PETSC_SUCCESS); 3102 } 3103 3104 /*@C 3105 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3106 3107 Not Collective 3108 3109 Input Parameters: 3110 + dm - The `DMPLEX` 3111 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3112 3113 Output Parameter: 3114 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3115 3116 Level: beginner 3117 3118 Fortran Notes: 3119 `cone` must be declared with 3120 .vb 3121 PetscInt, pointer :: cone(:) 3122 .ve 3123 3124 You must also call `DMPlexRestoreCone()` after you finish using the array. 3125 `DMPlexRestoreCone()` is not needed/available in C. 3126 3127 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3128 @*/ 3129 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3130 { 3131 DM_Plex *mesh = (DM_Plex *)dm->data; 3132 PetscInt off; 3133 3134 PetscFunctionBegin; 3135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3136 PetscAssertPointer(cone, 3); 3137 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3138 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3139 PetscFunctionReturn(PETSC_SUCCESS); 3140 } 3141 3142 /*@ 3143 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3144 3145 Not Collective 3146 3147 Input Parameters: 3148 + dm - The `DMPLEX` 3149 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3150 3151 Output Parameters: 3152 + pConesSection - `PetscSection` describing the layout of `pCones` 3153 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3154 3155 Level: intermediate 3156 3157 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3158 @*/ 3159 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3160 { 3161 PetscSection cs, newcs; 3162 PetscInt *cones; 3163 PetscInt *newarr = NULL; 3164 PetscInt n; 3165 3166 PetscFunctionBegin; 3167 PetscCall(DMPlexGetCones(dm, &cones)); 3168 PetscCall(DMPlexGetConeSection(dm, &cs)); 3169 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3170 if (pConesSection) *pConesSection = newcs; 3171 if (pCones) { 3172 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3173 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3174 } 3175 PetscFunctionReturn(PETSC_SUCCESS); 3176 } 3177 3178 /*@ 3179 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3180 3181 Not Collective 3182 3183 Input Parameters: 3184 + dm - The `DMPLEX` 3185 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3186 3187 Output Parameter: 3188 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3189 3190 Level: advanced 3191 3192 Notes: 3193 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3194 3195 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3196 3197 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3198 `DMPlexGetDepth()`, `IS` 3199 @*/ 3200 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3201 { 3202 IS *expandedPointsAll; 3203 PetscInt depth; 3204 3205 PetscFunctionBegin; 3206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3207 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3208 PetscAssertPointer(expandedPoints, 3); 3209 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3210 *expandedPoints = expandedPointsAll[0]; 3211 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3212 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3213 PetscFunctionReturn(PETSC_SUCCESS); 3214 } 3215 3216 /*@ 3217 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3218 (DAG points of depth 0, i.e., without cones). 3219 3220 Not Collective 3221 3222 Input Parameters: 3223 + dm - The `DMPLEX` 3224 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3225 3226 Output Parameters: 3227 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3228 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3229 - sections - (optional) An array of sections which describe mappings from points to their cone points 3230 3231 Level: advanced 3232 3233 Notes: 3234 Like `DMPlexGetConeTuple()` but recursive. 3235 3236 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. 3237 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3238 3239 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\: 3240 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3241 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3242 3243 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3244 `DMPlexGetDepth()`, `PetscSection`, `IS` 3245 @*/ 3246 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3247 { 3248 const PetscInt *arr0 = NULL, *cone = NULL; 3249 PetscInt *arr = NULL, *newarr = NULL; 3250 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3251 IS *expandedPoints_; 3252 PetscSection *sections_; 3253 3254 PetscFunctionBegin; 3255 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3256 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3257 if (depth) PetscAssertPointer(depth, 3); 3258 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3259 if (sections) PetscAssertPointer(sections, 5); 3260 PetscCall(ISGetLocalSize(points, &n)); 3261 PetscCall(ISGetIndices(points, &arr0)); 3262 PetscCall(DMPlexGetDepth(dm, &depth_)); 3263 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3264 PetscCall(PetscCalloc1(depth_, §ions_)); 3265 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3266 for (d = depth_ - 1; d >= 0; d--) { 3267 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3268 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3269 for (i = 0; i < n; i++) { 3270 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3271 if (arr[i] >= start && arr[i] < end) { 3272 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3273 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3274 } else { 3275 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3276 } 3277 } 3278 PetscCall(PetscSectionSetUp(sections_[d])); 3279 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3280 PetscCall(PetscMalloc1(newn, &newarr)); 3281 for (i = 0; i < n; i++) { 3282 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3283 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3284 if (cn > 1) { 3285 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3286 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3287 } else { 3288 newarr[co] = arr[i]; 3289 } 3290 } 3291 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3292 arr = newarr; 3293 n = newn; 3294 } 3295 PetscCall(ISRestoreIndices(points, &arr0)); 3296 *depth = depth_; 3297 if (expandedPoints) *expandedPoints = expandedPoints_; 3298 else { 3299 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3300 PetscCall(PetscFree(expandedPoints_)); 3301 } 3302 if (sections) *sections = sections_; 3303 else { 3304 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3305 PetscCall(PetscFree(sections_)); 3306 } 3307 PetscFunctionReturn(PETSC_SUCCESS); 3308 } 3309 3310 /*@ 3311 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3312 3313 Not Collective 3314 3315 Input Parameters: 3316 + dm - The `DMPLEX` 3317 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3318 3319 Output Parameters: 3320 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3321 . expandedPoints - (optional) An array of recursively expanded cones 3322 - sections - (optional) An array of sections which describe mappings from points to their cone points 3323 3324 Level: advanced 3325 3326 Note: 3327 See `DMPlexGetConeRecursive()` 3328 3329 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3330 `DMPlexGetDepth()`, `IS`, `PetscSection` 3331 @*/ 3332 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3333 { 3334 PetscInt d, depth_; 3335 3336 PetscFunctionBegin; 3337 PetscCall(DMPlexGetDepth(dm, &depth_)); 3338 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3339 if (depth) *depth = 0; 3340 if (expandedPoints) { 3341 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3342 PetscCall(PetscFree(*expandedPoints)); 3343 } 3344 if (sections) { 3345 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3346 PetscCall(PetscFree(*sections)); 3347 } 3348 PetscFunctionReturn(PETSC_SUCCESS); 3349 } 3350 3351 /*@ 3352 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 3353 3354 Not Collective 3355 3356 Input Parameters: 3357 + dm - The `DMPLEX` 3358 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3359 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3360 3361 Level: beginner 3362 3363 Note: 3364 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3365 3366 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3367 @*/ 3368 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3369 { 3370 DM_Plex *mesh = (DM_Plex *)dm->data; 3371 PetscInt dof, off, c; 3372 3373 PetscFunctionBegin; 3374 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3375 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3376 if (dof) PetscAssertPointer(cone, 3); 3377 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3378 if (PetscDefined(USE_DEBUG)) { 3379 PetscInt pStart, pEnd; 3380 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3381 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3382 for (c = 0; c < dof; ++c) { 3383 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); 3384 mesh->cones[off + c] = cone[c]; 3385 } 3386 } else { 3387 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3388 } 3389 PetscFunctionReturn(PETSC_SUCCESS); 3390 } 3391 3392 /*@C 3393 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3394 3395 Not Collective 3396 3397 Input Parameters: 3398 + dm - The `DMPLEX` 3399 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3400 3401 Output Parameter: 3402 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3403 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3404 3405 Level: beginner 3406 3407 Note: 3408 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3409 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3410 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3411 with the identity. 3412 3413 Fortran Notes: 3414 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3415 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3416 3417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3418 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3419 @*/ 3420 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3421 { 3422 DM_Plex *mesh = (DM_Plex *)dm->data; 3423 PetscInt off; 3424 3425 PetscFunctionBegin; 3426 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3427 if (PetscDefined(USE_DEBUG)) { 3428 PetscInt dof; 3429 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3430 if (dof) PetscAssertPointer(coneOrientation, 3); 3431 } 3432 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3433 3434 *coneOrientation = &mesh->coneOrientations[off]; 3435 PetscFunctionReturn(PETSC_SUCCESS); 3436 } 3437 3438 /*@ 3439 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3440 3441 Not Collective 3442 3443 Input Parameters: 3444 + dm - The `DMPLEX` 3445 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3446 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3447 3448 Level: beginner 3449 3450 Notes: 3451 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3452 3453 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3454 3455 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3456 @*/ 3457 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3458 { 3459 DM_Plex *mesh = (DM_Plex *)dm->data; 3460 PetscInt pStart, pEnd; 3461 PetscInt dof, off, c; 3462 3463 PetscFunctionBegin; 3464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3465 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3466 if (dof) PetscAssertPointer(coneOrientation, 3); 3467 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3468 if (PetscDefined(USE_DEBUG)) { 3469 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3470 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); 3471 for (c = 0; c < dof; ++c) { 3472 PetscInt cdof, o = coneOrientation[c]; 3473 3474 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3475 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); 3476 mesh->coneOrientations[off + c] = o; 3477 } 3478 } else { 3479 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3480 } 3481 PetscFunctionReturn(PETSC_SUCCESS); 3482 } 3483 3484 /*@ 3485 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3486 3487 Not Collective 3488 3489 Input Parameters: 3490 + dm - The `DMPLEX` 3491 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3492 . conePos - The local index in the cone where the point should be put 3493 - conePoint - The mesh point to insert 3494 3495 Level: beginner 3496 3497 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3498 @*/ 3499 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3500 { 3501 DM_Plex *mesh = (DM_Plex *)dm->data; 3502 PetscInt pStart, pEnd; 3503 PetscInt dof, off; 3504 3505 PetscFunctionBegin; 3506 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3507 if (PetscDefined(USE_DEBUG)) { 3508 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3509 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); 3510 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); 3511 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3512 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); 3513 } 3514 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3515 mesh->cones[off + conePos] = conePoint; 3516 PetscFunctionReturn(PETSC_SUCCESS); 3517 } 3518 3519 /*@ 3520 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3521 3522 Not Collective 3523 3524 Input Parameters: 3525 + dm - The `DMPLEX` 3526 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3527 . conePos - The local index in the cone where the point should be put 3528 - coneOrientation - The point orientation to insert 3529 3530 Level: beginner 3531 3532 Note: 3533 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3534 3535 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3536 @*/ 3537 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3538 { 3539 DM_Plex *mesh = (DM_Plex *)dm->data; 3540 PetscInt pStart, pEnd; 3541 PetscInt dof, off; 3542 3543 PetscFunctionBegin; 3544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3545 if (PetscDefined(USE_DEBUG)) { 3546 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3547 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); 3548 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3549 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); 3550 } 3551 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3552 mesh->coneOrientations[off + conePos] = coneOrientation; 3553 PetscFunctionReturn(PETSC_SUCCESS); 3554 } 3555 3556 /*@C 3557 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3558 3559 Not collective 3560 3561 Input Parameters: 3562 + dm - The DMPlex 3563 - p - The point, which must lie in the chart set with DMPlexSetChart() 3564 3565 Output Parameters: 3566 + cone - An array of points which are on the in-edges for point `p` 3567 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3568 integer giving the prescription for cone traversal. 3569 3570 Level: beginner 3571 3572 Notes: 3573 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3574 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3575 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3576 with the identity. 3577 3578 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3579 3580 Fortran Notes: 3581 `cone` and `ornt` must be declared with 3582 .vb 3583 PetscInt, pointer :: cone(:) 3584 PetscInt, pointer :: ornt(:) 3585 .ve 3586 3587 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3588 @*/ 3589 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3590 { 3591 DM_Plex *mesh = (DM_Plex *)dm->data; 3592 3593 PetscFunctionBegin; 3594 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3595 if (mesh->tr) { 3596 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3597 } else { 3598 PetscInt off; 3599 if (PetscDefined(USE_DEBUG)) { 3600 PetscInt dof; 3601 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3602 if (dof) { 3603 if (cone) PetscAssertPointer(cone, 3); 3604 if (ornt) PetscAssertPointer(ornt, 4); 3605 } 3606 } 3607 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3608 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3609 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3610 } 3611 PetscFunctionReturn(PETSC_SUCCESS); 3612 } 3613 3614 /*@C 3615 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3616 3617 Not Collective 3618 3619 Input Parameters: 3620 + dm - The DMPlex 3621 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3622 . cone - An array of points which are on the in-edges for point p 3623 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3624 integer giving the prescription for cone traversal. 3625 3626 Level: beginner 3627 3628 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3629 @*/ 3630 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3631 { 3632 DM_Plex *mesh = (DM_Plex *)dm->data; 3633 3634 PetscFunctionBegin; 3635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3636 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3637 PetscFunctionReturn(PETSC_SUCCESS); 3638 } 3639 3640 /*@ 3641 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3642 3643 Not Collective 3644 3645 Input Parameters: 3646 + dm - The `DMPLEX` 3647 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3648 3649 Output Parameter: 3650 . size - The support size for point `p` 3651 3652 Level: beginner 3653 3654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3655 @*/ 3656 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3657 { 3658 DM_Plex *mesh = (DM_Plex *)dm->data; 3659 3660 PetscFunctionBegin; 3661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3662 PetscAssertPointer(size, 3); 3663 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3664 PetscFunctionReturn(PETSC_SUCCESS); 3665 } 3666 3667 /*@ 3668 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3669 3670 Not Collective 3671 3672 Input Parameters: 3673 + dm - The `DMPLEX` 3674 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3675 - size - The support size for point `p` 3676 3677 Level: beginner 3678 3679 Note: 3680 This should be called after `DMPlexSetChart()`. 3681 3682 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3683 @*/ 3684 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3685 { 3686 DM_Plex *mesh = (DM_Plex *)dm->data; 3687 3688 PetscFunctionBegin; 3689 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3690 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3691 PetscFunctionReturn(PETSC_SUCCESS); 3692 } 3693 3694 /*@C 3695 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3696 3697 Not Collective 3698 3699 Input Parameters: 3700 + dm - The `DMPLEX` 3701 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3702 3703 Output Parameter: 3704 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3705 3706 Level: beginner 3707 3708 Fortran Notes: 3709 `support` must be declared with 3710 .vb 3711 PetscInt, pointer :: support(:) 3712 .ve 3713 3714 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3715 `DMPlexRestoreSupport()` is not needed/available in C. 3716 3717 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3718 @*/ 3719 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3720 { 3721 DM_Plex *mesh = (DM_Plex *)dm->data; 3722 PetscInt off; 3723 3724 PetscFunctionBegin; 3725 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3726 PetscAssertPointer(support, 3); 3727 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3728 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3729 PetscFunctionReturn(PETSC_SUCCESS); 3730 } 3731 3732 /*@ 3733 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3734 3735 Not Collective 3736 3737 Input Parameters: 3738 + dm - The `DMPLEX` 3739 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3740 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3741 3742 Level: beginner 3743 3744 Note: 3745 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3746 3747 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3748 @*/ 3749 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3750 { 3751 DM_Plex *mesh = (DM_Plex *)dm->data; 3752 PetscInt pStart, pEnd; 3753 PetscInt dof, off, c; 3754 3755 PetscFunctionBegin; 3756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3757 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3758 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3759 if (dof) PetscAssertPointer(support, 3); 3760 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3761 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); 3762 for (c = 0; c < dof; ++c) { 3763 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); 3764 mesh->supports[off + c] = support[c]; 3765 } 3766 PetscFunctionReturn(PETSC_SUCCESS); 3767 } 3768 3769 /*@ 3770 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3771 3772 Not Collective 3773 3774 Input Parameters: 3775 + dm - The `DMPLEX` 3776 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3777 . supportPos - The local index in the cone where the point should be put 3778 - supportPoint - The mesh point to insert 3779 3780 Level: beginner 3781 3782 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3783 @*/ 3784 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3785 { 3786 DM_Plex *mesh = (DM_Plex *)dm->data; 3787 PetscInt pStart, pEnd; 3788 PetscInt dof, off; 3789 3790 PetscFunctionBegin; 3791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3792 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3793 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3794 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3795 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); 3796 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); 3797 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); 3798 mesh->supports[off + supportPos] = supportPoint; 3799 PetscFunctionReturn(PETSC_SUCCESS); 3800 } 3801 3802 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3803 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3804 { 3805 switch (ct) { 3806 case DM_POLYTOPE_SEGMENT: 3807 if (o == -1) return -2; 3808 break; 3809 case DM_POLYTOPE_TRIANGLE: 3810 if (o == -3) return -1; 3811 if (o == -2) return -3; 3812 if (o == -1) return -2; 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 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3827 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3828 { 3829 switch (ct) { 3830 case DM_POLYTOPE_SEGMENT: 3831 if ((o == -2) || (o == 1)) return -1; 3832 if (o == -1) return 0; 3833 break; 3834 case DM_POLYTOPE_TRIANGLE: 3835 if (o == -3) return -2; 3836 if (o == -2) return -1; 3837 if (o == -1) return -3; 3838 break; 3839 case DM_POLYTOPE_QUADRILATERAL: 3840 if (o == -4) return -2; 3841 if (o == -3) return -1; 3842 if (o == -2) return -4; 3843 if (o == -1) return -3; 3844 break; 3845 default: 3846 return o; 3847 } 3848 return o; 3849 } 3850 3851 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3852 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3853 { 3854 PetscInt pStart, pEnd, p; 3855 3856 PetscFunctionBegin; 3857 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3858 for (p = pStart; p < pEnd; ++p) { 3859 const PetscInt *cone, *ornt; 3860 PetscInt coneSize, c; 3861 3862 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3863 PetscCall(DMPlexGetCone(dm, p, &cone)); 3864 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3865 for (c = 0; c < coneSize; ++c) { 3866 DMPolytopeType ct; 3867 const PetscInt o = ornt[c]; 3868 3869 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3870 switch (ct) { 3871 case DM_POLYTOPE_SEGMENT: 3872 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3873 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3874 break; 3875 case DM_POLYTOPE_TRIANGLE: 3876 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3877 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3878 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3879 break; 3880 case DM_POLYTOPE_QUADRILATERAL: 3881 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3882 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3883 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3884 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3885 break; 3886 default: 3887 break; 3888 } 3889 } 3890 } 3891 PetscFunctionReturn(PETSC_SUCCESS); 3892 } 3893 3894 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3895 { 3896 DM_Plex *mesh = (DM_Plex *)dm->data; 3897 3898 PetscFunctionBeginHot; 3899 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3900 if (useCone) { 3901 PetscCall(DMPlexGetConeSize(dm, p, size)); 3902 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3903 } else { 3904 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3905 PetscCall(DMPlexGetSupport(dm, p, arr)); 3906 } 3907 } else { 3908 if (useCone) { 3909 const PetscSection s = mesh->coneSection; 3910 const PetscInt ps = p - s->pStart; 3911 const PetscInt off = s->atlasOff[ps]; 3912 3913 *size = s->atlasDof[ps]; 3914 *arr = mesh->cones + off; 3915 *ornt = mesh->coneOrientations + off; 3916 } else { 3917 const PetscSection s = mesh->supportSection; 3918 const PetscInt ps = p - s->pStart; 3919 const PetscInt off = s->atlasOff[ps]; 3920 3921 *size = s->atlasDof[ps]; 3922 *arr = mesh->supports + off; 3923 } 3924 } 3925 PetscFunctionReturn(PETSC_SUCCESS); 3926 } 3927 3928 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3929 { 3930 DM_Plex *mesh = (DM_Plex *)dm->data; 3931 3932 PetscFunctionBeginHot; 3933 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3934 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3935 } 3936 PetscFunctionReturn(PETSC_SUCCESS); 3937 } 3938 3939 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3940 { 3941 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3942 PetscInt *closure; 3943 const PetscInt *tmp = NULL, *tmpO = NULL; 3944 PetscInt off = 0, tmpSize, t; 3945 3946 PetscFunctionBeginHot; 3947 if (ornt) { 3948 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3949 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; 3950 } 3951 if (*points) { 3952 closure = *points; 3953 } else { 3954 PetscInt maxConeSize, maxSupportSize; 3955 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3956 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3957 } 3958 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3959 if (ct == DM_POLYTOPE_UNKNOWN) { 3960 closure[off++] = p; 3961 closure[off++] = 0; 3962 for (t = 0; t < tmpSize; ++t) { 3963 closure[off++] = tmp[t]; 3964 closure[off++] = tmpO ? tmpO[t] : 0; 3965 } 3966 } else { 3967 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3968 3969 /* We assume that cells with a valid type have faces with a valid type */ 3970 closure[off++] = p; 3971 closure[off++] = ornt; 3972 for (t = 0; t < tmpSize; ++t) { 3973 DMPolytopeType ft; 3974 3975 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3976 closure[off++] = tmp[arr[t]]; 3977 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3978 } 3979 } 3980 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3981 if (numPoints) *numPoints = tmpSize + 1; 3982 if (points) *points = closure; 3983 PetscFunctionReturn(PETSC_SUCCESS); 3984 } 3985 3986 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3987 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3988 { 3989 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3990 const PetscInt *cone, *ornt; 3991 PetscInt *pts, *closure = NULL; 3992 DMPolytopeType ft; 3993 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3994 PetscInt dim, coneSize, c, d, clSize, cl; 3995 3996 PetscFunctionBeginHot; 3997 PetscCall(DMGetDimension(dm, &dim)); 3998 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3999 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4000 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4001 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4002 maxSize = PetscMax(coneSeries, supportSeries); 4003 if (*points) { 4004 pts = *points; 4005 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4006 c = 0; 4007 pts[c++] = point; 4008 pts[c++] = o; 4009 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4010 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4011 for (cl = 0; cl < clSize * 2; cl += 2) { 4012 pts[c++] = closure[cl]; 4013 pts[c++] = closure[cl + 1]; 4014 } 4015 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4016 for (cl = 0; cl < clSize * 2; cl += 2) { 4017 pts[c++] = closure[cl]; 4018 pts[c++] = closure[cl + 1]; 4019 } 4020 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4021 for (d = 2; d < coneSize; ++d) { 4022 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4023 pts[c++] = cone[arr[d * 2 + 0]]; 4024 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4025 } 4026 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4027 if (dim >= 3) { 4028 for (d = 2; d < coneSize; ++d) { 4029 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4030 const PetscInt *fcone, *fornt; 4031 PetscInt fconeSize, fc, i; 4032 4033 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4034 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4035 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4036 for (fc = 0; fc < fconeSize; ++fc) { 4037 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4038 const PetscInt co = farr[fc * 2 + 1]; 4039 4040 for (i = 0; i < c; i += 2) 4041 if (pts[i] == cp) break; 4042 if (i == c) { 4043 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4044 pts[c++] = cp; 4045 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4046 } 4047 } 4048 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4049 } 4050 } 4051 *numPoints = c / 2; 4052 *points = pts; 4053 PetscFunctionReturn(PETSC_SUCCESS); 4054 } 4055 4056 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4057 { 4058 DMPolytopeType ct; 4059 PetscInt *closure, *fifo; 4060 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4061 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4062 PetscInt depth, maxSize; 4063 4064 PetscFunctionBeginHot; 4065 PetscCall(DMPlexGetDepth(dm, &depth)); 4066 if (depth == 1) { 4067 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4068 PetscFunctionReturn(PETSC_SUCCESS); 4069 } 4070 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4071 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; 4072 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4073 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4074 PetscFunctionReturn(PETSC_SUCCESS); 4075 } 4076 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4077 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4078 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4079 maxSize = PetscMax(coneSeries, supportSeries); 4080 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4081 if (*points) { 4082 closure = *points; 4083 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4084 closure[closureSize++] = p; 4085 closure[closureSize++] = ornt; 4086 fifo[fifoSize++] = p; 4087 fifo[fifoSize++] = ornt; 4088 fifo[fifoSize++] = ct; 4089 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4090 while (fifoSize - fifoStart) { 4091 const PetscInt q = fifo[fifoStart++]; 4092 const PetscInt o = fifo[fifoStart++]; 4093 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4094 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4095 const PetscInt *tmp, *tmpO = NULL; 4096 PetscInt tmpSize, t; 4097 4098 if (PetscDefined(USE_DEBUG)) { 4099 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4100 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); 4101 } 4102 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4103 for (t = 0; t < tmpSize; ++t) { 4104 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4105 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4106 const PetscInt cp = tmp[ip]; 4107 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4108 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4109 PetscInt c; 4110 4111 /* Check for duplicate */ 4112 for (c = 0; c < closureSize; c += 2) { 4113 if (closure[c] == cp) break; 4114 } 4115 if (c == closureSize) { 4116 closure[closureSize++] = cp; 4117 closure[closureSize++] = co; 4118 fifo[fifoSize++] = cp; 4119 fifo[fifoSize++] = co; 4120 fifo[fifoSize++] = ct; 4121 } 4122 } 4123 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4124 } 4125 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4126 if (numPoints) *numPoints = closureSize / 2; 4127 if (points) *points = closure; 4128 PetscFunctionReturn(PETSC_SUCCESS); 4129 } 4130 4131 /*@C 4132 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4133 4134 Not Collective 4135 4136 Input Parameters: 4137 + dm - The `DMPLEX` 4138 . p - The mesh point 4139 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4140 4141 Input/Output Parameter: 4142 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4143 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4144 otherwise the provided array is used to hold the values 4145 4146 Output Parameter: 4147 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4148 4149 Level: beginner 4150 4151 Note: 4152 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4153 4154 Fortran Notes: 4155 `points` must be declared with 4156 .vb 4157 PetscInt, pointer :: points(:) 4158 .ve 4159 and is always allocated by the function. 4160 4161 The `numPoints` argument is not present in the Fortran binding. 4162 4163 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4164 @*/ 4165 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4166 { 4167 PetscFunctionBeginHot; 4168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4169 if (numPoints) PetscAssertPointer(numPoints, 4); 4170 if (points) PetscAssertPointer(points, 5); 4171 if (PetscDefined(USE_DEBUG)) { 4172 PetscInt pStart, pEnd; 4173 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4174 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); 4175 } 4176 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4177 PetscFunctionReturn(PETSC_SUCCESS); 4178 } 4179 4180 /*@C 4181 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4182 4183 Not Collective 4184 4185 Input Parameters: 4186 + dm - The `DMPLEX` 4187 . p - The mesh point 4188 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4189 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4190 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4191 4192 Level: beginner 4193 4194 Note: 4195 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4196 4197 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4198 @*/ 4199 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4200 { 4201 PetscFunctionBeginHot; 4202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4203 if (numPoints) *numPoints = 0; 4204 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4205 PetscFunctionReturn(PETSC_SUCCESS); 4206 } 4207 4208 /*@ 4209 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4210 4211 Not Collective 4212 4213 Input Parameter: 4214 . dm - The `DMPLEX` 4215 4216 Output Parameters: 4217 + maxConeSize - The maximum number of in-edges 4218 - maxSupportSize - The maximum number of out-edges 4219 4220 Level: beginner 4221 4222 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4223 @*/ 4224 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4225 { 4226 DM_Plex *mesh = (DM_Plex *)dm->data; 4227 4228 PetscFunctionBegin; 4229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4230 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4231 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4232 PetscFunctionReturn(PETSC_SUCCESS); 4233 } 4234 4235 PetscErrorCode DMSetUp_Plex(DM dm) 4236 { 4237 DM_Plex *mesh = (DM_Plex *)dm->data; 4238 PetscInt size, maxSupportSize; 4239 4240 PetscFunctionBegin; 4241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4242 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4243 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4244 PetscCall(PetscMalloc1(size, &mesh->cones)); 4245 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4246 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4247 if (maxSupportSize) { 4248 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4249 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4250 PetscCall(PetscMalloc1(size, &mesh->supports)); 4251 } 4252 PetscFunctionReturn(PETSC_SUCCESS); 4253 } 4254 4255 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4256 { 4257 PetscFunctionBegin; 4258 if (subdm) PetscCall(DMClone(dm, subdm)); 4259 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4260 if (subdm) (*subdm)->useNatural = dm->useNatural; 4261 if (dm->useNatural && dm->sfMigration) { 4262 PetscSF sfNatural; 4263 4264 (*subdm)->sfMigration = dm->sfMigration; 4265 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4266 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4267 (*subdm)->sfNatural = sfNatural; 4268 } 4269 PetscFunctionReturn(PETSC_SUCCESS); 4270 } 4271 4272 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4273 { 4274 PetscInt i = 0; 4275 4276 PetscFunctionBegin; 4277 PetscCall(DMClone(dms[0], superdm)); 4278 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4279 (*superdm)->useNatural = PETSC_FALSE; 4280 for (i = 0; i < len; i++) { 4281 if (dms[i]->useNatural && dms[i]->sfMigration) { 4282 PetscSF sfNatural; 4283 4284 (*superdm)->sfMigration = dms[i]->sfMigration; 4285 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4286 (*superdm)->useNatural = PETSC_TRUE; 4287 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4288 (*superdm)->sfNatural = sfNatural; 4289 break; 4290 } 4291 } 4292 PetscFunctionReturn(PETSC_SUCCESS); 4293 } 4294 4295 /*@ 4296 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4297 4298 Not Collective 4299 4300 Input Parameter: 4301 . dm - The `DMPLEX` 4302 4303 Level: beginner 4304 4305 Note: 4306 This should be called after all calls to `DMPlexSetCone()` 4307 4308 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4309 @*/ 4310 PetscErrorCode DMPlexSymmetrize(DM dm) 4311 { 4312 DM_Plex *mesh = (DM_Plex *)dm->data; 4313 PetscInt *offsets; 4314 PetscInt supportSize; 4315 PetscInt pStart, pEnd, p; 4316 4317 PetscFunctionBegin; 4318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4319 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4320 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4321 /* Calculate support sizes */ 4322 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4323 for (p = pStart; p < pEnd; ++p) { 4324 PetscInt dof, off, c; 4325 4326 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4327 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4328 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4329 } 4330 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4331 /* Calculate supports */ 4332 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4333 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4334 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4335 for (p = pStart; p < pEnd; ++p) { 4336 PetscInt dof, off, c; 4337 4338 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4339 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4340 for (c = off; c < off + dof; ++c) { 4341 const PetscInt q = mesh->cones[c]; 4342 PetscInt offS; 4343 4344 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4345 4346 mesh->supports[offS + offsets[q]] = p; 4347 ++offsets[q]; 4348 } 4349 } 4350 PetscCall(PetscFree(offsets)); 4351 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4352 PetscFunctionReturn(PETSC_SUCCESS); 4353 } 4354 4355 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4356 { 4357 IS stratumIS; 4358 4359 PetscFunctionBegin; 4360 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4361 if (PetscDefined(USE_DEBUG)) { 4362 PetscInt qStart, qEnd, numLevels, level; 4363 PetscBool overlap = PETSC_FALSE; 4364 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4365 for (level = 0; level < numLevels; level++) { 4366 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4367 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4368 overlap = PETSC_TRUE; 4369 break; 4370 } 4371 } 4372 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); 4373 } 4374 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4375 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4376 PetscCall(ISDestroy(&stratumIS)); 4377 PetscFunctionReturn(PETSC_SUCCESS); 4378 } 4379 4380 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4381 { 4382 PetscInt *pMin, *pMax; 4383 PetscInt pStart, pEnd; 4384 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4385 4386 PetscFunctionBegin; 4387 { 4388 DMLabel label2; 4389 4390 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4391 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4392 } 4393 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4394 for (PetscInt p = pStart; p < pEnd; ++p) { 4395 DMPolytopeType ct; 4396 4397 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4398 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4399 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4400 } 4401 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4402 for (PetscInt d = dmin; d <= dmax; ++d) { 4403 pMin[d] = PETSC_INT_MAX; 4404 pMax[d] = PETSC_INT_MIN; 4405 } 4406 for (PetscInt p = pStart; p < pEnd; ++p) { 4407 DMPolytopeType ct; 4408 PetscInt d; 4409 4410 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4411 d = DMPolytopeTypeGetDim(ct); 4412 pMin[d] = PetscMin(p, pMin[d]); 4413 pMax[d] = PetscMax(p, pMax[d]); 4414 } 4415 for (PetscInt d = dmin; d <= dmax; ++d) { 4416 if (pMin[d] > pMax[d]) continue; 4417 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4418 } 4419 PetscCall(PetscFree2(pMin, pMax)); 4420 PetscFunctionReturn(PETSC_SUCCESS); 4421 } 4422 4423 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4424 { 4425 PetscInt pStart, pEnd; 4426 PetscInt numRoots = 0, numLeaves = 0; 4427 4428 PetscFunctionBegin; 4429 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4430 { 4431 /* Initialize roots and count leaves */ 4432 PetscInt sMin = PETSC_INT_MAX; 4433 PetscInt sMax = PETSC_INT_MIN; 4434 PetscInt coneSize, supportSize; 4435 4436 for (PetscInt p = pStart; p < pEnd; ++p) { 4437 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4438 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4439 if (!coneSize && supportSize) { 4440 sMin = PetscMin(p, sMin); 4441 sMax = PetscMax(p, sMax); 4442 ++numRoots; 4443 } else if (!supportSize && coneSize) { 4444 ++numLeaves; 4445 } else if (!supportSize && !coneSize) { 4446 /* Isolated points */ 4447 sMin = PetscMin(p, sMin); 4448 sMax = PetscMax(p, sMax); 4449 } 4450 } 4451 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4452 } 4453 4454 if (numRoots + numLeaves == (pEnd - pStart)) { 4455 PetscInt sMin = PETSC_INT_MAX; 4456 PetscInt sMax = PETSC_INT_MIN; 4457 PetscInt coneSize, supportSize; 4458 4459 for (PetscInt p = pStart; p < pEnd; ++p) { 4460 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4461 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4462 if (!supportSize && coneSize) { 4463 sMin = PetscMin(p, sMin); 4464 sMax = PetscMax(p, sMax); 4465 } 4466 } 4467 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4468 } else { 4469 PetscInt level = 0; 4470 PetscInt qStart, qEnd; 4471 4472 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4473 while (qEnd > qStart) { 4474 PetscInt sMin = PETSC_INT_MAX; 4475 PetscInt sMax = PETSC_INT_MIN; 4476 4477 for (PetscInt q = qStart; q < qEnd; ++q) { 4478 const PetscInt *support; 4479 PetscInt supportSize; 4480 4481 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4482 PetscCall(DMPlexGetSupport(dm, q, &support)); 4483 for (PetscInt s = 0; s < supportSize; ++s) { 4484 sMin = PetscMin(support[s], sMin); 4485 sMax = PetscMax(support[s], sMax); 4486 } 4487 } 4488 PetscCall(DMLabelGetNumValues(label, &level)); 4489 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4490 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4491 } 4492 } 4493 PetscFunctionReturn(PETSC_SUCCESS); 4494 } 4495 4496 /*@ 4497 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4498 4499 Collective 4500 4501 Input Parameter: 4502 . dm - The `DMPLEX` 4503 4504 Level: beginner 4505 4506 Notes: 4507 The strata group all points of the same grade, and this function calculates the strata. This 4508 grade can be seen as the height (or depth) of the point in the DAG. 4509 4510 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4511 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4512 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4513 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4514 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4515 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4516 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4517 4518 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4519 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4520 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 4521 to interpolate only that one (e0), so that 4522 .vb 4523 cone(c0) = {e0, v2} 4524 cone(e0) = {v0, v1} 4525 .ve 4526 If `DMPlexStratify()` is run on this mesh, it will give depths 4527 .vb 4528 depth 0 = {v0, v1, v2} 4529 depth 1 = {e0, c0} 4530 .ve 4531 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4532 4533 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4534 4535 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4536 @*/ 4537 PetscErrorCode DMPlexStratify(DM dm) 4538 { 4539 DM_Plex *mesh = (DM_Plex *)dm->data; 4540 DMLabel label; 4541 PetscBool flg = PETSC_FALSE; 4542 4543 PetscFunctionBegin; 4544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4545 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4546 4547 // Create depth label 4548 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4549 PetscCall(DMCreateLabel(dm, "depth")); 4550 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4551 4552 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4553 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4554 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4555 4556 { /* just in case there is an empty process */ 4557 PetscInt numValues, maxValues = 0, v; 4558 4559 PetscCall(DMLabelGetNumValues(label, &numValues)); 4560 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4561 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4562 } 4563 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4564 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4565 PetscFunctionReturn(PETSC_SUCCESS); 4566 } 4567 4568 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4569 { 4570 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4571 PetscInt dim, depth, pheight, coneSize; 4572 4573 PetscFunctionBeginHot; 4574 PetscCall(DMGetDimension(dm, &dim)); 4575 PetscCall(DMPlexGetDepth(dm, &depth)); 4576 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4577 pheight = depth - pdepth; 4578 if (depth <= 1) { 4579 switch (pdepth) { 4580 case 0: 4581 ct = DM_POLYTOPE_POINT; 4582 break; 4583 case 1: 4584 switch (coneSize) { 4585 case 2: 4586 ct = DM_POLYTOPE_SEGMENT; 4587 break; 4588 case 3: 4589 ct = DM_POLYTOPE_TRIANGLE; 4590 break; 4591 case 4: 4592 switch (dim) { 4593 case 2: 4594 ct = DM_POLYTOPE_QUADRILATERAL; 4595 break; 4596 case 3: 4597 ct = DM_POLYTOPE_TETRAHEDRON; 4598 break; 4599 default: 4600 break; 4601 } 4602 break; 4603 case 5: 4604 ct = DM_POLYTOPE_PYRAMID; 4605 break; 4606 case 6: 4607 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4608 break; 4609 case 8: 4610 ct = DM_POLYTOPE_HEXAHEDRON; 4611 break; 4612 default: 4613 break; 4614 } 4615 } 4616 } else { 4617 if (pdepth == 0) { 4618 ct = DM_POLYTOPE_POINT; 4619 } else if (pheight == 0) { 4620 switch (dim) { 4621 case 1: 4622 switch (coneSize) { 4623 case 2: 4624 ct = DM_POLYTOPE_SEGMENT; 4625 break; 4626 default: 4627 break; 4628 } 4629 break; 4630 case 2: 4631 switch (coneSize) { 4632 case 3: 4633 ct = DM_POLYTOPE_TRIANGLE; 4634 break; 4635 case 4: 4636 ct = DM_POLYTOPE_QUADRILATERAL; 4637 break; 4638 default: 4639 break; 4640 } 4641 break; 4642 case 3: 4643 switch (coneSize) { 4644 case 4: 4645 ct = DM_POLYTOPE_TETRAHEDRON; 4646 break; 4647 case 5: { 4648 const PetscInt *cone; 4649 PetscInt faceConeSize; 4650 4651 PetscCall(DMPlexGetCone(dm, p, &cone)); 4652 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4653 switch (faceConeSize) { 4654 case 3: 4655 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4656 break; 4657 case 4: 4658 ct = DM_POLYTOPE_PYRAMID; 4659 break; 4660 } 4661 } break; 4662 case 6: 4663 ct = DM_POLYTOPE_HEXAHEDRON; 4664 break; 4665 default: 4666 break; 4667 } 4668 break; 4669 default: 4670 break; 4671 } 4672 } else if (pheight > 0) { 4673 switch (coneSize) { 4674 case 2: 4675 ct = DM_POLYTOPE_SEGMENT; 4676 break; 4677 case 3: 4678 ct = DM_POLYTOPE_TRIANGLE; 4679 break; 4680 case 4: 4681 ct = DM_POLYTOPE_QUADRILATERAL; 4682 break; 4683 default: 4684 break; 4685 } 4686 } 4687 } 4688 *pt = ct; 4689 PetscFunctionReturn(PETSC_SUCCESS); 4690 } 4691 4692 /*@ 4693 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4694 4695 Collective 4696 4697 Input Parameter: 4698 . dm - The `DMPLEX` 4699 4700 Level: developer 4701 4702 Note: 4703 This function is normally called automatically when a cell type is requested. It creates an 4704 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4705 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4706 4707 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4708 4709 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4710 @*/ 4711 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4712 { 4713 DM_Plex *mesh; 4714 DMLabel ctLabel; 4715 PetscInt pStart, pEnd, p; 4716 4717 PetscFunctionBegin; 4718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4719 mesh = (DM_Plex *)dm->data; 4720 PetscCall(DMCreateLabel(dm, "celltype")); 4721 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4722 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4723 PetscCall(PetscFree(mesh->cellTypes)); 4724 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4725 for (p = pStart; p < pEnd; ++p) { 4726 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4727 PetscInt pdepth; 4728 4729 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4730 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4731 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]); 4732 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4733 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4734 } 4735 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4736 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4737 PetscFunctionReturn(PETSC_SUCCESS); 4738 } 4739 4740 /*@C 4741 DMPlexGetJoin - Get an array for the join of the set of points 4742 4743 Not Collective 4744 4745 Input Parameters: 4746 + dm - The `DMPLEX` object 4747 . numPoints - The number of input points for the join 4748 - points - The input points 4749 4750 Output Parameters: 4751 + numCoveredPoints - The number of points in the join 4752 - coveredPoints - The points in the join 4753 4754 Level: intermediate 4755 4756 Note: 4757 Currently, this is restricted to a single level join 4758 4759 Fortran Notes: 4760 `converedPoints` must be declared with 4761 .vb 4762 PetscInt, pointer :: coveredPints(:) 4763 .ve 4764 4765 The `numCoveredPoints` argument is not present in the Fortran binding. 4766 4767 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4768 @*/ 4769 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4770 { 4771 DM_Plex *mesh = (DM_Plex *)dm->data; 4772 PetscInt *join[2]; 4773 PetscInt joinSize, i = 0; 4774 PetscInt dof, off, p, c, m; 4775 PetscInt maxSupportSize; 4776 4777 PetscFunctionBegin; 4778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4779 PetscAssertPointer(points, 3); 4780 PetscAssertPointer(numCoveredPoints, 4); 4781 PetscAssertPointer(coveredPoints, 5); 4782 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4783 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4784 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4785 /* Copy in support of first point */ 4786 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4787 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4788 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4789 /* Check each successive support */ 4790 for (p = 1; p < numPoints; ++p) { 4791 PetscInt newJoinSize = 0; 4792 4793 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4794 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4795 for (c = 0; c < dof; ++c) { 4796 const PetscInt point = mesh->supports[off + c]; 4797 4798 for (m = 0; m < joinSize; ++m) { 4799 if (point == join[i][m]) { 4800 join[1 - i][newJoinSize++] = point; 4801 break; 4802 } 4803 } 4804 } 4805 joinSize = newJoinSize; 4806 i = 1 - i; 4807 } 4808 *numCoveredPoints = joinSize; 4809 *coveredPoints = join[i]; 4810 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4811 PetscFunctionReturn(PETSC_SUCCESS); 4812 } 4813 4814 /*@C 4815 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4816 4817 Not Collective 4818 4819 Input Parameters: 4820 + dm - The `DMPLEX` object 4821 . numPoints - The number of input points for the join 4822 - points - The input points 4823 4824 Output Parameters: 4825 + numCoveredPoints - The number of points in the join 4826 - coveredPoints - The points in the join 4827 4828 Level: intermediate 4829 4830 Fortran Notes: 4831 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4832 4833 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4834 @*/ 4835 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4836 { 4837 PetscFunctionBegin; 4838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4839 if (points) PetscAssertPointer(points, 3); 4840 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4841 PetscAssertPointer(coveredPoints, 5); 4842 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4843 if (numCoveredPoints) *numCoveredPoints = 0; 4844 PetscFunctionReturn(PETSC_SUCCESS); 4845 } 4846 4847 /*@C 4848 DMPlexGetFullJoin - Get an array for the join of the set of points 4849 4850 Not Collective 4851 4852 Input Parameters: 4853 + dm - The `DMPLEX` object 4854 . numPoints - The number of input points for the join 4855 - points - The input points, its length is `numPoints` 4856 4857 Output Parameters: 4858 + numCoveredPoints - The number of points in the join 4859 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4860 4861 Level: intermediate 4862 4863 Fortran Notes: 4864 `points` and `converedPoints` must be declared with 4865 .vb 4866 PetscInt, pointer :: points(:) 4867 PetscInt, pointer :: coveredPints(:) 4868 .ve 4869 4870 The `numCoveredPoints` argument is not present in the Fortran binding. 4871 4872 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4873 @*/ 4874 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4875 { 4876 PetscInt *offsets, **closures; 4877 PetscInt *join[2]; 4878 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4879 PetscInt p, d, c, m, ms; 4880 4881 PetscFunctionBegin; 4882 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4883 PetscAssertPointer(points, 3); 4884 PetscAssertPointer(numCoveredPoints, 4); 4885 PetscAssertPointer(coveredPoints, 5); 4886 4887 PetscCall(DMPlexGetDepth(dm, &depth)); 4888 PetscCall(PetscCalloc1(numPoints, &closures)); 4889 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4890 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4891 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4892 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4893 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4894 4895 for (p = 0; p < numPoints; ++p) { 4896 PetscInt closureSize; 4897 4898 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4899 4900 offsets[p * (depth + 2) + 0] = 0; 4901 for (d = 0; d < depth + 1; ++d) { 4902 PetscInt pStart, pEnd, i; 4903 4904 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4905 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4906 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4907 offsets[p * (depth + 2) + d + 1] = i; 4908 break; 4909 } 4910 } 4911 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4912 } 4913 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); 4914 } 4915 for (d = 0; d < depth + 1; ++d) { 4916 PetscInt dof; 4917 4918 /* Copy in support of first point */ 4919 dof = offsets[d + 1] - offsets[d]; 4920 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4921 /* Check each successive cone */ 4922 for (p = 1; p < numPoints && joinSize; ++p) { 4923 PetscInt newJoinSize = 0; 4924 4925 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4926 for (c = 0; c < dof; ++c) { 4927 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4928 4929 for (m = 0; m < joinSize; ++m) { 4930 if (point == join[i][m]) { 4931 join[1 - i][newJoinSize++] = point; 4932 break; 4933 } 4934 } 4935 } 4936 joinSize = newJoinSize; 4937 i = 1 - i; 4938 } 4939 if (joinSize) break; 4940 } 4941 *numCoveredPoints = joinSize; 4942 *coveredPoints = join[i]; 4943 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4944 PetscCall(PetscFree(closures)); 4945 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4946 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4947 PetscFunctionReturn(PETSC_SUCCESS); 4948 } 4949 4950 /*@C 4951 DMPlexGetMeet - Get an array for the meet of the set of points 4952 4953 Not Collective 4954 4955 Input Parameters: 4956 + dm - The `DMPLEX` object 4957 . numPoints - The number of input points for the meet 4958 - points - The input points, of length `numPoints` 4959 4960 Output Parameters: 4961 + numCoveringPoints - The number of points in the meet 4962 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4963 4964 Level: intermediate 4965 4966 Note: 4967 Currently, this is restricted to a single level meet 4968 4969 Fortran Notes: 4970 `coveringPoints` must be declared with 4971 .vb 4972 PetscInt, pointer :: coveringPoints(:) 4973 .ve 4974 4975 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4976 4977 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4978 @*/ 4979 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4980 { 4981 DM_Plex *mesh = (DM_Plex *)dm->data; 4982 PetscInt *meet[2]; 4983 PetscInt meetSize, i = 0; 4984 PetscInt dof, off, p, c, m; 4985 PetscInt maxConeSize; 4986 4987 PetscFunctionBegin; 4988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4989 PetscAssertPointer(points, 3); 4990 PetscAssertPointer(numCoveringPoints, 4); 4991 PetscAssertPointer(coveringPoints, 5); 4992 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4993 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4994 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4995 /* Copy in cone of first point */ 4996 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4997 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4998 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4999 /* Check each successive cone */ 5000 for (p = 1; p < numPoints; ++p) { 5001 PetscInt newMeetSize = 0; 5002 5003 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5004 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5005 for (c = 0; c < dof; ++c) { 5006 const PetscInt point = mesh->cones[off + c]; 5007 5008 for (m = 0; m < meetSize; ++m) { 5009 if (point == meet[i][m]) { 5010 meet[1 - i][newMeetSize++] = point; 5011 break; 5012 } 5013 } 5014 } 5015 meetSize = newMeetSize; 5016 i = 1 - i; 5017 } 5018 *numCoveringPoints = meetSize; 5019 *coveringPoints = meet[i]; 5020 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5021 PetscFunctionReturn(PETSC_SUCCESS); 5022 } 5023 5024 /*@C 5025 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5026 5027 Not Collective 5028 5029 Input Parameters: 5030 + dm - The `DMPLEX` object 5031 . numPoints - The number of input points for the meet 5032 - points - The input points 5033 5034 Output Parameters: 5035 + numCoveredPoints - The number of points in the meet 5036 - coveredPoints - The points in the meet 5037 5038 Level: intermediate 5039 5040 Fortran Notes: 5041 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5042 5043 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5044 @*/ 5045 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5046 { 5047 PetscFunctionBegin; 5048 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5049 if (points) PetscAssertPointer(points, 3); 5050 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5051 PetscAssertPointer(coveredPoints, 5); 5052 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5053 if (numCoveredPoints) *numCoveredPoints = 0; 5054 PetscFunctionReturn(PETSC_SUCCESS); 5055 } 5056 5057 /*@C 5058 DMPlexGetFullMeet - Get an array for the meet of the set of points 5059 5060 Not Collective 5061 5062 Input Parameters: 5063 + dm - The `DMPLEX` object 5064 . numPoints - The number of input points for the meet 5065 - points - The input points, of length `numPoints` 5066 5067 Output Parameters: 5068 + numCoveredPoints - The number of points in the meet 5069 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5070 5071 Level: intermediate 5072 5073 Fortran Notes: 5074 `points` and `coveredPoints` must be declared with 5075 .vb 5076 PetscInt, pointer :: points(:) 5077 PetscInt, pointer :: coveredPoints(:) 5078 .ve 5079 5080 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5081 5082 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5083 @*/ 5084 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5085 { 5086 PetscInt *offsets, **closures; 5087 PetscInt *meet[2]; 5088 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5089 PetscInt p, h, c, m, mc; 5090 5091 PetscFunctionBegin; 5092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5093 PetscAssertPointer(points, 3); 5094 PetscAssertPointer(numCoveredPoints, 4); 5095 PetscAssertPointer(coveredPoints, 5); 5096 5097 PetscCall(DMPlexGetDepth(dm, &height)); 5098 PetscCall(PetscMalloc1(numPoints, &closures)); 5099 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5100 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5101 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5102 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5103 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5104 5105 for (p = 0; p < numPoints; ++p) { 5106 PetscInt closureSize; 5107 5108 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5109 5110 offsets[p * (height + 2) + 0] = 0; 5111 for (h = 0; h < height + 1; ++h) { 5112 PetscInt pStart, pEnd, i; 5113 5114 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5115 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5116 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5117 offsets[p * (height + 2) + h + 1] = i; 5118 break; 5119 } 5120 } 5121 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5122 } 5123 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); 5124 } 5125 for (h = 0; h < height + 1; ++h) { 5126 PetscInt dof; 5127 5128 /* Copy in cone of first point */ 5129 dof = offsets[h + 1] - offsets[h]; 5130 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5131 /* Check each successive cone */ 5132 for (p = 1; p < numPoints && meetSize; ++p) { 5133 PetscInt newMeetSize = 0; 5134 5135 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5136 for (c = 0; c < dof; ++c) { 5137 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5138 5139 for (m = 0; m < meetSize; ++m) { 5140 if (point == meet[i][m]) { 5141 meet[1 - i][newMeetSize++] = point; 5142 break; 5143 } 5144 } 5145 } 5146 meetSize = newMeetSize; 5147 i = 1 - i; 5148 } 5149 if (meetSize) break; 5150 } 5151 *numCoveredPoints = meetSize; 5152 *coveredPoints = meet[i]; 5153 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5154 PetscCall(PetscFree(closures)); 5155 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5156 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5157 PetscFunctionReturn(PETSC_SUCCESS); 5158 } 5159 5160 /*@ 5161 DMPlexEqual - Determine if two `DM` have the same topology 5162 5163 Not Collective 5164 5165 Input Parameters: 5166 + dmA - A `DMPLEX` object 5167 - dmB - A `DMPLEX` object 5168 5169 Output Parameter: 5170 . equal - `PETSC_TRUE` if the topologies are identical 5171 5172 Level: intermediate 5173 5174 Note: 5175 We are not solving graph isomorphism, so we do not permute. 5176 5177 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5178 @*/ 5179 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5180 { 5181 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5182 5183 PetscFunctionBegin; 5184 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5185 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5186 PetscAssertPointer(equal, 3); 5187 5188 *equal = PETSC_FALSE; 5189 PetscCall(DMPlexGetDepth(dmA, &depth)); 5190 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5191 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5192 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5193 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5194 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5195 for (p = pStart; p < pEnd; ++p) { 5196 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5197 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5198 5199 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5200 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5201 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5202 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5203 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5204 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5205 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5206 for (c = 0; c < coneSize; ++c) { 5207 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5208 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5209 } 5210 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5211 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5212 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5213 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5214 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5215 for (s = 0; s < supportSize; ++s) { 5216 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5217 } 5218 } 5219 *equal = PETSC_TRUE; 5220 PetscFunctionReturn(PETSC_SUCCESS); 5221 } 5222 5223 /*@ 5224 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5225 5226 Not Collective 5227 5228 Input Parameters: 5229 + dm - The `DMPLEX` 5230 . cellDim - The cell dimension 5231 - numCorners - The number of vertices on a cell 5232 5233 Output Parameter: 5234 . numFaceVertices - The number of vertices on a face 5235 5236 Level: developer 5237 5238 Note: 5239 Of course this can only work for a restricted set of symmetric shapes 5240 5241 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5242 @*/ 5243 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5244 { 5245 MPI_Comm comm; 5246 5247 PetscFunctionBegin; 5248 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5249 PetscAssertPointer(numFaceVertices, 4); 5250 switch (cellDim) { 5251 case 0: 5252 *numFaceVertices = 0; 5253 break; 5254 case 1: 5255 *numFaceVertices = 1; 5256 break; 5257 case 2: 5258 switch (numCorners) { 5259 case 3: /* triangle */ 5260 *numFaceVertices = 2; /* Edge has 2 vertices */ 5261 break; 5262 case 4: /* quadrilateral */ 5263 *numFaceVertices = 2; /* Edge has 2 vertices */ 5264 break; 5265 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5266 *numFaceVertices = 3; /* Edge has 3 vertices */ 5267 break; 5268 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5269 *numFaceVertices = 3; /* Edge has 3 vertices */ 5270 break; 5271 default: 5272 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5273 } 5274 break; 5275 case 3: 5276 switch (numCorners) { 5277 case 4: /* tetradehdron */ 5278 *numFaceVertices = 3; /* Face has 3 vertices */ 5279 break; 5280 case 6: /* tet cohesive cells */ 5281 *numFaceVertices = 4; /* Face has 4 vertices */ 5282 break; 5283 case 8: /* hexahedron */ 5284 *numFaceVertices = 4; /* Face has 4 vertices */ 5285 break; 5286 case 9: /* tet cohesive Lagrange cells */ 5287 *numFaceVertices = 6; /* Face has 6 vertices */ 5288 break; 5289 case 10: /* quadratic tetrahedron */ 5290 *numFaceVertices = 6; /* Face has 6 vertices */ 5291 break; 5292 case 12: /* hex cohesive Lagrange cells */ 5293 *numFaceVertices = 6; /* Face has 6 vertices */ 5294 break; 5295 case 18: /* quadratic tet cohesive Lagrange cells */ 5296 *numFaceVertices = 6; /* Face has 6 vertices */ 5297 break; 5298 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5299 *numFaceVertices = 9; /* Face has 9 vertices */ 5300 break; 5301 default: 5302 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5303 } 5304 break; 5305 default: 5306 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5307 } 5308 PetscFunctionReturn(PETSC_SUCCESS); 5309 } 5310 5311 /*@ 5312 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5313 5314 Not Collective 5315 5316 Input Parameter: 5317 . dm - The `DMPLEX` object 5318 5319 Output Parameter: 5320 . depthLabel - The `DMLabel` recording point depth 5321 5322 Level: developer 5323 5324 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5325 @*/ 5326 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5327 { 5328 PetscFunctionBegin; 5329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5330 PetscAssertPointer(depthLabel, 2); 5331 *depthLabel = dm->depthLabel; 5332 PetscFunctionReturn(PETSC_SUCCESS); 5333 } 5334 5335 /*@ 5336 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5337 5338 Not Collective 5339 5340 Input Parameter: 5341 . dm - The `DMPLEX` object 5342 5343 Output Parameter: 5344 . depth - The number of strata (breadth first levels) in the DAG 5345 5346 Level: developer 5347 5348 Notes: 5349 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5350 5351 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5352 5353 An empty mesh gives -1. 5354 5355 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5356 @*/ 5357 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5358 { 5359 DM_Plex *mesh = (DM_Plex *)dm->data; 5360 DMLabel label; 5361 PetscInt d = -1; 5362 5363 PetscFunctionBegin; 5364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5365 PetscAssertPointer(depth, 2); 5366 if (mesh->tr) { 5367 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5368 } else { 5369 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5370 // Allow missing depths 5371 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5372 *depth = d; 5373 } 5374 PetscFunctionReturn(PETSC_SUCCESS); 5375 } 5376 5377 /*@ 5378 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5379 5380 Not Collective 5381 5382 Input Parameters: 5383 + dm - The `DMPLEX` object 5384 - depth - The requested depth 5385 5386 Output Parameters: 5387 + start - The first point at this `depth` 5388 - end - One beyond the last point at this `depth` 5389 5390 Level: developer 5391 5392 Notes: 5393 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5394 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5395 higher dimension, e.g., "edges". 5396 5397 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5398 @*/ 5399 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5400 { 5401 DM_Plex *mesh = (DM_Plex *)dm->data; 5402 DMLabel label; 5403 PetscInt pStart, pEnd; 5404 5405 PetscFunctionBegin; 5406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5407 if (start) { 5408 PetscAssertPointer(start, 3); 5409 *start = 0; 5410 } 5411 if (end) { 5412 PetscAssertPointer(end, 4); 5413 *end = 0; 5414 } 5415 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5416 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5417 if (depth < 0) { 5418 if (start) *start = pStart; 5419 if (end) *end = pEnd; 5420 PetscFunctionReturn(PETSC_SUCCESS); 5421 } 5422 if (mesh->tr) { 5423 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5424 } else { 5425 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5426 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5427 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5428 } 5429 PetscFunctionReturn(PETSC_SUCCESS); 5430 } 5431 5432 /*@ 5433 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5434 5435 Not Collective 5436 5437 Input Parameters: 5438 + dm - The `DMPLEX` object 5439 - height - The requested height 5440 5441 Output Parameters: 5442 + start - The first point at this `height` 5443 - end - One beyond the last point at this `height` 5444 5445 Level: developer 5446 5447 Notes: 5448 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5449 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5450 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5451 5452 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5453 @*/ 5454 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5455 { 5456 DMLabel label; 5457 PetscInt depth, pStart, pEnd; 5458 5459 PetscFunctionBegin; 5460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5461 if (start) { 5462 PetscAssertPointer(start, 3); 5463 *start = 0; 5464 } 5465 if (end) { 5466 PetscAssertPointer(end, 4); 5467 *end = 0; 5468 } 5469 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5470 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5471 if (height < 0) { 5472 if (start) *start = pStart; 5473 if (end) *end = pEnd; 5474 PetscFunctionReturn(PETSC_SUCCESS); 5475 } 5476 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5477 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5478 else PetscCall(DMGetDimension(dm, &depth)); 5479 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5480 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5481 PetscFunctionReturn(PETSC_SUCCESS); 5482 } 5483 5484 /*@ 5485 DMPlexGetPointDepth - Get the `depth` 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 . depth - The depth of the `point` 5495 5496 Level: intermediate 5497 5498 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5499 @*/ 5500 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5501 { 5502 PetscFunctionBegin; 5503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5504 PetscAssertPointer(depth, 3); 5505 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5506 PetscFunctionReturn(PETSC_SUCCESS); 5507 } 5508 5509 /*@ 5510 DMPlexGetPointHeight - Get the `height` of a given point 5511 5512 Not Collective 5513 5514 Input Parameters: 5515 + dm - The `DMPLEX` object 5516 - point - The point 5517 5518 Output Parameter: 5519 . height - The height of the `point` 5520 5521 Level: intermediate 5522 5523 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5524 @*/ 5525 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5526 { 5527 PetscInt n, pDepth; 5528 5529 PetscFunctionBegin; 5530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5531 PetscAssertPointer(height, 3); 5532 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5533 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5534 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5535 PetscFunctionReturn(PETSC_SUCCESS); 5536 } 5537 5538 /*@ 5539 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5540 5541 Not Collective 5542 5543 Input Parameter: 5544 . dm - The `DMPLEX` object 5545 5546 Output Parameter: 5547 . celltypeLabel - The `DMLabel` recording cell polytope type 5548 5549 Level: developer 5550 5551 Note: 5552 This function will trigger automatica computation of cell types. This can be disabled by calling 5553 `DMCreateLabel`(dm, "celltype") beforehand. 5554 5555 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5556 @*/ 5557 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5558 { 5559 PetscFunctionBegin; 5560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5561 PetscAssertPointer(celltypeLabel, 2); 5562 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5563 *celltypeLabel = dm->celltypeLabel; 5564 PetscFunctionReturn(PETSC_SUCCESS); 5565 } 5566 5567 /*@ 5568 DMPlexGetCellType - Get the polytope type of a given cell 5569 5570 Not Collective 5571 5572 Input Parameters: 5573 + dm - The `DMPLEX` object 5574 - cell - The cell 5575 5576 Output Parameter: 5577 . celltype - The polytope type of the cell 5578 5579 Level: intermediate 5580 5581 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5582 @*/ 5583 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5584 { 5585 DM_Plex *mesh = (DM_Plex *)dm->data; 5586 DMLabel label; 5587 PetscInt ct; 5588 5589 PetscFunctionBegin; 5590 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5591 PetscAssertPointer(celltype, 3); 5592 if (mesh->tr) { 5593 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5594 } else { 5595 PetscInt pStart, pEnd; 5596 5597 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5598 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5599 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5600 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5601 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5602 for (PetscInt p = pStart; p < pEnd; p++) { 5603 PetscCall(DMLabelGetValue(label, p, &ct)); 5604 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5605 } 5606 } 5607 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5608 if (PetscDefined(USE_DEBUG)) { 5609 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5610 PetscCall(DMLabelGetValue(label, cell, &ct)); 5611 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5612 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5613 } 5614 } 5615 PetscFunctionReturn(PETSC_SUCCESS); 5616 } 5617 5618 /*@ 5619 DMPlexSetCellType - Set the polytope type of a given cell 5620 5621 Not Collective 5622 5623 Input Parameters: 5624 + dm - The `DMPLEX` object 5625 . cell - The cell 5626 - celltype - The polytope type of the cell 5627 5628 Level: advanced 5629 5630 Note: 5631 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5632 is executed. This function will override the computed type. However, if automatic classification will not succeed 5633 and a user wants to manually specify all types, the classification must be disabled by calling 5634 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5635 5636 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5637 @*/ 5638 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5639 { 5640 DM_Plex *mesh = (DM_Plex *)dm->data; 5641 DMLabel label; 5642 PetscInt pStart, pEnd; 5643 5644 PetscFunctionBegin; 5645 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5646 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5647 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5648 PetscCall(DMLabelSetValue(label, cell, celltype)); 5649 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5650 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5651 PetscFunctionReturn(PETSC_SUCCESS); 5652 } 5653 5654 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5655 { 5656 PetscSection section; 5657 PetscInt maxHeight; 5658 const char *prefix; 5659 5660 PetscFunctionBegin; 5661 PetscCall(DMClone(dm, cdm)); 5662 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5663 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5664 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5665 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5666 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5667 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5668 PetscCall(DMSetLocalSection(*cdm, section)); 5669 PetscCall(PetscSectionDestroy(§ion)); 5670 5671 PetscCall(DMSetNumFields(*cdm, 1)); 5672 PetscCall(DMCreateDS(*cdm)); 5673 (*cdm)->cloneOpts = PETSC_TRUE; 5674 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5675 PetscFunctionReturn(PETSC_SUCCESS); 5676 } 5677 5678 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5679 { 5680 Vec coordsLocal, cellCoordsLocal; 5681 DM coordsDM, cellCoordsDM; 5682 5683 PetscFunctionBegin; 5684 *field = NULL; 5685 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5686 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5687 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5688 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5689 if (coordsLocal && coordsDM) { 5690 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5691 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5692 } 5693 PetscFunctionReturn(PETSC_SUCCESS); 5694 } 5695 5696 /*@ 5697 DMPlexGetConeSection - Return a section which describes the layout of cone 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`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5710 @*/ 5711 PetscErrorCode DMPlexGetConeSection(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->coneSection; 5718 PetscFunctionReturn(PETSC_SUCCESS); 5719 } 5720 5721 /*@ 5722 DMPlexGetSupportSection - Return a section which describes the layout of support data 5723 5724 Not Collective 5725 5726 Input Parameter: 5727 . dm - The `DMPLEX` object 5728 5729 Output Parameter: 5730 . section - The `PetscSection` object 5731 5732 Level: developer 5733 5734 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5735 @*/ 5736 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5737 { 5738 DM_Plex *mesh = (DM_Plex *)dm->data; 5739 5740 PetscFunctionBegin; 5741 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5742 if (section) *section = mesh->supportSection; 5743 PetscFunctionReturn(PETSC_SUCCESS); 5744 } 5745 5746 /*@C 5747 DMPlexGetCones - Return cone data 5748 5749 Not Collective 5750 5751 Input Parameter: 5752 . dm - The `DMPLEX` object 5753 5754 Output Parameter: 5755 . cones - The cone for each point 5756 5757 Level: developer 5758 5759 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5760 @*/ 5761 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5762 { 5763 DM_Plex *mesh = (DM_Plex *)dm->data; 5764 5765 PetscFunctionBegin; 5766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5767 if (cones) *cones = mesh->cones; 5768 PetscFunctionReturn(PETSC_SUCCESS); 5769 } 5770 5771 /*@C 5772 DMPlexGetConeOrientations - Return cone orientation data 5773 5774 Not Collective 5775 5776 Input Parameter: 5777 . dm - The `DMPLEX` object 5778 5779 Output Parameter: 5780 . coneOrientations - The array of cone orientations for all points 5781 5782 Level: developer 5783 5784 Notes: 5785 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5786 as returned by `DMPlexGetConeOrientation()`. 5787 5788 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5789 5790 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5791 @*/ 5792 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5793 { 5794 DM_Plex *mesh = (DM_Plex *)dm->data; 5795 5796 PetscFunctionBegin; 5797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5798 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5799 PetscFunctionReturn(PETSC_SUCCESS); 5800 } 5801 5802 /* FEM Support */ 5803 5804 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5805 { 5806 PetscInt depth; 5807 5808 PetscFunctionBegin; 5809 PetscCall(DMPlexGetDepth(plex, &depth)); 5810 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5811 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5812 PetscFunctionReturn(PETSC_SUCCESS); 5813 } 5814 5815 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5816 { 5817 PetscInt depth; 5818 5819 PetscFunctionBegin; 5820 PetscCall(DMPlexGetDepth(plex, &depth)); 5821 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5822 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5823 PetscFunctionReturn(PETSC_SUCCESS); 5824 } 5825 5826 /* 5827 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5828 representing a line in the section. 5829 */ 5830 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5831 { 5832 PetscObject obj; 5833 PetscClassId id; 5834 PetscFE fe = NULL; 5835 5836 PetscFunctionBeginHot; 5837 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5838 PetscCall(DMGetField(dm, field, NULL, &obj)); 5839 PetscCall(PetscObjectGetClassId(obj, &id)); 5840 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5841 5842 if (!fe) { 5843 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5844 /* An order k SEM disc has k-1 dofs on an edge */ 5845 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5846 *k = *k / *Nc + 1; 5847 } else { 5848 PetscInt dual_space_size, dim; 5849 PetscDualSpace dsp; 5850 5851 PetscCall(DMGetDimension(dm, &dim)); 5852 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5853 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5854 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5855 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5856 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5857 } 5858 PetscFunctionReturn(PETSC_SUCCESS); 5859 } 5860 5861 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5862 { 5863 PetscFunctionBeginHot; 5864 if (tensor) { 5865 *dof = PetscPowInt(k + 1, dim); 5866 } else { 5867 switch (dim) { 5868 case 1: 5869 *dof = k + 1; 5870 break; 5871 case 2: 5872 *dof = ((k + 1) * (k + 2)) / 2; 5873 break; 5874 case 3: 5875 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5876 break; 5877 default: 5878 *dof = 0; 5879 } 5880 } 5881 PetscFunctionReturn(PETSC_SUCCESS); 5882 } 5883 5884 /*@ 5885 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5886 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5887 section provided (or the section of the `DM`). 5888 5889 Input Parameters: 5890 + dm - The `DM` 5891 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5892 - section - The `PetscSection` to reorder, or `NULL` for the default section 5893 5894 Example: 5895 A typical interpolated single-quad mesh might order points as 5896 .vb 5897 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5898 5899 v4 -- e6 -- v3 5900 | | 5901 e7 c0 e8 5902 | | 5903 v1 -- e5 -- v2 5904 .ve 5905 5906 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5907 dofs in the order of points, e.g., 5908 .vb 5909 c0 -> [0,1,2,3] 5910 v1 -> [4] 5911 ... 5912 e5 -> [8, 9] 5913 .ve 5914 5915 which corresponds to the dofs 5916 .vb 5917 6 10 11 7 5918 13 2 3 15 5919 12 0 1 14 5920 4 8 9 5 5921 .ve 5922 5923 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5924 .vb 5925 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5926 .ve 5927 5928 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5929 .vb 5930 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5931 .ve 5932 5933 Level: developer 5934 5935 Notes: 5936 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5937 degree of the basis. 5938 5939 This is required to run with libCEED. 5940 5941 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5942 @*/ 5943 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5944 { 5945 DMLabel label; 5946 PetscInt dim, depth = -1, eStart = -1, Nf; 5947 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5948 5949 PetscFunctionBegin; 5950 PetscCall(DMGetDimension(dm, &dim)); 5951 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5952 if (point < 0) { 5953 PetscInt sStart, sEnd; 5954 5955 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5956 point = sEnd - sStart ? sStart : point; 5957 } 5958 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5959 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5960 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5961 if (depth == 1) { 5962 eStart = point; 5963 } else if (depth == dim) { 5964 const PetscInt *cone; 5965 5966 PetscCall(DMPlexGetCone(dm, point, &cone)); 5967 if (dim == 2) eStart = cone[0]; 5968 else if (dim == 3) { 5969 const PetscInt *cone2; 5970 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5971 eStart = cone2[0]; 5972 } 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); 5973 } 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); 5974 5975 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5976 for (PetscInt d = 1; d <= dim; d++) { 5977 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5978 PetscInt *perm; 5979 5980 for (f = 0; f < Nf; ++f) { 5981 PetscInt dof; 5982 5983 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5984 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5985 if (!continuous && d < dim) continue; 5986 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5987 size += dof * Nc; 5988 } 5989 PetscCall(PetscMalloc1(size, &perm)); 5990 for (f = 0; f < Nf; ++f) { 5991 switch (d) { 5992 case 1: 5993 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5994 if (!continuous && d < dim) continue; 5995 /* 5996 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5997 We want [ vtx0; edge of length k-1; vtx1 ] 5998 */ 5999 if (continuous) { 6000 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6001 for (i = 0; i < k - 1; i++) 6002 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6003 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6004 foffset = offset; 6005 } else { 6006 PetscInt dof; 6007 6008 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6009 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6010 foffset = offset; 6011 } 6012 break; 6013 case 2: 6014 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6015 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6016 if (!continuous && d < dim) continue; 6017 /* The SEM order is 6018 6019 v_lb, {e_b}, v_rb, 6020 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6021 v_lt, reverse {e_t}, v_rt 6022 */ 6023 if (continuous) { 6024 const PetscInt of = 0; 6025 const PetscInt oeb = of + PetscSqr(k - 1); 6026 const PetscInt oer = oeb + (k - 1); 6027 const PetscInt oet = oer + (k - 1); 6028 const PetscInt oel = oet + (k - 1); 6029 const PetscInt ovlb = oel + (k - 1); 6030 const PetscInt ovrb = ovlb + 1; 6031 const PetscInt ovrt = ovrb + 1; 6032 const PetscInt ovlt = ovrt + 1; 6033 PetscInt o; 6034 6035 /* bottom */ 6036 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6037 for (o = oeb; o < oer; ++o) 6038 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6039 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6040 /* middle */ 6041 for (i = 0; i < k - 1; ++i) { 6042 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6043 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6044 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6046 } 6047 /* top */ 6048 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6049 for (o = oel - 1; o >= oet; --o) 6050 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6051 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6052 foffset = offset; 6053 } else { 6054 PetscInt dof; 6055 6056 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6057 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6058 foffset = offset; 6059 } 6060 break; 6061 case 3: 6062 /* The original hex closure is 6063 6064 {c, 6065 f_b, f_t, f_f, f_b, f_r, f_l, 6066 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6067 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6068 */ 6069 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6070 if (!continuous && d < dim) continue; 6071 /* The SEM order is 6072 Bottom Slice 6073 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6074 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6075 v_blb, {e_bb}, v_brb, 6076 6077 Middle Slice (j) 6078 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6079 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6080 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6081 6082 Top Slice 6083 v_tlf, {e_tf}, v_trf, 6084 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6085 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6086 */ 6087 if (continuous) { 6088 const PetscInt oc = 0; 6089 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6090 const PetscInt oft = ofb + PetscSqr(k - 1); 6091 const PetscInt off = oft + PetscSqr(k - 1); 6092 const PetscInt ofk = off + PetscSqr(k - 1); 6093 const PetscInt ofr = ofk + PetscSqr(k - 1); 6094 const PetscInt ofl = ofr + PetscSqr(k - 1); 6095 const PetscInt oebl = ofl + PetscSqr(k - 1); 6096 const PetscInt oebb = oebl + (k - 1); 6097 const PetscInt oebr = oebb + (k - 1); 6098 const PetscInt oebf = oebr + (k - 1); 6099 const PetscInt oetf = oebf + (k - 1); 6100 const PetscInt oetr = oetf + (k - 1); 6101 const PetscInt oetb = oetr + (k - 1); 6102 const PetscInt oetl = oetb + (k - 1); 6103 const PetscInt oerf = oetl + (k - 1); 6104 const PetscInt oelf = oerf + (k - 1); 6105 const PetscInt oelb = oelf + (k - 1); 6106 const PetscInt oerb = oelb + (k - 1); 6107 const PetscInt ovblf = oerb + (k - 1); 6108 const PetscInt ovblb = ovblf + 1; 6109 const PetscInt ovbrb = ovblb + 1; 6110 const PetscInt ovbrf = ovbrb + 1; 6111 const PetscInt ovtlf = ovbrf + 1; 6112 const PetscInt ovtrf = ovtlf + 1; 6113 const PetscInt ovtrb = ovtrf + 1; 6114 const PetscInt ovtlb = ovtrb + 1; 6115 PetscInt o, n; 6116 6117 /* Bottom Slice */ 6118 /* bottom */ 6119 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6120 for (o = oetf - 1; o >= oebf; --o) 6121 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6122 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6123 /* middle */ 6124 for (i = 0; i < k - 1; ++i) { 6125 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6126 for (n = 0; n < k - 1; ++n) { 6127 o = ofb + n * (k - 1) + i; 6128 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6129 } 6130 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6131 } 6132 /* top */ 6133 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6134 for (o = oebb; o < oebr; ++o) 6135 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6137 6138 /* Middle Slice */ 6139 for (j = 0; j < k - 1; ++j) { 6140 /* bottom */ 6141 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6142 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6143 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6144 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6145 /* middle */ 6146 for (i = 0; i < k - 1; ++i) { 6147 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6148 for (n = 0; n < k - 1; ++n) 6149 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6150 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6151 } 6152 /* top */ 6153 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6154 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6155 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6156 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6157 } 6158 6159 /* Top Slice */ 6160 /* bottom */ 6161 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6162 for (o = oetf; o < oetr; ++o) 6163 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6164 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6165 /* middle */ 6166 for (i = 0; i < k - 1; ++i) { 6167 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6168 for (n = 0; n < k - 1; ++n) 6169 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6170 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6171 } 6172 /* top */ 6173 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6174 for (o = oetl - 1; o >= oetb; --o) 6175 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6176 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6177 6178 foffset = offset; 6179 } else { 6180 PetscInt dof; 6181 6182 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6183 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6184 foffset = offset; 6185 } 6186 break; 6187 default: 6188 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6189 } 6190 } 6191 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6192 /* Check permutation */ 6193 { 6194 PetscInt *check; 6195 6196 PetscCall(PetscMalloc1(size, &check)); 6197 for (i = 0; i < size; ++i) { 6198 check[i] = -1; 6199 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6200 } 6201 for (i = 0; i < size; ++i) check[perm[i]] = i; 6202 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6203 PetscCall(PetscFree(check)); 6204 } 6205 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6206 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6207 PetscInt *loc_perm; 6208 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6209 for (PetscInt i = 0; i < size; i++) { 6210 loc_perm[i] = perm[i]; 6211 loc_perm[size + i] = size + perm[i]; 6212 } 6213 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6214 } 6215 } 6216 PetscFunctionReturn(PETSC_SUCCESS); 6217 } 6218 6219 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6220 { 6221 PetscDS prob; 6222 PetscInt depth, Nf, h; 6223 DMLabel label; 6224 6225 PetscFunctionBeginHot; 6226 PetscCall(DMGetDS(dm, &prob)); 6227 Nf = prob->Nf; 6228 label = dm->depthLabel; 6229 *dspace = NULL; 6230 if (field < Nf) { 6231 PetscObject disc = prob->disc[field]; 6232 6233 if (disc->classid == PETSCFE_CLASSID) { 6234 PetscDualSpace dsp; 6235 6236 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6237 PetscCall(DMLabelGetNumValues(label, &depth)); 6238 PetscCall(DMLabelGetValue(label, point, &h)); 6239 h = depth - 1 - h; 6240 if (h) { 6241 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6242 } else { 6243 *dspace = dsp; 6244 } 6245 } 6246 } 6247 PetscFunctionReturn(PETSC_SUCCESS); 6248 } 6249 6250 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6251 { 6252 PetscScalar *array; 6253 const PetscScalar *vArray; 6254 const PetscInt *cone, *coneO; 6255 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6256 6257 PetscFunctionBeginHot; 6258 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6259 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6260 PetscCall(DMPlexGetCone(dm, point, &cone)); 6261 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6262 if (!values || !*values) { 6263 if ((point >= pStart) && (point < pEnd)) { 6264 PetscInt dof; 6265 6266 PetscCall(PetscSectionGetDof(section, point, &dof)); 6267 size += dof; 6268 } 6269 for (p = 0; p < numPoints; ++p) { 6270 const PetscInt cp = cone[p]; 6271 PetscInt dof; 6272 6273 if ((cp < pStart) || (cp >= pEnd)) continue; 6274 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6275 size += dof; 6276 } 6277 if (!values) { 6278 if (csize) *csize = size; 6279 PetscFunctionReturn(PETSC_SUCCESS); 6280 } 6281 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6282 } else { 6283 array = *values; 6284 } 6285 size = 0; 6286 PetscCall(VecGetArrayRead(v, &vArray)); 6287 if ((point >= pStart) && (point < pEnd)) { 6288 PetscInt dof, off, d; 6289 const PetscScalar *varr; 6290 6291 PetscCall(PetscSectionGetDof(section, point, &dof)); 6292 PetscCall(PetscSectionGetOffset(section, point, &off)); 6293 varr = PetscSafePointerPlusOffset(vArray, off); 6294 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6295 size += dof; 6296 } 6297 for (p = 0; p < numPoints; ++p) { 6298 const PetscInt cp = cone[p]; 6299 PetscInt o = coneO[p]; 6300 PetscInt dof, off, d; 6301 const PetscScalar *varr; 6302 6303 if ((cp < pStart) || (cp >= pEnd)) continue; 6304 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6305 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6306 varr = PetscSafePointerPlusOffset(vArray, off); 6307 if (o >= 0) { 6308 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6309 } else { 6310 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6311 } 6312 size += dof; 6313 } 6314 PetscCall(VecRestoreArrayRead(v, &vArray)); 6315 if (!*values) { 6316 if (csize) *csize = size; 6317 *values = array; 6318 } else { 6319 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6320 *csize = size; 6321 } 6322 PetscFunctionReturn(PETSC_SUCCESS); 6323 } 6324 6325 /* Compress out points not in the section */ 6326 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6327 { 6328 const PetscInt np = *numPoints; 6329 PetscInt pStart, pEnd, p, q; 6330 6331 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6332 for (p = 0, q = 0; p < np; ++p) { 6333 const PetscInt r = points[p * 2]; 6334 if ((r >= pStart) && (r < pEnd)) { 6335 points[q * 2] = r; 6336 points[q * 2 + 1] = points[p * 2 + 1]; 6337 ++q; 6338 } 6339 } 6340 *numPoints = q; 6341 return PETSC_SUCCESS; 6342 } 6343 6344 /* Compressed closure does not apply closure permutation */ 6345 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6346 { 6347 const PetscInt *cla = NULL; 6348 PetscInt np, *pts = NULL; 6349 6350 PetscFunctionBeginHot; 6351 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6352 if (!ornt && *clPoints) { 6353 PetscInt dof, off; 6354 6355 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6356 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6357 PetscCall(ISGetIndices(*clPoints, &cla)); 6358 np = dof / 2; 6359 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6360 } else { 6361 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6362 PetscCall(CompressPoints_Private(section, &np, pts)); 6363 } 6364 *numPoints = np; 6365 *points = pts; 6366 *clp = cla; 6367 PetscFunctionReturn(PETSC_SUCCESS); 6368 } 6369 6370 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6371 { 6372 PetscFunctionBeginHot; 6373 if (!*clPoints) { 6374 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6375 } else { 6376 PetscCall(ISRestoreIndices(*clPoints, clp)); 6377 } 6378 *numPoints = 0; 6379 *points = NULL; 6380 *clSec = NULL; 6381 *clPoints = NULL; 6382 *clp = NULL; 6383 PetscFunctionReturn(PETSC_SUCCESS); 6384 } 6385 6386 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6387 { 6388 PetscInt offset = 0, p; 6389 const PetscInt **perms = NULL; 6390 const PetscScalar **flips = NULL; 6391 6392 PetscFunctionBeginHot; 6393 *size = 0; 6394 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6395 for (p = 0; p < numPoints; p++) { 6396 const PetscInt point = points[2 * p]; 6397 const PetscInt *perm = perms ? perms[p] : NULL; 6398 const PetscScalar *flip = flips ? flips[p] : NULL; 6399 PetscInt dof, off, d; 6400 const PetscScalar *varr; 6401 6402 PetscCall(PetscSectionGetDof(section, point, &dof)); 6403 PetscCall(PetscSectionGetOffset(section, point, &off)); 6404 varr = PetscSafePointerPlusOffset(vArray, off); 6405 if (clperm) { 6406 if (perm) { 6407 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6408 } else { 6409 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6410 } 6411 if (flip) { 6412 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6413 } 6414 } else { 6415 if (perm) { 6416 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6417 } else { 6418 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6419 } 6420 if (flip) { 6421 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6422 } 6423 } 6424 offset += dof; 6425 } 6426 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6427 *size = offset; 6428 PetscFunctionReturn(PETSC_SUCCESS); 6429 } 6430 6431 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[]) 6432 { 6433 PetscInt offset = 0, f; 6434 6435 PetscFunctionBeginHot; 6436 *size = 0; 6437 for (f = 0; f < numFields; ++f) { 6438 PetscInt p; 6439 const PetscInt **perms = NULL; 6440 const PetscScalar **flips = NULL; 6441 6442 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6443 for (p = 0; p < numPoints; p++) { 6444 const PetscInt point = points[2 * p]; 6445 PetscInt fdof, foff, b; 6446 const PetscScalar *varr; 6447 const PetscInt *perm = perms ? perms[p] : NULL; 6448 const PetscScalar *flip = flips ? flips[p] : NULL; 6449 6450 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6451 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6452 varr = &vArray[foff]; 6453 if (clperm) { 6454 if (perm) { 6455 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6456 } else { 6457 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6458 } 6459 if (flip) { 6460 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6461 } 6462 } else { 6463 if (perm) { 6464 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6465 } else { 6466 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6467 } 6468 if (flip) { 6469 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6470 } 6471 } 6472 offset += fdof; 6473 } 6474 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6475 } 6476 *size = offset; 6477 PetscFunctionReturn(PETSC_SUCCESS); 6478 } 6479 6480 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6481 { 6482 PetscSection clSection; 6483 IS clPoints; 6484 PetscInt *points = NULL; 6485 const PetscInt *clp, *perm = NULL; 6486 PetscInt depth, numFields, numPoints, asize; 6487 6488 PetscFunctionBeginHot; 6489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6490 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6491 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6492 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6493 PetscCall(DMPlexGetDepth(dm, &depth)); 6494 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6495 if (depth == 1 && numFields < 2) { 6496 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6497 PetscFunctionReturn(PETSC_SUCCESS); 6498 } 6499 /* Get points */ 6500 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6501 /* Get sizes */ 6502 asize = 0; 6503 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6504 PetscInt dof; 6505 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6506 asize += dof; 6507 } 6508 if (values) { 6509 const PetscScalar *vArray; 6510 PetscInt size; 6511 6512 if (*values) { 6513 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); 6514 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6515 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6516 PetscCall(VecGetArrayRead(v, &vArray)); 6517 /* Get values */ 6518 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6519 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6520 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6521 /* Cleanup array */ 6522 PetscCall(VecRestoreArrayRead(v, &vArray)); 6523 } 6524 if (csize) *csize = asize; 6525 /* Cleanup points */ 6526 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6527 PetscFunctionReturn(PETSC_SUCCESS); 6528 } 6529 6530 /*@C 6531 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6532 6533 Not collective 6534 6535 Input Parameters: 6536 + dm - The `DM` 6537 . section - The section describing the layout in `v`, or `NULL` to use the default section 6538 . v - The local vector 6539 - point - The point in the `DM` 6540 6541 Input/Output Parameters: 6542 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6543 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6544 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6545 6546 Level: intermediate 6547 6548 Notes: 6549 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6550 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6551 assembly function, and a user may already have allocated storage for this operation. 6552 6553 A typical use could be 6554 .vb 6555 values = NULL; 6556 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6557 for (cl = 0; cl < clSize; ++cl) { 6558 <Compute on closure> 6559 } 6560 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6561 .ve 6562 or 6563 .vb 6564 PetscMalloc1(clMaxSize, &values); 6565 for (p = pStart; p < pEnd; ++p) { 6566 clSize = clMaxSize; 6567 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6568 for (cl = 0; cl < clSize; ++cl) { 6569 <Compute on closure> 6570 } 6571 } 6572 PetscFree(values); 6573 .ve 6574 6575 Fortran Notes: 6576 The `csize` argument is not present in the Fortran binding. 6577 6578 `values` must be declared with 6579 .vb 6580 PetscScalar,dimension(:),pointer :: values 6581 .ve 6582 and it will be allocated internally by PETSc to hold the values returned 6583 6584 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6585 @*/ 6586 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6587 { 6588 PetscFunctionBeginHot; 6589 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6590 PetscFunctionReturn(PETSC_SUCCESS); 6591 } 6592 6593 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6594 { 6595 DMLabel depthLabel; 6596 PetscSection clSection; 6597 IS clPoints; 6598 PetscScalar *array; 6599 const PetscScalar *vArray; 6600 PetscInt *points = NULL; 6601 const PetscInt *clp, *perm = NULL; 6602 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6603 6604 PetscFunctionBeginHot; 6605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6606 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6607 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6608 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6609 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6610 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6612 if (mdepth == 1 && numFields < 2) { 6613 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6614 PetscFunctionReturn(PETSC_SUCCESS); 6615 } 6616 /* Get points */ 6617 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6618 for (clsize = 0, p = 0; p < Np; p++) { 6619 PetscInt dof; 6620 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6621 clsize += dof; 6622 } 6623 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6624 /* Filter points */ 6625 for (p = 0; p < numPoints * 2; p += 2) { 6626 PetscInt dep; 6627 6628 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6629 if (dep != depth) continue; 6630 points[Np * 2 + 0] = points[p]; 6631 points[Np * 2 + 1] = points[p + 1]; 6632 ++Np; 6633 } 6634 /* Get array */ 6635 if (!values || !*values) { 6636 PetscInt asize = 0, dof; 6637 6638 for (p = 0; p < Np * 2; p += 2) { 6639 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6640 asize += dof; 6641 } 6642 if (!values) { 6643 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6644 if (csize) *csize = asize; 6645 PetscFunctionReturn(PETSC_SUCCESS); 6646 } 6647 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6648 } else { 6649 array = *values; 6650 } 6651 PetscCall(VecGetArrayRead(v, &vArray)); 6652 /* Get values */ 6653 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6654 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6655 /* Cleanup points */ 6656 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6657 /* Cleanup array */ 6658 PetscCall(VecRestoreArrayRead(v, &vArray)); 6659 if (!*values) { 6660 if (csize) *csize = size; 6661 *values = array; 6662 } else { 6663 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6664 *csize = size; 6665 } 6666 PetscFunctionReturn(PETSC_SUCCESS); 6667 } 6668 6669 /*@C 6670 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6671 6672 Not collective 6673 6674 Input Parameters: 6675 + dm - The `DM` 6676 . section - The section describing the layout in `v`, or `NULL` to use the default section 6677 . v - The local vector 6678 . point - The point in the `DM` 6679 . csize - The number of values in the closure, or `NULL` 6680 - values - The array of values 6681 6682 Level: intermediate 6683 6684 Note: 6685 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6686 6687 Fortran Note: 6688 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6689 6690 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6691 @*/ 6692 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6693 { 6694 PetscInt size = 0; 6695 6696 PetscFunctionBegin; 6697 /* Should work without recalculating size */ 6698 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6699 *values = NULL; 6700 PetscFunctionReturn(PETSC_SUCCESS); 6701 } 6702 6703 static inline void add(PetscScalar *x, PetscScalar y) 6704 { 6705 *x += y; 6706 } 6707 static inline void insert(PetscScalar *x, PetscScalar y) 6708 { 6709 *x = y; 6710 } 6711 6712 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[]) 6713 { 6714 PetscInt cdof; /* The number of constraints on this point */ 6715 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6716 PetscScalar *a; 6717 PetscInt off, cind = 0, k; 6718 6719 PetscFunctionBegin; 6720 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6721 PetscCall(PetscSectionGetOffset(section, point, &off)); 6722 a = &array[off]; 6723 if (!cdof || setBC) { 6724 if (clperm) { 6725 if (perm) { 6726 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6727 } else { 6728 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6729 } 6730 } else { 6731 if (perm) { 6732 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6733 } else { 6734 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6735 } 6736 } 6737 } else { 6738 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6739 if (clperm) { 6740 if (perm) { 6741 for (k = 0; k < dof; ++k) { 6742 if ((cind < cdof) && (k == cdofs[cind])) { 6743 ++cind; 6744 continue; 6745 } 6746 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6747 } 6748 } else { 6749 for (k = 0; k < dof; ++k) { 6750 if ((cind < cdof) && (k == cdofs[cind])) { 6751 ++cind; 6752 continue; 6753 } 6754 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6755 } 6756 } 6757 } else { 6758 if (perm) { 6759 for (k = 0; k < dof; ++k) { 6760 if ((cind < cdof) && (k == cdofs[cind])) { 6761 ++cind; 6762 continue; 6763 } 6764 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6765 } 6766 } else { 6767 for (k = 0; k < dof; ++k) { 6768 if ((cind < cdof) && (k == cdofs[cind])) { 6769 ++cind; 6770 continue; 6771 } 6772 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6773 } 6774 } 6775 } 6776 } 6777 PetscFunctionReturn(PETSC_SUCCESS); 6778 } 6779 6780 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[]) 6781 { 6782 PetscInt cdof; /* The number of constraints on this point */ 6783 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6784 PetscScalar *a; 6785 PetscInt off, cind = 0, k; 6786 6787 PetscFunctionBegin; 6788 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6789 PetscCall(PetscSectionGetOffset(section, point, &off)); 6790 a = &array[off]; 6791 if (cdof) { 6792 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6793 if (clperm) { 6794 if (perm) { 6795 for (k = 0; k < dof; ++k) { 6796 if ((cind < cdof) && (k == cdofs[cind])) { 6797 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6798 cind++; 6799 } 6800 } 6801 } else { 6802 for (k = 0; k < dof; ++k) { 6803 if ((cind < cdof) && (k == cdofs[cind])) { 6804 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6805 cind++; 6806 } 6807 } 6808 } 6809 } else { 6810 if (perm) { 6811 for (k = 0; k < dof; ++k) { 6812 if ((cind < cdof) && (k == cdofs[cind])) { 6813 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6814 cind++; 6815 } 6816 } 6817 } else { 6818 for (k = 0; k < dof; ++k) { 6819 if ((cind < cdof) && (k == cdofs[cind])) { 6820 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6821 cind++; 6822 } 6823 } 6824 } 6825 } 6826 } 6827 PetscFunctionReturn(PETSC_SUCCESS); 6828 } 6829 6830 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[]) 6831 { 6832 PetscScalar *a; 6833 PetscInt fdof, foff, fcdof, foffset = *offset; 6834 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6835 PetscInt cind = 0, b; 6836 6837 PetscFunctionBegin; 6838 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6839 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6840 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6841 a = &array[foff]; 6842 if (!fcdof || setBC) { 6843 if (clperm) { 6844 if (perm) { 6845 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6846 } else { 6847 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6848 } 6849 } else { 6850 if (perm) { 6851 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6852 } else { 6853 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6854 } 6855 } 6856 } else { 6857 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6858 if (clperm) { 6859 if (perm) { 6860 for (b = 0; b < fdof; b++) { 6861 if ((cind < fcdof) && (b == fcdofs[cind])) { 6862 ++cind; 6863 continue; 6864 } 6865 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6866 } 6867 } else { 6868 for (b = 0; b < fdof; b++) { 6869 if ((cind < fcdof) && (b == fcdofs[cind])) { 6870 ++cind; 6871 continue; 6872 } 6873 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6874 } 6875 } 6876 } else { 6877 if (perm) { 6878 for (b = 0; b < fdof; b++) { 6879 if ((cind < fcdof) && (b == fcdofs[cind])) { 6880 ++cind; 6881 continue; 6882 } 6883 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6884 } 6885 } else { 6886 for (b = 0; b < fdof; b++) { 6887 if ((cind < fcdof) && (b == fcdofs[cind])) { 6888 ++cind; 6889 continue; 6890 } 6891 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6892 } 6893 } 6894 } 6895 } 6896 *offset += fdof; 6897 PetscFunctionReturn(PETSC_SUCCESS); 6898 } 6899 6900 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[]) 6901 { 6902 PetscScalar *a; 6903 PetscInt fdof, foff, fcdof, foffset = *offset; 6904 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6905 PetscInt Nc, cind = 0, ncind = 0, b; 6906 PetscBool ncSet, fcSet; 6907 6908 PetscFunctionBegin; 6909 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6910 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6911 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6912 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6913 a = &array[foff]; 6914 if (fcdof) { 6915 /* We just override fcdof and fcdofs with Ncc and comps */ 6916 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6917 if (clperm) { 6918 if (perm) { 6919 if (comps) { 6920 for (b = 0; b < fdof; b++) { 6921 ncSet = fcSet = PETSC_FALSE; 6922 if (b % Nc == comps[ncind]) { 6923 ncind = (ncind + 1) % Ncc; 6924 ncSet = PETSC_TRUE; 6925 } 6926 if ((cind < fcdof) && (b == fcdofs[cind])) { 6927 ++cind; 6928 fcSet = PETSC_TRUE; 6929 } 6930 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6931 } 6932 } else { 6933 for (b = 0; b < fdof; b++) { 6934 if ((cind < fcdof) && (b == fcdofs[cind])) { 6935 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6936 ++cind; 6937 } 6938 } 6939 } 6940 } else { 6941 if (comps) { 6942 for (b = 0; b < fdof; b++) { 6943 ncSet = fcSet = PETSC_FALSE; 6944 if (b % Nc == comps[ncind]) { 6945 ncind = (ncind + 1) % Ncc; 6946 ncSet = PETSC_TRUE; 6947 } 6948 if ((cind < fcdof) && (b == fcdofs[cind])) { 6949 ++cind; 6950 fcSet = PETSC_TRUE; 6951 } 6952 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6953 } 6954 } else { 6955 for (b = 0; b < fdof; b++) { 6956 if ((cind < fcdof) && (b == fcdofs[cind])) { 6957 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6958 ++cind; 6959 } 6960 } 6961 } 6962 } 6963 } else { 6964 if (perm) { 6965 if (comps) { 6966 for (b = 0; b < fdof; b++) { 6967 ncSet = fcSet = PETSC_FALSE; 6968 if (b % Nc == comps[ncind]) { 6969 ncind = (ncind + 1) % Ncc; 6970 ncSet = PETSC_TRUE; 6971 } 6972 if ((cind < fcdof) && (b == fcdofs[cind])) { 6973 ++cind; 6974 fcSet = PETSC_TRUE; 6975 } 6976 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6977 } 6978 } else { 6979 for (b = 0; b < fdof; b++) { 6980 if ((cind < fcdof) && (b == fcdofs[cind])) { 6981 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6982 ++cind; 6983 } 6984 } 6985 } 6986 } else { 6987 if (comps) { 6988 for (b = 0; b < fdof; b++) { 6989 ncSet = fcSet = PETSC_FALSE; 6990 if (b % Nc == comps[ncind]) { 6991 ncind = (ncind + 1) % Ncc; 6992 ncSet = PETSC_TRUE; 6993 } 6994 if ((cind < fcdof) && (b == fcdofs[cind])) { 6995 ++cind; 6996 fcSet = PETSC_TRUE; 6997 } 6998 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6999 } 7000 } else { 7001 for (b = 0; b < fdof; b++) { 7002 if ((cind < fcdof) && (b == fcdofs[cind])) { 7003 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7004 ++cind; 7005 } 7006 } 7007 } 7008 } 7009 } 7010 } 7011 *offset += fdof; 7012 PetscFunctionReturn(PETSC_SUCCESS); 7013 } 7014 7015 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7016 { 7017 PetscScalar *array; 7018 const PetscInt *cone, *coneO; 7019 PetscInt pStart, pEnd, p, numPoints, off, dof; 7020 7021 PetscFunctionBeginHot; 7022 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7023 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7024 PetscCall(DMPlexGetCone(dm, point, &cone)); 7025 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7026 PetscCall(VecGetArray(v, &array)); 7027 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7028 const PetscInt cp = !p ? point : cone[p - 1]; 7029 const PetscInt o = !p ? 0 : coneO[p - 1]; 7030 7031 if ((cp < pStart) || (cp >= pEnd)) { 7032 dof = 0; 7033 continue; 7034 } 7035 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7036 /* ADD_VALUES */ 7037 { 7038 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7039 PetscScalar *a; 7040 PetscInt cdof, coff, cind = 0, k; 7041 7042 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7043 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7044 a = &array[coff]; 7045 if (!cdof) { 7046 if (o >= 0) { 7047 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7048 } else { 7049 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7050 } 7051 } else { 7052 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7053 if (o >= 0) { 7054 for (k = 0; k < dof; ++k) { 7055 if ((cind < cdof) && (k == cdofs[cind])) { 7056 ++cind; 7057 continue; 7058 } 7059 a[k] += values[off + k]; 7060 } 7061 } else { 7062 for (k = 0; k < dof; ++k) { 7063 if ((cind < cdof) && (k == cdofs[cind])) { 7064 ++cind; 7065 continue; 7066 } 7067 a[k] += values[off + dof - k - 1]; 7068 } 7069 } 7070 } 7071 } 7072 } 7073 PetscCall(VecRestoreArray(v, &array)); 7074 PetscFunctionReturn(PETSC_SUCCESS); 7075 } 7076 7077 /*@C 7078 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7079 7080 Not collective 7081 7082 Input Parameters: 7083 + dm - The `DM` 7084 . section - The section describing the layout in `v`, or `NULL` to use the default section 7085 . v - The local vector 7086 . point - The point in the `DM` 7087 . values - The array of values 7088 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7089 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7090 7091 Level: intermediate 7092 7093 Note: 7094 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7095 7096 Fortran Note: 7097 `values` must be declared with 7098 .vb 7099 PetscScalar,dimension(:),pointer :: values 7100 .ve 7101 7102 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7103 @*/ 7104 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7105 { 7106 PetscSection clSection; 7107 IS clPoints; 7108 PetscScalar *array; 7109 PetscInt *points = NULL; 7110 const PetscInt *clp, *clperm = NULL; 7111 PetscInt depth, numFields, numPoints, p, clsize; 7112 7113 PetscFunctionBeginHot; 7114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7115 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7116 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7117 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7118 PetscCall(DMPlexGetDepth(dm, &depth)); 7119 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7120 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7121 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7122 PetscFunctionReturn(PETSC_SUCCESS); 7123 } 7124 /* Get points */ 7125 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7126 for (clsize = 0, p = 0; p < numPoints; p++) { 7127 PetscInt dof; 7128 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7129 clsize += dof; 7130 } 7131 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7132 /* Get array */ 7133 PetscCall(VecGetArray(v, &array)); 7134 /* Get values */ 7135 if (numFields > 0) { 7136 PetscInt offset = 0, f; 7137 for (f = 0; f < numFields; ++f) { 7138 const PetscInt **perms = NULL; 7139 const PetscScalar **flips = NULL; 7140 7141 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7142 switch (mode) { 7143 case INSERT_VALUES: 7144 for (p = 0; p < numPoints; p++) { 7145 const PetscInt point = points[2 * p]; 7146 const PetscInt *perm = perms ? perms[p] : NULL; 7147 const PetscScalar *flip = flips ? flips[p] : NULL; 7148 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7149 } 7150 break; 7151 case INSERT_ALL_VALUES: 7152 for (p = 0; p < numPoints; p++) { 7153 const PetscInt point = points[2 * p]; 7154 const PetscInt *perm = perms ? perms[p] : NULL; 7155 const PetscScalar *flip = flips ? flips[p] : NULL; 7156 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7157 } 7158 break; 7159 case INSERT_BC_VALUES: 7160 for (p = 0; p < numPoints; p++) { 7161 const PetscInt point = points[2 * p]; 7162 const PetscInt *perm = perms ? perms[p] : NULL; 7163 const PetscScalar *flip = flips ? flips[p] : NULL; 7164 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7165 } 7166 break; 7167 case ADD_VALUES: 7168 for (p = 0; p < numPoints; p++) { 7169 const PetscInt point = points[2 * p]; 7170 const PetscInt *perm = perms ? perms[p] : NULL; 7171 const PetscScalar *flip = flips ? flips[p] : NULL; 7172 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7173 } 7174 break; 7175 case ADD_ALL_VALUES: 7176 for (p = 0; p < numPoints; p++) { 7177 const PetscInt point = points[2 * p]; 7178 const PetscInt *perm = perms ? perms[p] : NULL; 7179 const PetscScalar *flip = flips ? flips[p] : NULL; 7180 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7181 } 7182 break; 7183 case ADD_BC_VALUES: 7184 for (p = 0; p < numPoints; p++) { 7185 const PetscInt point = points[2 * p]; 7186 const PetscInt *perm = perms ? perms[p] : NULL; 7187 const PetscScalar *flip = flips ? flips[p] : NULL; 7188 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7189 } 7190 break; 7191 default: 7192 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7193 } 7194 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7195 } 7196 } else { 7197 PetscInt dof, off; 7198 const PetscInt **perms = NULL; 7199 const PetscScalar **flips = NULL; 7200 7201 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7202 switch (mode) { 7203 case INSERT_VALUES: 7204 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7205 const PetscInt point = points[2 * p]; 7206 const PetscInt *perm = perms ? perms[p] : NULL; 7207 const PetscScalar *flip = flips ? flips[p] : NULL; 7208 PetscCall(PetscSectionGetDof(section, point, &dof)); 7209 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7210 } 7211 break; 7212 case INSERT_ALL_VALUES: 7213 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7214 const PetscInt point = points[2 * p]; 7215 const PetscInt *perm = perms ? perms[p] : NULL; 7216 const PetscScalar *flip = flips ? flips[p] : NULL; 7217 PetscCall(PetscSectionGetDof(section, point, &dof)); 7218 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7219 } 7220 break; 7221 case INSERT_BC_VALUES: 7222 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7223 const PetscInt point = points[2 * p]; 7224 const PetscInt *perm = perms ? perms[p] : NULL; 7225 const PetscScalar *flip = flips ? flips[p] : NULL; 7226 PetscCall(PetscSectionGetDof(section, point, &dof)); 7227 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7228 } 7229 break; 7230 case ADD_VALUES: 7231 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7232 const PetscInt point = points[2 * p]; 7233 const PetscInt *perm = perms ? perms[p] : NULL; 7234 const PetscScalar *flip = flips ? flips[p] : NULL; 7235 PetscCall(PetscSectionGetDof(section, point, &dof)); 7236 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7237 } 7238 break; 7239 case ADD_ALL_VALUES: 7240 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7241 const PetscInt point = points[2 * p]; 7242 const PetscInt *perm = perms ? perms[p] : NULL; 7243 const PetscScalar *flip = flips ? flips[p] : NULL; 7244 PetscCall(PetscSectionGetDof(section, point, &dof)); 7245 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7246 } 7247 break; 7248 case ADD_BC_VALUES: 7249 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7250 const PetscInt point = points[2 * p]; 7251 const PetscInt *perm = perms ? perms[p] : NULL; 7252 const PetscScalar *flip = flips ? flips[p] : NULL; 7253 PetscCall(PetscSectionGetDof(section, point, &dof)); 7254 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7255 } 7256 break; 7257 default: 7258 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7259 } 7260 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7261 } 7262 /* Cleanup points */ 7263 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7264 /* Cleanup array */ 7265 PetscCall(VecRestoreArray(v, &array)); 7266 PetscFunctionReturn(PETSC_SUCCESS); 7267 } 7268 7269 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7270 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7271 { 7272 PetscFunctionBegin; 7273 *contains = PETSC_TRUE; 7274 if (label) { 7275 PetscInt fdof; 7276 7277 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7278 if (!*contains) { 7279 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7280 *offset += fdof; 7281 PetscFunctionReturn(PETSC_SUCCESS); 7282 } 7283 } 7284 PetscFunctionReturn(PETSC_SUCCESS); 7285 } 7286 7287 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7288 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) 7289 { 7290 PetscSection clSection; 7291 IS clPoints; 7292 PetscScalar *array; 7293 PetscInt *points = NULL; 7294 const PetscInt *clp; 7295 PetscInt numFields, numPoints, p; 7296 PetscInt offset = 0, f; 7297 7298 PetscFunctionBeginHot; 7299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7300 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7301 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7302 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7303 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7304 /* Get points */ 7305 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7306 /* Get array */ 7307 PetscCall(VecGetArray(v, &array)); 7308 /* Get values */ 7309 for (f = 0; f < numFields; ++f) { 7310 const PetscInt **perms = NULL; 7311 const PetscScalar **flips = NULL; 7312 PetscBool contains; 7313 7314 if (!fieldActive[f]) { 7315 for (p = 0; p < numPoints * 2; p += 2) { 7316 PetscInt fdof; 7317 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7318 offset += fdof; 7319 } 7320 continue; 7321 } 7322 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7323 switch (mode) { 7324 case INSERT_VALUES: 7325 for (p = 0; p < numPoints; p++) { 7326 const PetscInt point = points[2 * p]; 7327 const PetscInt *perm = perms ? perms[p] : NULL; 7328 const PetscScalar *flip = flips ? flips[p] : NULL; 7329 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7330 if (!contains) continue; 7331 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7332 } 7333 break; 7334 case INSERT_ALL_VALUES: 7335 for (p = 0; p < numPoints; p++) { 7336 const PetscInt point = points[2 * p]; 7337 const PetscInt *perm = perms ? perms[p] : NULL; 7338 const PetscScalar *flip = flips ? flips[p] : NULL; 7339 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7340 if (!contains) continue; 7341 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7342 } 7343 break; 7344 case INSERT_BC_VALUES: 7345 for (p = 0; p < numPoints; p++) { 7346 const PetscInt point = points[2 * p]; 7347 const PetscInt *perm = perms ? perms[p] : NULL; 7348 const PetscScalar *flip = flips ? flips[p] : NULL; 7349 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7350 if (!contains) continue; 7351 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7352 } 7353 break; 7354 case ADD_VALUES: 7355 for (p = 0; p < numPoints; p++) { 7356 const PetscInt point = points[2 * p]; 7357 const PetscInt *perm = perms ? perms[p] : NULL; 7358 const PetscScalar *flip = flips ? flips[p] : NULL; 7359 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7360 if (!contains) continue; 7361 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7362 } 7363 break; 7364 case ADD_ALL_VALUES: 7365 for (p = 0; p < numPoints; p++) { 7366 const PetscInt point = points[2 * p]; 7367 const PetscInt *perm = perms ? perms[p] : NULL; 7368 const PetscScalar *flip = flips ? flips[p] : NULL; 7369 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7370 if (!contains) continue; 7371 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7372 } 7373 break; 7374 default: 7375 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7376 } 7377 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7378 } 7379 /* Cleanup points */ 7380 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7381 /* Cleanup array */ 7382 PetscCall(VecRestoreArray(v, &array)); 7383 PetscFunctionReturn(PETSC_SUCCESS); 7384 } 7385 7386 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7387 { 7388 PetscMPIInt rank; 7389 PetscInt i, j; 7390 7391 PetscFunctionBegin; 7392 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7393 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7394 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7395 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7396 numCIndices = numCIndices ? numCIndices : numRIndices; 7397 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7398 for (i = 0; i < numRIndices; i++) { 7399 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7400 for (j = 0; j < numCIndices; j++) { 7401 #if defined(PETSC_USE_COMPLEX) 7402 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7403 #else 7404 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7405 #endif 7406 } 7407 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7408 } 7409 PetscFunctionReturn(PETSC_SUCCESS); 7410 } 7411 7412 /* 7413 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7414 7415 Input Parameters: 7416 + section - The section for this data layout 7417 . islocal - Is the section (and thus indices being requested) local or global? 7418 . point - The point contributing dofs with these indices 7419 . off - The global offset of this point 7420 . loff - The local offset of each field 7421 . setBC - The flag determining whether to include indices of boundary values 7422 . perm - A permutation of the dofs on this point, or NULL 7423 - indperm - A permutation of the entire indices array, or NULL 7424 7425 Output Parameter: 7426 . indices - Indices for dofs on this point 7427 7428 Level: developer 7429 7430 Note: The indices could be local or global, depending on the value of 'off'. 7431 */ 7432 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7433 { 7434 PetscInt dof; /* The number of unknowns on this point */ 7435 PetscInt cdof; /* The number of constraints on this point */ 7436 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7437 PetscInt cind = 0, k; 7438 7439 PetscFunctionBegin; 7440 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7441 PetscCall(PetscSectionGetDof(section, point, &dof)); 7442 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7443 if (!cdof || setBC) { 7444 for (k = 0; k < dof; ++k) { 7445 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7446 const PetscInt ind = indperm ? indperm[preind] : preind; 7447 7448 indices[ind] = off + k; 7449 } 7450 } else { 7451 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7452 for (k = 0; k < dof; ++k) { 7453 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7454 const PetscInt ind = indperm ? indperm[preind] : preind; 7455 7456 if ((cind < cdof) && (k == cdofs[cind])) { 7457 /* Insert check for returning constrained indices */ 7458 indices[ind] = -(off + k + 1); 7459 ++cind; 7460 } else { 7461 indices[ind] = off + k - (islocal ? 0 : cind); 7462 } 7463 } 7464 } 7465 *loff += dof; 7466 PetscFunctionReturn(PETSC_SUCCESS); 7467 } 7468 7469 /* 7470 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7471 7472 Input Parameters: 7473 + section - a section (global or local) 7474 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7475 . point - point within section 7476 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7477 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7478 . setBC - identify constrained (boundary condition) points via involution. 7479 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7480 . permsoff - offset 7481 - indperm - index permutation 7482 7483 Output Parameter: 7484 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7485 . indices - array to hold indices (as defined by section) of each dof associated with point 7486 7487 Notes: 7488 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7489 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7490 in the local vector. 7491 7492 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7493 significant). It is invalid to call with a global section and setBC=true. 7494 7495 Developer Note: 7496 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7497 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7498 offset could be obtained from the section instead of passing it explicitly as we do now. 7499 7500 Example: 7501 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7502 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7503 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7504 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. 7505 7506 Level: developer 7507 */ 7508 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[]) 7509 { 7510 PetscInt numFields, foff, f; 7511 7512 PetscFunctionBegin; 7513 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7514 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7515 for (f = 0, foff = 0; f < numFields; ++f) { 7516 PetscInt fdof, cfdof; 7517 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7518 PetscInt cind = 0, b; 7519 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7520 7521 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7522 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7523 if (!cfdof || setBC) { 7524 for (b = 0; b < fdof; ++b) { 7525 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7526 const PetscInt ind = indperm ? indperm[preind] : preind; 7527 7528 indices[ind] = off + foff + b; 7529 } 7530 } else { 7531 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7532 for (b = 0; b < fdof; ++b) { 7533 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7534 const PetscInt ind = indperm ? indperm[preind] : preind; 7535 7536 if ((cind < cfdof) && (b == fcdofs[cind])) { 7537 indices[ind] = -(off + foff + b + 1); 7538 ++cind; 7539 } else { 7540 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7541 } 7542 } 7543 } 7544 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7545 foffs[f] += fdof; 7546 } 7547 PetscFunctionReturn(PETSC_SUCCESS); 7548 } 7549 7550 /* 7551 This version believes the globalSection offsets for each field, rather than just the point offset 7552 7553 . foffs - The offset into 'indices' for each field, since it is segregated by field 7554 7555 Notes: 7556 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7557 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7558 */ 7559 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7560 { 7561 PetscInt numFields, foff, f; 7562 7563 PetscFunctionBegin; 7564 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7565 for (f = 0; f < numFields; ++f) { 7566 PetscInt fdof, cfdof; 7567 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7568 PetscInt cind = 0, b; 7569 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7570 7571 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7572 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7573 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7574 if (!cfdof) { 7575 for (b = 0; b < fdof; ++b) { 7576 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7577 const PetscInt ind = indperm ? indperm[preind] : preind; 7578 7579 indices[ind] = foff + b; 7580 } 7581 } else { 7582 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7583 for (b = 0; b < fdof; ++b) { 7584 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7585 const PetscInt ind = indperm ? indperm[preind] : preind; 7586 7587 if ((cind < cfdof) && (b == fcdofs[cind])) { 7588 indices[ind] = -(foff + b + 1); 7589 ++cind; 7590 } else { 7591 indices[ind] = foff + b - cind; 7592 } 7593 } 7594 } 7595 foffs[f] += fdof; 7596 } 7597 PetscFunctionReturn(PETSC_SUCCESS); 7598 } 7599 7600 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7601 { 7602 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7603 7604 PetscFunctionBegin; 7605 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7606 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7607 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7608 for (PetscInt p = 0; p < nPoints; p++) { 7609 PetscInt b = pnts[2 * p]; 7610 PetscInt bSecDof = 0, bOff; 7611 PetscInt cSecDof = 0; 7612 PetscSection indices_section; 7613 7614 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7615 if (!bSecDof) continue; 7616 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7617 indices_section = cSecDof > 0 ? cSec : section; 7618 if (numFields) { 7619 PetscInt fStart[32], fEnd[32]; 7620 7621 fStart[0] = 0; 7622 fEnd[0] = 0; 7623 for (PetscInt f = 0; f < numFields; f++) { 7624 PetscInt fDof = 0; 7625 7626 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7627 fStart[f + 1] = fStart[f] + fDof; 7628 fEnd[f + 1] = fStart[f + 1]; 7629 } 7630 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7631 // only apply permutations on one side 7632 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7633 for (PetscInt f = 0; f < numFields; f++) { 7634 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7635 } 7636 } else { 7637 PetscInt bEnd = 0; 7638 7639 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7640 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7641 7642 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7643 } 7644 } 7645 PetscFunctionReturn(PETSC_SUCCESS); 7646 } 7647 7648 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[]) 7649 { 7650 Mat cMat; 7651 PetscSection aSec, cSec; 7652 IS aIS; 7653 PetscInt aStart = -1, aEnd = -1; 7654 PetscInt sStart = -1, sEnd = -1; 7655 PetscInt cStart = -1, cEnd = -1; 7656 const PetscInt *anchors; 7657 PetscInt numFields, p; 7658 PetscInt newNumPoints = 0, newNumIndices = 0; 7659 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7660 PetscInt oldOffsets[32]; 7661 PetscInt newOffsets[32]; 7662 PetscInt oldOffsetsCopy[32]; 7663 PetscInt newOffsetsCopy[32]; 7664 PetscScalar *modMat = NULL; 7665 PetscBool anyConstrained = PETSC_FALSE; 7666 7667 PetscFunctionBegin; 7668 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7669 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7670 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7671 7672 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7673 /* if there are point-to-point constraints */ 7674 if (aSec) { 7675 PetscCall(PetscArrayzero(newOffsets, 32)); 7676 PetscCall(PetscArrayzero(oldOffsets, 32)); 7677 PetscCall(ISGetIndices(aIS, &anchors)); 7678 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7679 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7680 /* figure out how many points are going to be in the new element matrix 7681 * (we allow double counting, because it's all just going to be summed 7682 * into the global matrix anyway) */ 7683 for (p = 0; p < 2 * numPoints; p += 2) { 7684 PetscInt b = points[p]; 7685 PetscInt bDof = 0, bSecDof = 0; 7686 7687 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7688 if (!bSecDof) continue; 7689 7690 for (PetscInt f = 0; f < numFields; f++) { 7691 PetscInt fDof = 0; 7692 7693 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7694 oldOffsets[f + 1] += fDof; 7695 } 7696 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7697 if (bDof) { 7698 /* this point is constrained */ 7699 /* it is going to be replaced by its anchors */ 7700 PetscInt bOff, q; 7701 7702 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7703 for (q = 0; q < bDof; q++) { 7704 PetscInt a = anchors[bOff + q]; 7705 PetscInt aDof = 0; 7706 7707 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7708 if (aDof) { 7709 anyConstrained = PETSC_TRUE; 7710 newNumPoints += 1; 7711 } 7712 newNumIndices += aDof; 7713 for (PetscInt f = 0; f < numFields; ++f) { 7714 PetscInt fDof = 0; 7715 7716 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7717 newOffsets[f + 1] += fDof; 7718 } 7719 } 7720 } else { 7721 /* this point is not constrained */ 7722 newNumPoints++; 7723 newNumIndices += bSecDof; 7724 for (PetscInt f = 0; f < numFields; ++f) { 7725 PetscInt fDof; 7726 7727 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7728 newOffsets[f + 1] += fDof; 7729 } 7730 } 7731 } 7732 } 7733 if (!anyConstrained) { 7734 if (outNumPoints) *outNumPoints = 0; 7735 if (outNumIndices) *outNumIndices = 0; 7736 if (outPoints) *outPoints = NULL; 7737 if (outMat) *outMat = NULL; 7738 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7739 PetscFunctionReturn(PETSC_SUCCESS); 7740 } 7741 7742 if (outNumPoints) *outNumPoints = newNumPoints; 7743 if (outNumIndices) *outNumIndices = newNumIndices; 7744 7745 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7746 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7747 7748 if (!outPoints && !outMat) { 7749 if (offsets) { 7750 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7751 } 7752 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7753 PetscFunctionReturn(PETSC_SUCCESS); 7754 } 7755 7756 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7757 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7758 7759 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7760 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7761 7762 /* output arrays */ 7763 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7764 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7765 7766 // get the new Points 7767 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7768 PetscInt b = points[2 * p]; 7769 PetscInt bDof = 0, bSecDof = 0, bOff; 7770 7771 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7772 if (!bSecDof) continue; 7773 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7774 if (bDof) { 7775 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7776 for (PetscInt q = 0; q < bDof; q++) { 7777 PetscInt a = anchors[bOff + q], aDof = 0; 7778 7779 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7780 if (aDof) { 7781 newPoints[2 * newP] = a; 7782 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7783 newP++; 7784 } 7785 } 7786 } else { 7787 newPoints[2 * newP] = b; 7788 newPoints[2 * newP + 1] = points[2 * p + 1]; 7789 newP++; 7790 } 7791 } 7792 7793 if (outMat) { 7794 PetscScalar *tmpMat; 7795 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7796 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7797 7798 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7799 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7800 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7801 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7802 7803 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7804 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7805 7806 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7807 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7808 7809 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7810 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7811 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7812 // for each field, insert the anchor modification into modMat 7813 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7814 PetscInt fStart = oldOffsets[f]; 7815 PetscInt fNewStart = newOffsets[f]; 7816 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7817 PetscInt b = points[2 * p]; 7818 PetscInt bDof = 0, bSecDof = 0, bOff; 7819 7820 if (b >= sStart && b < sEnd) { 7821 if (numFields) { 7822 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7823 } else { 7824 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7825 } 7826 } 7827 if (!bSecDof) continue; 7828 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7829 if (bDof) { 7830 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7831 for (PetscInt q = 0; q < bDof; q++, newP++) { 7832 PetscInt a = anchors[bOff + q], aDof = 0; 7833 7834 if (a >= sStart && a < sEnd) { 7835 if (numFields) { 7836 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7837 } else { 7838 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7839 } 7840 } 7841 if (aDof) { 7842 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7843 for (PetscInt d = 0; d < bSecDof; d++) { 7844 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7845 } 7846 } 7847 oNew += aDof; 7848 } 7849 } else { 7850 // Insert the identity matrix in this block 7851 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7852 oNew += bSecDof; 7853 newP++; 7854 } 7855 o += bSecDof; 7856 } 7857 } 7858 7859 *outMat = modMat; 7860 7861 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7862 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7863 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7864 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7865 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7866 } 7867 PetscCall(ISRestoreIndices(aIS, &anchors)); 7868 7869 /* output */ 7870 if (outPoints) { 7871 *outPoints = newPoints; 7872 } else { 7873 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7874 } 7875 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7876 PetscFunctionReturn(PETSC_SUCCESS); 7877 } 7878 7879 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) 7880 { 7881 PetscScalar *modMat = NULL; 7882 PetscInt newNumIndices = -1; 7883 7884 PetscFunctionBegin; 7885 /* 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. 7886 modMat is that matrix C */ 7887 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7888 if (outNumIndices) *outNumIndices = newNumIndices; 7889 if (modMat) { 7890 const PetscScalar *newValues = values; 7891 7892 if (multiplyRight) { 7893 PetscScalar *newNewValues = NULL; 7894 PetscBLASInt M, N, K; 7895 PetscScalar a = 1.0, b = 0.0; 7896 7897 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); 7898 7899 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7900 PetscCall(PetscBLASIntCast(numRows, &N)); 7901 PetscCall(PetscBLASIntCast(numIndices, &K)); 7902 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7903 // row-major to column-major conversion, right multiplication becomes left multiplication 7904 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7905 numCols = newNumIndices; 7906 newValues = newNewValues; 7907 } 7908 7909 if (multiplyLeft) { 7910 PetscScalar *newNewValues = NULL; 7911 PetscBLASInt M, N, K; 7912 PetscScalar a = 1.0, b = 0.0; 7913 7914 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); 7915 7916 PetscCall(PetscBLASIntCast(numCols, &M)); 7917 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7918 PetscCall(PetscBLASIntCast(numIndices, &K)); 7919 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7920 // row-major to column-major conversion, left multiplication becomes right multiplication 7921 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7922 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7923 newValues = newNewValues; 7924 } 7925 *outValues = (PetscScalar *)newValues; 7926 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7927 } 7928 PetscFunctionReturn(PETSC_SUCCESS); 7929 } 7930 7931 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) 7932 { 7933 PetscFunctionBegin; 7934 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7935 PetscFunctionReturn(PETSC_SUCCESS); 7936 } 7937 7938 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7939 { 7940 /* Closure ordering */ 7941 PetscSection clSection; 7942 IS clPoints; 7943 const PetscInt *clp; 7944 PetscInt *points; 7945 PetscInt Ncl, Ni = 0; 7946 7947 PetscFunctionBeginHot; 7948 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7949 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7950 PetscInt dof; 7951 7952 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7953 Ni += dof; 7954 } 7955 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7956 *closureSize = Ni; 7957 PetscFunctionReturn(PETSC_SUCCESS); 7958 } 7959 7960 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) 7961 { 7962 /* Closure ordering */ 7963 PetscSection clSection; 7964 IS clPoints; 7965 const PetscInt *clp; 7966 PetscInt *points; 7967 const PetscInt *clperm = NULL; 7968 /* Dof permutation and sign flips */ 7969 const PetscInt **perms[32] = {NULL}; 7970 const PetscScalar **flips[32] = {NULL}; 7971 PetscScalar *valCopy = NULL; 7972 /* Hanging node constraints */ 7973 PetscInt *pointsC = NULL; 7974 PetscScalar *valuesC = NULL; 7975 PetscInt NclC, NiC; 7976 7977 PetscInt *idx; 7978 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7979 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7980 PetscInt idxStart, idxEnd; 7981 PetscInt nRows, nCols; 7982 7983 PetscFunctionBeginHot; 7984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7985 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7986 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7987 PetscAssertPointer(numRows, 6); 7988 PetscAssertPointer(numCols, 7); 7989 if (indices) PetscAssertPointer(indices, 8); 7990 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7991 if (values) PetscAssertPointer(values, 10); 7992 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7993 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7994 PetscCall(PetscArrayzero(offsets, 32)); 7995 /* 1) Get points in closure */ 7996 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7997 if (useClPerm) { 7998 PetscInt depth, clsize; 7999 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8000 for (clsize = 0, p = 0; p < Ncl; p++) { 8001 PetscInt dof; 8002 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8003 clsize += dof; 8004 } 8005 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8006 } 8007 /* 2) Get number of indices on these points and field offsets from section */ 8008 for (p = 0; p < Ncl * 2; p += 2) { 8009 PetscInt dof, fdof; 8010 8011 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8012 for (f = 0; f < Nf; ++f) { 8013 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8014 offsets[f + 1] += fdof; 8015 } 8016 Ni += dof; 8017 } 8018 if (*numRows == -1) *numRows = Ni; 8019 if (*numCols == -1) *numCols = Ni; 8020 nRows = *numRows; 8021 nCols = *numCols; 8022 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8023 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8024 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8025 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8026 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8027 for (f = 0; f < PetscMax(1, Nf); ++f) { 8028 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8029 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8030 /* may need to apply sign changes to the element matrix */ 8031 if (values && flips[f]) { 8032 PetscInt foffset = offsets[f]; 8033 8034 for (p = 0; p < Ncl; ++p) { 8035 PetscInt pnt = points[2 * p], fdof; 8036 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8037 8038 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8039 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8040 if (flip) { 8041 PetscInt i, j, k; 8042 8043 if (!valCopy) { 8044 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8045 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8046 *values = valCopy; 8047 } 8048 for (i = 0; i < fdof; ++i) { 8049 PetscScalar fval = flip[i]; 8050 8051 if (multiplyRight) { 8052 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8053 } 8054 if (multiplyLeft) { 8055 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8056 } 8057 } 8058 } 8059 foffset += fdof; 8060 } 8061 } 8062 } 8063 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8064 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8065 if (NclC) { 8066 if (multiplyRight) *numCols = NiC; 8067 if (multiplyLeft) *numRows = NiC; 8068 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8069 for (f = 0; f < PetscMax(1, Nf); ++f) { 8070 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8071 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8072 } 8073 for (f = 0; f < PetscMax(1, Nf); ++f) { 8074 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8075 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8076 } 8077 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8078 Ncl = NclC; 8079 Ni = NiC; 8080 points = pointsC; 8081 if (values) *values = valuesC; 8082 } 8083 /* 5) Calculate indices */ 8084 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8085 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8086 if (Nf) { 8087 PetscInt idxOff; 8088 PetscBool useFieldOffsets; 8089 8090 if (outOffsets) { 8091 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8092 } 8093 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8094 if (useFieldOffsets) { 8095 for (p = 0; p < Ncl; ++p) { 8096 const PetscInt pnt = points[p * 2]; 8097 8098 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8099 } 8100 } else { 8101 for (p = 0; p < Ncl; ++p) { 8102 const PetscInt pnt = points[p * 2]; 8103 8104 if (pnt < idxStart || pnt >= idxEnd) continue; 8105 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8106 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8107 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8108 * global section. */ 8109 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8110 } 8111 } 8112 } else { 8113 PetscInt off = 0, idxOff; 8114 8115 for (p = 0; p < Ncl; ++p) { 8116 const PetscInt pnt = points[p * 2]; 8117 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8118 8119 if (pnt < idxStart || pnt >= idxEnd) continue; 8120 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8121 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8122 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8123 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8124 } 8125 } 8126 /* 6) Cleanup */ 8127 for (f = 0; f < PetscMax(1, Nf); ++f) { 8128 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8129 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8130 } 8131 if (NclC) { 8132 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8133 } else { 8134 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8135 } 8136 8137 if (indices) *indices = idx; 8138 PetscFunctionReturn(PETSC_SUCCESS); 8139 } 8140 8141 /*@C 8142 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8143 8144 Not collective 8145 8146 Input Parameters: 8147 + dm - The `DM` 8148 . section - The `PetscSection` describing the points (a local section) 8149 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8150 . point - The point defining the closure 8151 - useClPerm - Use the closure point permutation if available 8152 8153 Output Parameters: 8154 + numIndices - The number of dof indices in the closure of point with the input sections 8155 . indices - The dof indices 8156 . outOffsets - Array to write the field offsets into, or `NULL` 8157 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8158 8159 Level: advanced 8160 8161 Notes: 8162 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8163 8164 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8165 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8166 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8167 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8168 indices (with the above semantics) are implied. 8169 8170 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8171 `PetscSection`, `DMGetGlobalSection()` 8172 @*/ 8173 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8174 { 8175 PetscInt numRows = -1, numCols = -1; 8176 8177 PetscFunctionBeginHot; 8178 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8179 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8180 *numIndices = numRows; 8181 PetscFunctionReturn(PETSC_SUCCESS); 8182 } 8183 8184 /*@C 8185 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8186 8187 Not collective 8188 8189 Input Parameters: 8190 + dm - The `DM` 8191 . section - The `PetscSection` describing the points (a local section) 8192 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8193 . point - The point defining the closure 8194 - useClPerm - Use the closure point permutation if available 8195 8196 Output Parameters: 8197 + numIndices - The number of dof indices in the closure of point with the input sections 8198 . indices - The dof indices 8199 . outOffsets - Array to write the field offsets into, or `NULL` 8200 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8201 8202 Level: advanced 8203 8204 Notes: 8205 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8206 8207 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8208 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8209 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8210 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8211 indices (with the above semantics) are implied. 8212 8213 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8214 @*/ 8215 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8216 { 8217 PetscFunctionBegin; 8218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8219 PetscAssertPointer(indices, 7); 8220 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8221 PetscFunctionReturn(PETSC_SUCCESS); 8222 } 8223 8224 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8225 { 8226 DM_Plex *mesh = (DM_Plex *)dm->data; 8227 PetscInt *indices; 8228 PetscInt numIndices; 8229 const PetscScalar *valuesOrig = values; 8230 PetscErrorCode ierr; 8231 8232 PetscFunctionBegin; 8233 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8234 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8235 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8236 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8237 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8238 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8239 8240 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8241 8242 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8243 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8244 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8245 if (ierr) { 8246 PetscMPIInt rank; 8247 8248 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8249 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8250 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8251 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8252 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8253 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8254 } 8255 if (mesh->printFEM > 1) { 8256 PetscInt i; 8257 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8258 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8259 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8260 } 8261 8262 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8263 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8264 PetscFunctionReturn(PETSC_SUCCESS); 8265 } 8266 8267 /*@C 8268 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8269 8270 Not collective 8271 8272 Input Parameters: 8273 + dm - The `DM` 8274 . section - The section describing the layout in `v`, or `NULL` to use the default section 8275 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8276 . A - The matrix 8277 . point - The point in the `DM` 8278 . values - The array of values 8279 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8280 8281 Level: intermediate 8282 8283 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8284 @*/ 8285 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8286 { 8287 PetscFunctionBegin; 8288 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8289 PetscFunctionReturn(PETSC_SUCCESS); 8290 } 8291 8292 /*@C 8293 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8294 8295 Not collective 8296 8297 Input Parameters: 8298 + dmRow - The `DM` for the row fields 8299 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8300 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8301 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8302 . dmCol - The `DM` for the column fields 8303 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8304 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8305 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8306 . A - The matrix 8307 . point - The point in the `DM` 8308 . values - The array of values 8309 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8310 8311 Level: intermediate 8312 8313 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8314 @*/ 8315 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) 8316 { 8317 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8318 PetscInt *indicesRow, *indicesCol; 8319 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8320 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8321 8322 PetscErrorCode ierr; 8323 8324 PetscFunctionBegin; 8325 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8326 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8327 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8328 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8329 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8330 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8331 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8332 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8333 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8334 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8335 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8336 8337 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8338 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8339 valuesV1 = valuesV0; 8340 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8341 valuesV2 = valuesV1; 8342 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8343 8344 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8345 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8346 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8347 if (ierr) { 8348 PetscMPIInt rank; 8349 8350 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8351 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8352 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8353 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8354 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8355 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8356 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8357 } 8358 8359 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8360 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8361 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8362 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8363 PetscFunctionReturn(PETSC_SUCCESS); 8364 } 8365 8366 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8367 { 8368 DM_Plex *mesh = (DM_Plex *)dmf->data; 8369 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8370 PetscInt *cpoints = NULL; 8371 PetscInt *findices, *cindices; 8372 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8373 PetscInt foffsets[32], coffsets[32]; 8374 DMPolytopeType ct; 8375 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8376 PetscErrorCode ierr; 8377 8378 PetscFunctionBegin; 8379 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8380 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8381 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8382 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8383 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8384 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8385 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8386 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8387 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8388 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8389 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8390 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8391 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8392 PetscCall(PetscArrayzero(foffsets, 32)); 8393 PetscCall(PetscArrayzero(coffsets, 32)); 8394 /* Column indices */ 8395 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8396 maxFPoints = numCPoints; 8397 /* Compress out points not in the section */ 8398 /* TODO: Squeeze out points with 0 dof as well */ 8399 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8400 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8401 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8402 cpoints[q * 2] = cpoints[p]; 8403 cpoints[q * 2 + 1] = cpoints[p + 1]; 8404 ++q; 8405 } 8406 } 8407 numCPoints = q; 8408 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8409 PetscInt fdof; 8410 8411 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8412 if (!dof) continue; 8413 for (f = 0; f < numFields; ++f) { 8414 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8415 coffsets[f + 1] += fdof; 8416 } 8417 numCIndices += dof; 8418 } 8419 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8420 /* Row indices */ 8421 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8422 { 8423 DMPlexTransform tr; 8424 DMPolytopeType *rct; 8425 PetscInt *rsize, *rcone, *rornt, Nt; 8426 8427 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8428 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8429 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8430 numSubcells = rsize[Nt - 1]; 8431 PetscCall(DMPlexTransformDestroy(&tr)); 8432 } 8433 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8434 for (r = 0, q = 0; r < numSubcells; ++r) { 8435 /* TODO Map from coarse to fine cells */ 8436 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8437 /* Compress out points not in the section */ 8438 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8439 for (p = 0; p < numFPoints * 2; p += 2) { 8440 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8441 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8442 if (!dof) continue; 8443 for (s = 0; s < q; ++s) 8444 if (fpoints[p] == ftotpoints[s * 2]) break; 8445 if (s < q) continue; 8446 ftotpoints[q * 2] = fpoints[p]; 8447 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8448 ++q; 8449 } 8450 } 8451 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8452 } 8453 numFPoints = q; 8454 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8455 PetscInt fdof; 8456 8457 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8458 if (!dof) continue; 8459 for (f = 0; f < numFields; ++f) { 8460 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8461 foffsets[f + 1] += fdof; 8462 } 8463 numFIndices += dof; 8464 } 8465 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8466 8467 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8468 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8469 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8470 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8471 if (numFields) { 8472 const PetscInt **permsF[32] = {NULL}; 8473 const PetscInt **permsC[32] = {NULL}; 8474 8475 for (f = 0; f < numFields; f++) { 8476 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8477 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8478 } 8479 for (p = 0; p < numFPoints; p++) { 8480 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8481 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8482 } 8483 for (p = 0; p < numCPoints; p++) { 8484 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8485 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8486 } 8487 for (f = 0; f < numFields; f++) { 8488 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8489 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8490 } 8491 } else { 8492 const PetscInt **permsF = NULL; 8493 const PetscInt **permsC = NULL; 8494 8495 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8496 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8497 for (p = 0, off = 0; p < numFPoints; p++) { 8498 const PetscInt *perm = permsF ? permsF[p] : NULL; 8499 8500 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8501 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8502 } 8503 for (p = 0, off = 0; p < numCPoints; p++) { 8504 const PetscInt *perm = permsC ? permsC[p] : NULL; 8505 8506 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8507 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8508 } 8509 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8510 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8511 } 8512 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8513 /* TODO: flips */ 8514 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8515 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8516 if (ierr) { 8517 PetscMPIInt rank; 8518 8519 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8520 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8521 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8522 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8523 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8524 } 8525 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8526 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8527 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8528 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8529 PetscFunctionReturn(PETSC_SUCCESS); 8530 } 8531 8532 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8533 { 8534 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8535 PetscInt *cpoints = NULL; 8536 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8537 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8538 DMPolytopeType ct; 8539 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8540 8541 PetscFunctionBegin; 8542 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8543 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8544 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8545 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8546 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8547 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8548 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8549 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8550 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8551 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8552 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8553 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8554 /* Column indices */ 8555 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8556 maxFPoints = numCPoints; 8557 /* Compress out points not in the section */ 8558 /* TODO: Squeeze out points with 0 dof as well */ 8559 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8560 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8561 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8562 cpoints[q * 2] = cpoints[p]; 8563 cpoints[q * 2 + 1] = cpoints[p + 1]; 8564 ++q; 8565 } 8566 } 8567 numCPoints = q; 8568 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8569 PetscInt fdof; 8570 8571 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8572 if (!dof) continue; 8573 for (f = 0; f < numFields; ++f) { 8574 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8575 coffsets[f + 1] += fdof; 8576 } 8577 numCIndices += dof; 8578 } 8579 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8580 /* Row indices */ 8581 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8582 { 8583 DMPlexTransform tr; 8584 DMPolytopeType *rct; 8585 PetscInt *rsize, *rcone, *rornt, Nt; 8586 8587 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8588 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8589 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8590 numSubcells = rsize[Nt - 1]; 8591 PetscCall(DMPlexTransformDestroy(&tr)); 8592 } 8593 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8594 for (r = 0, q = 0; r < numSubcells; ++r) { 8595 /* TODO Map from coarse to fine cells */ 8596 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8597 /* Compress out points not in the section */ 8598 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8599 for (p = 0; p < numFPoints * 2; p += 2) { 8600 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8601 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8602 if (!dof) continue; 8603 for (s = 0; s < q; ++s) 8604 if (fpoints[p] == ftotpoints[s * 2]) break; 8605 if (s < q) continue; 8606 ftotpoints[q * 2] = fpoints[p]; 8607 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8608 ++q; 8609 } 8610 } 8611 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8612 } 8613 numFPoints = q; 8614 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8615 PetscInt fdof; 8616 8617 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8618 if (!dof) continue; 8619 for (f = 0; f < numFields; ++f) { 8620 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8621 foffsets[f + 1] += fdof; 8622 } 8623 numFIndices += dof; 8624 } 8625 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8626 8627 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8628 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8629 if (numFields) { 8630 const PetscInt **permsF[32] = {NULL}; 8631 const PetscInt **permsC[32] = {NULL}; 8632 8633 for (f = 0; f < numFields; f++) { 8634 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8635 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8636 } 8637 for (p = 0; p < numFPoints; p++) { 8638 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8639 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8640 } 8641 for (p = 0; p < numCPoints; p++) { 8642 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8643 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8644 } 8645 for (f = 0; f < numFields; f++) { 8646 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8647 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8648 } 8649 } else { 8650 const PetscInt **permsF = NULL; 8651 const PetscInt **permsC = NULL; 8652 8653 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8654 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8655 for (p = 0, off = 0; p < numFPoints; p++) { 8656 const PetscInt *perm = permsF ? permsF[p] : NULL; 8657 8658 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8659 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8660 } 8661 for (p = 0, off = 0; p < numCPoints; p++) { 8662 const PetscInt *perm = permsC ? permsC[p] : NULL; 8663 8664 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8665 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8666 } 8667 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8668 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8669 } 8670 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8671 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8672 PetscFunctionReturn(PETSC_SUCCESS); 8673 } 8674 8675 /*@ 8676 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8677 8678 Input Parameter: 8679 . dm - The `DMPLEX` object 8680 8681 Output Parameter: 8682 . cellHeight - The height of a cell 8683 8684 Level: developer 8685 8686 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8687 @*/ 8688 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8689 { 8690 DM_Plex *mesh = (DM_Plex *)dm->data; 8691 8692 PetscFunctionBegin; 8693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8694 PetscAssertPointer(cellHeight, 2); 8695 *cellHeight = mesh->vtkCellHeight; 8696 PetscFunctionReturn(PETSC_SUCCESS); 8697 } 8698 8699 /*@ 8700 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8701 8702 Input Parameters: 8703 + dm - The `DMPLEX` object 8704 - cellHeight - The height of a cell 8705 8706 Level: developer 8707 8708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8709 @*/ 8710 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8711 { 8712 DM_Plex *mesh = (DM_Plex *)dm->data; 8713 8714 PetscFunctionBegin; 8715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8716 mesh->vtkCellHeight = cellHeight; 8717 PetscFunctionReturn(PETSC_SUCCESS); 8718 } 8719 8720 /*@ 8721 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8722 8723 Input Parameters: 8724 + dm - The `DMPLEX` object 8725 - ct - The `DMPolytopeType` of the cell 8726 8727 Output Parameters: 8728 + start - The first cell of this type, or `NULL` 8729 - end - The upper bound on this celltype, or `NULL` 8730 8731 Level: advanced 8732 8733 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8734 @*/ 8735 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8736 { 8737 DM_Plex *mesh = (DM_Plex *)dm->data; 8738 DMLabel label; 8739 PetscInt pStart, pEnd; 8740 8741 PetscFunctionBegin; 8742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8743 if (start) { 8744 PetscAssertPointer(start, 3); 8745 *start = 0; 8746 } 8747 if (end) { 8748 PetscAssertPointer(end, 4); 8749 *end = 0; 8750 } 8751 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8752 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8753 if (mesh->tr) { 8754 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8755 } else { 8756 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8757 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8758 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8759 } 8760 PetscFunctionReturn(PETSC_SUCCESS); 8761 } 8762 8763 /*@ 8764 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8765 8766 Input Parameters: 8767 + dm - The `DMPLEX` object 8768 - depth - The depth for the given point stratum 8769 8770 Output Parameter: 8771 . gsize - The global number of points in the stratum 8772 8773 Level: advanced 8774 8775 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8776 @*/ 8777 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8778 { 8779 PetscSF sf; 8780 const PetscInt *leaves; 8781 PetscInt Nl, loc, start, end, lsize = 0; 8782 8783 PetscFunctionBegin; 8784 PetscCall(DMGetPointSF(dm, &sf)); 8785 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8786 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8787 for (PetscInt p = start; p < end; ++p) { 8788 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8789 if (loc < 0) ++lsize; 8790 } 8791 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8792 PetscFunctionReturn(PETSC_SUCCESS); 8793 } 8794 8795 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8796 { 8797 PetscSection section, globalSection; 8798 PetscInt *numbers, p; 8799 8800 PetscFunctionBegin; 8801 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8802 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8803 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8804 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8805 PetscCall(PetscSectionSetUp(section)); 8806 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8807 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8808 for (p = pStart; p < pEnd; ++p) { 8809 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8810 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8811 else numbers[p - pStart] += shift; 8812 } 8813 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8814 if (globalSize) { 8815 PetscLayout layout; 8816 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8817 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8818 PetscCall(PetscLayoutDestroy(&layout)); 8819 } 8820 PetscCall(PetscSectionDestroy(§ion)); 8821 PetscCall(PetscSectionDestroy(&globalSection)); 8822 PetscFunctionReturn(PETSC_SUCCESS); 8823 } 8824 8825 /*@ 8826 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8827 8828 Input Parameters: 8829 + dm - The `DMPLEX` object 8830 - includeAll - Whether to include all cells, or just the simplex and box cells 8831 8832 Output Parameter: 8833 . globalCellNumbers - Global cell numbers for all cells on this process 8834 8835 Level: developer 8836 8837 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8838 @*/ 8839 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8840 { 8841 PetscInt cellHeight, cStart, cEnd; 8842 8843 PetscFunctionBegin; 8844 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8845 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8846 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8847 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8848 PetscFunctionReturn(PETSC_SUCCESS); 8849 } 8850 8851 /*@ 8852 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8853 8854 Input Parameter: 8855 . dm - The `DMPLEX` object 8856 8857 Output Parameter: 8858 . globalCellNumbers - Global cell numbers for all cells on this process 8859 8860 Level: developer 8861 8862 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8863 @*/ 8864 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8865 { 8866 DM_Plex *mesh = (DM_Plex *)dm->data; 8867 8868 PetscFunctionBegin; 8869 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8870 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8871 *globalCellNumbers = mesh->globalCellNumbers; 8872 PetscFunctionReturn(PETSC_SUCCESS); 8873 } 8874 8875 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8876 { 8877 PetscInt vStart, vEnd; 8878 8879 PetscFunctionBegin; 8880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8881 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8882 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8883 PetscFunctionReturn(PETSC_SUCCESS); 8884 } 8885 8886 /*@ 8887 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8888 8889 Input Parameter: 8890 . dm - The `DMPLEX` object 8891 8892 Output Parameter: 8893 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8894 8895 Level: developer 8896 8897 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8898 @*/ 8899 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8900 { 8901 DM_Plex *mesh = (DM_Plex *)dm->data; 8902 8903 PetscFunctionBegin; 8904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8905 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8906 *globalVertexNumbers = mesh->globalVertexNumbers; 8907 PetscFunctionReturn(PETSC_SUCCESS); 8908 } 8909 8910 /*@ 8911 DMPlexCreatePointNumbering - Create a global numbering for all points. 8912 8913 Collective 8914 8915 Input Parameter: 8916 . dm - The `DMPLEX` object 8917 8918 Output Parameter: 8919 . globalPointNumbers - Global numbers for all points on this process 8920 8921 Level: developer 8922 8923 Notes: 8924 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8925 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8926 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8927 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8928 8929 The partitioned mesh is 8930 ``` 8931 (2)--0--(3)--1--(4) (1)--0--(2) 8932 ``` 8933 and its global numbering is 8934 ``` 8935 (3)--0--(4)--1--(5)--2--(6) 8936 ``` 8937 Then the global numbering is provided as 8938 ``` 8939 [0] Number of indices in set 5 8940 [0] 0 0 8941 [0] 1 1 8942 [0] 2 3 8943 [0] 3 4 8944 [0] 4 -6 8945 [1] Number of indices in set 3 8946 [1] 0 2 8947 [1] 1 5 8948 [1] 2 6 8949 ``` 8950 8951 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8952 @*/ 8953 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8954 { 8955 IS nums[4]; 8956 PetscInt depths[4], gdepths[4], starts[4]; 8957 PetscInt depth, d, shift = 0; 8958 PetscBool empty = PETSC_FALSE; 8959 8960 PetscFunctionBegin; 8961 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8962 PetscCall(DMPlexGetDepth(dm, &depth)); 8963 // For unstratified meshes use dim instead of depth 8964 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8965 // If any stratum is empty, we must mark all empty 8966 for (d = 0; d <= depth; ++d) { 8967 PetscInt end; 8968 8969 depths[d] = depth - d; 8970 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8971 if (!(starts[d] - end)) empty = PETSC_TRUE; 8972 } 8973 if (empty) 8974 for (d = 0; d <= depth; ++d) { 8975 depths[d] = -1; 8976 starts[d] = -1; 8977 } 8978 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8979 PetscCallMPI(MPIU_Allreduce(depths, gdepths, (PetscMPIInt)(depth + 1), MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8980 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]); 8981 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8982 for (d = 0; d <= depth; ++d) { 8983 PetscInt pStart, pEnd, gsize; 8984 8985 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8986 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8987 shift += gsize; 8988 } 8989 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8990 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8991 PetscFunctionReturn(PETSC_SUCCESS); 8992 } 8993 8994 /*@ 8995 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8996 8997 Collective 8998 8999 Input Parameter: 9000 . dm - The `DMPLEX` object 9001 9002 Output Parameter: 9003 . globalEdgeNumbers - Global numbers for all edges on this process 9004 9005 Level: developer 9006 9007 Notes: 9008 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). 9009 9010 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9011 @*/ 9012 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9013 { 9014 PetscSF sf; 9015 PetscInt eStart, eEnd; 9016 9017 PetscFunctionBegin; 9018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9019 PetscCall(DMGetPointSF(dm, &sf)); 9020 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9021 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9022 PetscFunctionReturn(PETSC_SUCCESS); 9023 } 9024 9025 /*@ 9026 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9027 9028 Input Parameter: 9029 . dm - The `DMPLEX` object 9030 9031 Output Parameter: 9032 . ranks - The rank field 9033 9034 Options Database Key: 9035 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9036 9037 Level: intermediate 9038 9039 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9040 @*/ 9041 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9042 { 9043 DM rdm; 9044 PetscFE fe; 9045 PetscScalar *r; 9046 PetscMPIInt rank; 9047 DMPolytopeType ct; 9048 PetscInt dim, cStart, cEnd, c; 9049 PetscBool simplex; 9050 9051 PetscFunctionBeginUser; 9052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9053 PetscAssertPointer(ranks, 2); 9054 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9055 PetscCall(DMClone(dm, &rdm)); 9056 PetscCall(DMGetDimension(rdm, &dim)); 9057 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9058 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9059 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9060 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9061 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9062 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9063 PetscCall(PetscFEDestroy(&fe)); 9064 PetscCall(DMCreateDS(rdm)); 9065 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9066 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9067 PetscCall(VecGetArray(*ranks, &r)); 9068 for (c = cStart; c < cEnd; ++c) { 9069 PetscScalar *lr; 9070 9071 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9072 if (lr) *lr = rank; 9073 } 9074 PetscCall(VecRestoreArray(*ranks, &r)); 9075 PetscCall(DMDestroy(&rdm)); 9076 PetscFunctionReturn(PETSC_SUCCESS); 9077 } 9078 9079 /*@ 9080 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9081 9082 Input Parameters: 9083 + dm - The `DMPLEX` 9084 - label - The `DMLabel` 9085 9086 Output Parameter: 9087 . val - The label value field 9088 9089 Options Database Key: 9090 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9091 9092 Level: intermediate 9093 9094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9095 @*/ 9096 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9097 { 9098 DM rdm, plex; 9099 Vec lval; 9100 PetscSection section; 9101 PetscFE fe; 9102 PetscScalar *v; 9103 PetscInt dim, pStart, pEnd, p, cStart; 9104 DMPolytopeType ct; 9105 char name[PETSC_MAX_PATH_LEN]; 9106 const char *lname, *prefix; 9107 9108 PetscFunctionBeginUser; 9109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9110 PetscAssertPointer(label, 2); 9111 PetscAssertPointer(val, 3); 9112 PetscCall(DMClone(dm, &rdm)); 9113 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9114 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9115 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9116 PetscCall(DMDestroy(&plex)); 9117 PetscCall(DMGetDimension(rdm, &dim)); 9118 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9119 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9120 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9121 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9122 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9123 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9124 PetscCall(PetscFEDestroy(&fe)); 9125 PetscCall(DMCreateDS(rdm)); 9126 PetscCall(DMCreateGlobalVector(rdm, val)); 9127 PetscCall(DMCreateLocalVector(rdm, &lval)); 9128 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9129 PetscCall(DMGetLocalSection(rdm, §ion)); 9130 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9131 PetscCall(VecGetArray(lval, &v)); 9132 for (p = pStart; p < pEnd; ++p) { 9133 PetscInt cval, dof, off; 9134 9135 PetscCall(PetscSectionGetDof(section, p, &dof)); 9136 if (!dof) continue; 9137 PetscCall(DMLabelGetValue(label, p, &cval)); 9138 PetscCall(PetscSectionGetOffset(section, p, &off)); 9139 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9140 } 9141 PetscCall(VecRestoreArray(lval, &v)); 9142 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9143 PetscCall(VecDestroy(&lval)); 9144 PetscCall(DMDestroy(&rdm)); 9145 PetscFunctionReturn(PETSC_SUCCESS); 9146 } 9147 9148 /*@ 9149 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9150 9151 Input Parameter: 9152 . dm - The `DMPLEX` object 9153 9154 Level: developer 9155 9156 Notes: 9157 This is a useful diagnostic when creating meshes programmatically. 9158 9159 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9160 9161 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9162 @*/ 9163 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9164 { 9165 PetscSection coneSection, supportSection; 9166 const PetscInt *cone, *support; 9167 PetscInt coneSize, c, supportSize, s; 9168 PetscInt pStart, pEnd, p, pp, csize, ssize; 9169 PetscBool storagecheck = PETSC_TRUE; 9170 9171 PetscFunctionBegin; 9172 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9173 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9174 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9175 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9176 /* Check that point p is found in the support of its cone points, and vice versa */ 9177 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9178 for (p = pStart; p < pEnd; ++p) { 9179 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9180 PetscCall(DMPlexGetCone(dm, p, &cone)); 9181 for (c = 0; c < coneSize; ++c) { 9182 PetscBool dup = PETSC_FALSE; 9183 PetscInt d; 9184 for (d = c - 1; d >= 0; --d) { 9185 if (cone[c] == cone[d]) { 9186 dup = PETSC_TRUE; 9187 break; 9188 } 9189 } 9190 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9191 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9192 for (s = 0; s < supportSize; ++s) { 9193 if (support[s] == p) break; 9194 } 9195 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9196 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9197 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9198 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9199 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9200 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9201 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9202 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]); 9203 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9204 } 9205 } 9206 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9207 if (p != pp) { 9208 storagecheck = PETSC_FALSE; 9209 continue; 9210 } 9211 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9212 PetscCall(DMPlexGetSupport(dm, p, &support)); 9213 for (s = 0; s < supportSize; ++s) { 9214 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9215 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9216 for (c = 0; c < coneSize; ++c) { 9217 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9218 if (cone[c] != pp) { 9219 c = 0; 9220 break; 9221 } 9222 if (cone[c] == p) break; 9223 } 9224 if (c >= coneSize) { 9225 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9226 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9227 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9228 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9229 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9230 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9231 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9232 } 9233 } 9234 } 9235 if (storagecheck) { 9236 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9237 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9238 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9239 } 9240 PetscFunctionReturn(PETSC_SUCCESS); 9241 } 9242 9243 /* 9244 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. 9245 */ 9246 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9247 { 9248 DMPolytopeType cct; 9249 PetscInt ptpoints[4]; 9250 const PetscInt *cone, *ccone, *ptcone; 9251 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9252 9253 PetscFunctionBegin; 9254 *unsplit = 0; 9255 switch (ct) { 9256 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9257 ptpoints[npt++] = c; 9258 break; 9259 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9260 PetscCall(DMPlexGetCone(dm, c, &cone)); 9261 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9262 for (cp = 0; cp < coneSize; ++cp) { 9263 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9264 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9265 } 9266 break; 9267 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9268 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9269 PetscCall(DMPlexGetCone(dm, c, &cone)); 9270 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9271 for (cp = 0; cp < coneSize; ++cp) { 9272 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9273 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9274 for (ccp = 0; ccp < cconeSize; ++ccp) { 9275 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9276 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9277 PetscInt p; 9278 for (p = 0; p < npt; ++p) 9279 if (ptpoints[p] == ccone[ccp]) break; 9280 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9281 } 9282 } 9283 } 9284 break; 9285 default: 9286 break; 9287 } 9288 for (pt = 0; pt < npt; ++pt) { 9289 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9290 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9291 } 9292 PetscFunctionReturn(PETSC_SUCCESS); 9293 } 9294 9295 /*@ 9296 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 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 Currently applicable only to homogeneous simplex or tensor meshes. 9307 9308 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9309 9310 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9311 @*/ 9312 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9313 { 9314 DMPlexInterpolatedFlag interp; 9315 DMPolytopeType ct; 9316 PetscInt vStart, vEnd, cStart, cEnd, c; 9317 9318 PetscFunctionBegin; 9319 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9320 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9321 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9322 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9323 for (c = cStart; c < cEnd; ++c) { 9324 PetscInt *closure = NULL; 9325 PetscInt coneSize, closureSize, cl, Nv = 0; 9326 9327 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9328 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9329 if (interp == DMPLEX_INTERPOLATED_FULL) { 9330 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9331 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)); 9332 } 9333 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9334 for (cl = 0; cl < closureSize * 2; cl += 2) { 9335 const PetscInt p = closure[cl]; 9336 if ((p >= vStart) && (p < vEnd)) ++Nv; 9337 } 9338 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9339 /* Special Case: Tensor faces with identified vertices */ 9340 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9341 PetscInt unsplit; 9342 9343 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9344 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9345 } 9346 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)); 9347 } 9348 PetscFunctionReturn(PETSC_SUCCESS); 9349 } 9350 9351 /*@ 9352 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9353 9354 Collective 9355 9356 Input Parameters: 9357 + dm - The `DMPLEX` object 9358 - cellHeight - Normally 0 9359 9360 Level: developer 9361 9362 Notes: 9363 This is a useful diagnostic when creating meshes programmatically. 9364 This routine is only relevant for meshes that are fully interpolated across all ranks. 9365 It will error out if a partially interpolated mesh is given on some rank. 9366 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9367 9368 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9369 9370 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9371 @*/ 9372 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9373 { 9374 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9375 DMPlexInterpolatedFlag interpEnum; 9376 9377 PetscFunctionBegin; 9378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9379 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9380 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9381 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9382 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9383 PetscFunctionReturn(PETSC_SUCCESS); 9384 } 9385 9386 PetscCall(DMGetDimension(dm, &dim)); 9387 PetscCall(DMPlexGetDepth(dm, &depth)); 9388 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9389 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9390 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9391 for (c = cStart; c < cEnd; ++c) { 9392 const PetscInt *cone, *ornt, *faceSizes, *faces; 9393 const DMPolytopeType *faceTypes; 9394 DMPolytopeType ct; 9395 PetscInt numFaces, coneSize, f; 9396 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9397 9398 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9399 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9400 if (unsplit) continue; 9401 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9402 PetscCall(DMPlexGetCone(dm, c, &cone)); 9403 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9404 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9405 for (cl = 0; cl < closureSize * 2; cl += 2) { 9406 const PetscInt p = closure[cl]; 9407 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9408 } 9409 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9410 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); 9411 for (f = 0; f < numFaces; ++f) { 9412 DMPolytopeType fct; 9413 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9414 9415 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9416 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9417 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9418 const PetscInt p = fclosure[cl]; 9419 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9420 } 9421 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]); 9422 for (v = 0; v < fnumCorners; ++v) { 9423 if (fclosure[v] != faces[fOff + v]) { 9424 PetscInt v1; 9425 9426 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9427 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9428 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9429 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9430 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9431 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]); 9432 } 9433 } 9434 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9435 fOff += faceSizes[f]; 9436 } 9437 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9438 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9439 } 9440 } 9441 PetscFunctionReturn(PETSC_SUCCESS); 9442 } 9443 9444 /*@ 9445 DMPlexCheckGeometry - Check the geometry of mesh cells 9446 9447 Input Parameter: 9448 . dm - The `DMPLEX` object 9449 9450 Level: developer 9451 9452 Notes: 9453 This is a useful diagnostic when creating meshes programmatically. 9454 9455 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9456 9457 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9458 @*/ 9459 PetscErrorCode DMPlexCheckGeometry(DM dm) 9460 { 9461 Vec coordinates; 9462 PetscReal detJ, J[9], refVol = 1.0; 9463 PetscReal vol; 9464 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9465 9466 PetscFunctionBegin; 9467 PetscCall(DMGetDimension(dm, &dim)); 9468 PetscCall(DMGetCoordinateDim(dm, &dE)); 9469 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9470 PetscCall(DMPlexGetDepth(dm, &depth)); 9471 for (d = 0; d < dim; ++d) refVol *= 2.0; 9472 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9473 /* Make sure local coordinates are created, because that step is collective */ 9474 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9475 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9476 for (c = cStart; c < cEnd; ++c) { 9477 DMPolytopeType ct; 9478 PetscInt unsplit; 9479 PetscBool ignoreZeroVol = PETSC_FALSE; 9480 9481 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9482 switch (ct) { 9483 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9484 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9485 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9486 ignoreZeroVol = PETSC_TRUE; 9487 break; 9488 default: 9489 break; 9490 } 9491 switch (ct) { 9492 case DM_POLYTOPE_TRI_PRISM: 9493 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9494 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9495 case DM_POLYTOPE_PYRAMID: 9496 continue; 9497 default: 9498 break; 9499 } 9500 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9501 if (unsplit) continue; 9502 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9503 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); 9504 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9505 /* This should work with periodicity since DG coordinates should be used */ 9506 if (depth > 1) { 9507 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9508 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); 9509 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9510 } 9511 } 9512 PetscFunctionReturn(PETSC_SUCCESS); 9513 } 9514 9515 /*@ 9516 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9517 9518 Collective 9519 9520 Input Parameters: 9521 + dm - The `DMPLEX` object 9522 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9523 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9524 9525 Level: developer 9526 9527 Notes: 9528 This is mainly intended for debugging/testing purposes. 9529 9530 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9531 9532 Extra roots can come from periodic cuts, where additional points appear on the boundary 9533 9534 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9535 @*/ 9536 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9537 { 9538 PetscInt l, nleaves, nroots, overlap; 9539 const PetscInt *locals; 9540 const PetscSFNode *remotes; 9541 PetscBool distributed; 9542 MPI_Comm comm; 9543 PetscMPIInt rank; 9544 9545 PetscFunctionBegin; 9546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9547 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9548 else pointSF = dm->sf; 9549 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9550 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9551 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9552 { 9553 PetscMPIInt mpiFlag; 9554 9555 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9556 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9557 } 9558 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9559 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9560 if (!distributed) { 9561 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); 9562 PetscFunctionReturn(PETSC_SUCCESS); 9563 } 9564 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); 9565 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9566 9567 /* Check SF graph is compatible with DMPlex chart */ 9568 { 9569 PetscInt pStart, pEnd, maxLeaf; 9570 9571 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9572 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9573 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9574 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9575 } 9576 9577 /* Check Point SF has no local points referenced */ 9578 for (l = 0; l < nleaves; l++) { 9579 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%d,%" PetscInt_FMT ")", locals ? locals[l] : l, (PetscMPIInt)remotes[l].rank, remotes[l].index); 9580 } 9581 9582 /* Check there are no cells in interface */ 9583 if (!overlap) { 9584 PetscInt cellHeight, cStart, cEnd; 9585 9586 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9587 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9588 for (l = 0; l < nleaves; ++l) { 9589 const PetscInt point = locals ? locals[l] : l; 9590 9591 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9592 } 9593 } 9594 9595 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9596 { 9597 const PetscInt *rootdegree; 9598 9599 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9600 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9601 for (l = 0; l < nleaves; ++l) { 9602 const PetscInt point = locals ? locals[l] : l; 9603 const PetscInt *cone; 9604 PetscInt coneSize, c, idx; 9605 9606 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9607 PetscCall(DMPlexGetCone(dm, point, &cone)); 9608 for (c = 0; c < coneSize; ++c) { 9609 if (!rootdegree[cone[c]]) { 9610 if (locals) { 9611 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9612 } else { 9613 idx = (cone[c] < nleaves) ? cone[c] : -1; 9614 } 9615 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9616 } 9617 } 9618 } 9619 } 9620 PetscFunctionReturn(PETSC_SUCCESS); 9621 } 9622 9623 /*@ 9624 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9625 9626 Collective 9627 9628 Input Parameter: 9629 . dm - The `DMPLEX` object 9630 9631 Level: developer 9632 9633 Notes: 9634 This is mainly intended for debugging/testing purposes. 9635 9636 Other cell types which are disconnected would be caught by the symmetry and face checks. 9637 9638 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9639 9640 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9641 @*/ 9642 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9643 { 9644 PetscInt pStart, pEnd, vStart, vEnd; 9645 9646 PetscFunctionBegin; 9647 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9648 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9649 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9650 for (PetscInt v = vStart; v < vEnd; ++v) { 9651 PetscInt suppSize; 9652 9653 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9654 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9655 } 9656 PetscFunctionReturn(PETSC_SUCCESS); 9657 } 9658 9659 /*@ 9660 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9661 9662 Input Parameter: 9663 . dm - The `DMPLEX` object 9664 9665 Level: developer 9666 9667 Notes: 9668 This is a useful diagnostic when creating meshes programmatically. 9669 9670 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9671 9672 Currently does not include `DMPlexCheckCellShape()`. 9673 9674 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9675 @*/ 9676 PetscErrorCode DMPlexCheck(DM dm) 9677 { 9678 PetscInt cellHeight; 9679 9680 PetscFunctionBegin; 9681 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9682 PetscCall(DMPlexCheckSymmetry(dm)); 9683 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9684 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9685 PetscCall(DMPlexCheckGeometry(dm)); 9686 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9687 PetscCall(DMPlexCheckInterfaceCones(dm)); 9688 PetscCall(DMPlexCheckOrphanVertices(dm)); 9689 PetscFunctionReturn(PETSC_SUCCESS); 9690 } 9691 9692 typedef struct cell_stats { 9693 PetscReal min, max, sum, squaresum; 9694 PetscInt count; 9695 } cell_stats_t; 9696 9697 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9698 { 9699 PetscInt i, N = *len; 9700 9701 for (i = 0; i < N; i++) { 9702 cell_stats_t *A = (cell_stats_t *)a; 9703 cell_stats_t *B = (cell_stats_t *)b; 9704 9705 B->min = PetscMin(A->min, B->min); 9706 B->max = PetscMax(A->max, B->max); 9707 B->sum += A->sum; 9708 B->squaresum += A->squaresum; 9709 B->count += A->count; 9710 } 9711 } 9712 9713 /*@ 9714 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9715 9716 Collective 9717 9718 Input Parameters: 9719 + dm - The `DMPLEX` object 9720 . output - If true, statistics will be displayed on `stdout` 9721 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9722 9723 Level: developer 9724 9725 Notes: 9726 This is mainly intended for debugging/testing purposes. 9727 9728 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9729 9730 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9731 @*/ 9732 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9733 { 9734 DM dmCoarse; 9735 cell_stats_t stats, globalStats; 9736 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9737 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9738 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9739 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9740 PetscMPIInt rank, size; 9741 9742 PetscFunctionBegin; 9743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9744 stats.min = PETSC_MAX_REAL; 9745 stats.max = PETSC_MIN_REAL; 9746 stats.sum = stats.squaresum = 0.; 9747 stats.count = 0; 9748 9749 PetscCallMPI(MPI_Comm_size(comm, &size)); 9750 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9751 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9752 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9753 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9754 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9755 for (c = cStart; c < cEnd; c++) { 9756 PetscInt i; 9757 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9758 9759 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9760 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9761 for (i = 0; i < PetscSqr(cdim); ++i) { 9762 frobJ += J[i] * J[i]; 9763 frobInvJ += invJ[i] * invJ[i]; 9764 } 9765 cond2 = frobJ * frobInvJ; 9766 cond = PetscSqrtReal(cond2); 9767 9768 stats.min = PetscMin(stats.min, cond); 9769 stats.max = PetscMax(stats.max, cond); 9770 stats.sum += cond; 9771 stats.squaresum += cond2; 9772 stats.count++; 9773 if (output && cond > limit) { 9774 PetscSection coordSection; 9775 Vec coordsLocal; 9776 PetscScalar *coords = NULL; 9777 PetscInt Nv, d, clSize, cl, *closure = NULL; 9778 9779 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9780 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9781 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9782 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9783 for (i = 0; i < Nv / cdim; ++i) { 9784 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9785 for (d = 0; d < cdim; ++d) { 9786 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9787 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9788 } 9789 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9790 } 9791 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9792 for (cl = 0; cl < clSize * 2; cl += 2) { 9793 const PetscInt edge = closure[cl]; 9794 9795 if ((edge >= eStart) && (edge < eEnd)) { 9796 PetscReal len; 9797 9798 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9799 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9800 } 9801 } 9802 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9803 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9804 } 9805 } 9806 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9807 9808 if (size > 1) { 9809 PetscMPIInt blockLengths[2] = {4, 1}; 9810 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9811 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9812 MPI_Op statReduce; 9813 9814 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9815 PetscCallMPI(MPI_Type_commit(&statType)); 9816 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9817 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9818 PetscCallMPI(MPI_Op_free(&statReduce)); 9819 PetscCallMPI(MPI_Type_free(&statType)); 9820 } else { 9821 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9822 } 9823 if (rank == 0) { 9824 count = globalStats.count; 9825 min = globalStats.min; 9826 max = globalStats.max; 9827 mean = globalStats.sum / globalStats.count; 9828 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9829 } 9830 9831 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)); 9832 PetscCall(PetscFree2(J, invJ)); 9833 9834 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9835 if (dmCoarse) { 9836 PetscBool isplex; 9837 9838 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9839 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9840 } 9841 PetscFunctionReturn(PETSC_SUCCESS); 9842 } 9843 9844 /*@ 9845 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9846 orthogonal quality below given tolerance. 9847 9848 Collective 9849 9850 Input Parameters: 9851 + dm - The `DMPLEX` object 9852 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9853 - atol - [0, 1] Absolute tolerance for tagging cells. 9854 9855 Output Parameters: 9856 + OrthQual - `Vec` containing orthogonal quality per cell 9857 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9858 9859 Options Database Keys: 9860 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9861 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9862 9863 Level: intermediate 9864 9865 Notes: 9866 Orthogonal quality is given by the following formula\: 9867 9868 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9869 9870 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 9871 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9872 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9873 calculating the cosine of the angle between these vectors. 9874 9875 Orthogonal quality ranges from 1 (best) to 0 (worst). 9876 9877 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9878 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9879 9880 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9881 9882 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9883 @*/ 9884 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9885 { 9886 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9887 PetscInt *idx; 9888 PetscScalar *oqVals; 9889 const PetscScalar *cellGeomArr, *faceGeomArr; 9890 PetscReal *ci, *fi, *Ai; 9891 MPI_Comm comm; 9892 Vec cellgeom, facegeom; 9893 DM dmFace, dmCell; 9894 IS glob; 9895 ISLocalToGlobalMapping ltog; 9896 PetscViewer vwr; 9897 9898 PetscFunctionBegin; 9899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9900 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9901 PetscAssertPointer(OrthQual, 4); 9902 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9903 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9904 PetscCall(DMGetDimension(dm, &nc)); 9905 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9906 { 9907 DMPlexInterpolatedFlag interpFlag; 9908 9909 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9910 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9911 PetscMPIInt rank; 9912 9913 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9914 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9915 } 9916 } 9917 if (OrthQualLabel) { 9918 PetscAssertPointer(OrthQualLabel, 5); 9919 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9920 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9921 } else { 9922 *OrthQualLabel = NULL; 9923 } 9924 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9925 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9926 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9927 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9928 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9929 PetscCall(VecCreate(comm, OrthQual)); 9930 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9931 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9932 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9933 PetscCall(VecSetUp(*OrthQual)); 9934 PetscCall(ISDestroy(&glob)); 9935 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9936 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9937 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9938 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9939 PetscCall(VecGetDM(cellgeom, &dmCell)); 9940 PetscCall(VecGetDM(facegeom, &dmFace)); 9941 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9942 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9943 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9944 PetscInt cellarr[2], *adj = NULL; 9945 PetscScalar *cArr, *fArr; 9946 PetscReal minvalc = 1.0, minvalf = 1.0; 9947 PetscFVCellGeom *cg; 9948 9949 idx[cellIter] = cell - cStart; 9950 cellarr[0] = cell; 9951 /* Make indexing into cellGeom easier */ 9952 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9953 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9954 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9955 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9956 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9957 PetscInt i; 9958 const PetscInt neigh = adj[cellneigh]; 9959 PetscReal normci = 0, normfi = 0, normai = 0; 9960 PetscFVCellGeom *cgneigh; 9961 PetscFVFaceGeom *fg; 9962 9963 /* Don't count ourselves in the neighbor list */ 9964 if (neigh == cell) continue; 9965 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9966 cellarr[1] = neigh; 9967 { 9968 PetscInt numcovpts; 9969 const PetscInt *covpts; 9970 9971 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9972 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9973 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9974 } 9975 9976 /* Compute c_i, f_i and their norms */ 9977 for (i = 0; i < nc; i++) { 9978 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9979 fi[i] = fg->centroid[i] - cg->centroid[i]; 9980 Ai[i] = fg->normal[i]; 9981 normci += PetscPowReal(ci[i], 2); 9982 normfi += PetscPowReal(fi[i], 2); 9983 normai += PetscPowReal(Ai[i], 2); 9984 } 9985 normci = PetscSqrtReal(normci); 9986 normfi = PetscSqrtReal(normfi); 9987 normai = PetscSqrtReal(normai); 9988 9989 /* Normalize and compute for each face-cell-normal pair */ 9990 for (i = 0; i < nc; i++) { 9991 ci[i] = ci[i] / normci; 9992 fi[i] = fi[i] / normfi; 9993 Ai[i] = Ai[i] / normai; 9994 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9995 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9996 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9997 } 9998 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9999 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10000 } 10001 PetscCall(PetscFree(adj)); 10002 PetscCall(PetscFree2(cArr, fArr)); 10003 /* Defer to cell if they're equal */ 10004 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10005 if (OrthQualLabel) { 10006 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10007 } 10008 } 10009 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10010 PetscCall(VecAssemblyBegin(*OrthQual)); 10011 PetscCall(VecAssemblyEnd(*OrthQual)); 10012 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10013 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10014 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10015 if (OrthQualLabel) { 10016 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10017 } 10018 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10019 PetscCall(PetscViewerDestroy(&vwr)); 10020 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10021 PetscFunctionReturn(PETSC_SUCCESS); 10022 } 10023 10024 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10025 * interpolator construction */ 10026 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10027 { 10028 PetscSection section, newSection, gsection; 10029 PetscSF sf; 10030 PetscBool hasConstraints, ghasConstraints; 10031 10032 PetscFunctionBegin; 10033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10034 PetscAssertPointer(odm, 2); 10035 PetscCall(DMGetLocalSection(dm, §ion)); 10036 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10037 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10038 if (!ghasConstraints) { 10039 PetscCall(PetscObjectReference((PetscObject)dm)); 10040 *odm = dm; 10041 PetscFunctionReturn(PETSC_SUCCESS); 10042 } 10043 PetscCall(DMClone(dm, odm)); 10044 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10045 PetscCall(DMGetLocalSection(*odm, &newSection)); 10046 PetscCall(DMGetPointSF(*odm, &sf)); 10047 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10048 PetscCall(DMSetGlobalSection(*odm, gsection)); 10049 PetscCall(PetscSectionDestroy(&gsection)); 10050 PetscFunctionReturn(PETSC_SUCCESS); 10051 } 10052 10053 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10054 { 10055 DM dmco, dmfo; 10056 Mat interpo; 10057 Vec rscale; 10058 Vec cglobalo, clocal; 10059 Vec fglobal, fglobalo, flocal; 10060 PetscBool regular; 10061 10062 PetscFunctionBegin; 10063 PetscCall(DMGetFullDM(dmc, &dmco)); 10064 PetscCall(DMGetFullDM(dmf, &dmfo)); 10065 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10066 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10067 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10068 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10069 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10070 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10071 PetscCall(VecSet(cglobalo, 0.)); 10072 PetscCall(VecSet(clocal, 0.)); 10073 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10074 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10075 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10076 PetscCall(VecSet(fglobal, 0.)); 10077 PetscCall(VecSet(fglobalo, 0.)); 10078 PetscCall(VecSet(flocal, 0.)); 10079 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10080 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10081 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10082 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10083 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10084 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10085 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10086 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10087 *shift = fglobal; 10088 PetscCall(VecDestroy(&flocal)); 10089 PetscCall(VecDestroy(&fglobalo)); 10090 PetscCall(VecDestroy(&clocal)); 10091 PetscCall(VecDestroy(&cglobalo)); 10092 PetscCall(VecDestroy(&rscale)); 10093 PetscCall(MatDestroy(&interpo)); 10094 PetscCall(DMDestroy(&dmfo)); 10095 PetscCall(DMDestroy(&dmco)); 10096 PetscFunctionReturn(PETSC_SUCCESS); 10097 } 10098 10099 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10100 { 10101 PetscObject shifto; 10102 Vec shift; 10103 10104 PetscFunctionBegin; 10105 if (!interp) { 10106 Vec rscale; 10107 10108 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10109 PetscCall(VecDestroy(&rscale)); 10110 } else { 10111 PetscCall(PetscObjectReference((PetscObject)interp)); 10112 } 10113 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10114 if (!shifto) { 10115 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10116 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10117 shifto = (PetscObject)shift; 10118 PetscCall(VecDestroy(&shift)); 10119 } 10120 shift = (Vec)shifto; 10121 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10122 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10123 PetscCall(MatDestroy(&interp)); 10124 PetscFunctionReturn(PETSC_SUCCESS); 10125 } 10126 10127 /* Pointwise interpolation 10128 Just code FEM for now 10129 u^f = I u^c 10130 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10131 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10132 I_{ij} = psi^f_i phi^c_j 10133 */ 10134 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10135 { 10136 PetscSection gsc, gsf; 10137 PetscInt m, n; 10138 void *ctx; 10139 DM cdm; 10140 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10141 10142 PetscFunctionBegin; 10143 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10144 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10145 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10146 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10147 10148 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10149 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10150 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10151 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10152 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10153 10154 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10155 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10156 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10157 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10158 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10159 if (scaling) { 10160 /* Use naive scaling */ 10161 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10162 } 10163 PetscFunctionReturn(PETSC_SUCCESS); 10164 } 10165 10166 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10167 { 10168 VecScatter ctx; 10169 10170 PetscFunctionBegin; 10171 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10172 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10173 PetscCall(VecScatterDestroy(&ctx)); 10174 PetscFunctionReturn(PETSC_SUCCESS); 10175 } 10176 10177 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[]) 10178 { 10179 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10180 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10181 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10182 } 10183 10184 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10185 { 10186 DM dmc; 10187 PetscDS ds; 10188 Vec ones, locmass; 10189 IS cellIS; 10190 PetscFormKey key; 10191 PetscInt depth; 10192 10193 PetscFunctionBegin; 10194 PetscCall(DMClone(dm, &dmc)); 10195 PetscCall(DMCopyDisc(dm, dmc)); 10196 PetscCall(DMGetDS(dmc, &ds)); 10197 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10198 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10199 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10200 else PetscCall(DMGetLocalVector(dm, &locmass)); 10201 PetscCall(DMGetLocalVector(dm, &ones)); 10202 PetscCall(DMPlexGetDepth(dm, &depth)); 10203 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10204 PetscCall(VecSet(locmass, 0.0)); 10205 PetscCall(VecSet(ones, 1.0)); 10206 key.label = NULL; 10207 key.value = 0; 10208 key.field = 0; 10209 key.part = 0; 10210 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10211 PetscCall(ISDestroy(&cellIS)); 10212 if (mass) { 10213 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10214 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10215 } 10216 PetscCall(DMRestoreLocalVector(dm, &ones)); 10217 if (lmass) *lmass = locmass; 10218 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10219 PetscCall(DMDestroy(&dmc)); 10220 PetscFunctionReturn(PETSC_SUCCESS); 10221 } 10222 10223 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10224 { 10225 PetscSection gsc, gsf; 10226 PetscInt m, n; 10227 void *ctx; 10228 DM cdm; 10229 PetscBool regular; 10230 10231 PetscFunctionBegin; 10232 if (dmFine == dmCoarse) { 10233 DM dmc; 10234 PetscDS ds; 10235 PetscWeakForm wf; 10236 Vec u; 10237 IS cellIS; 10238 PetscFormKey key; 10239 PetscInt depth; 10240 10241 PetscCall(DMClone(dmFine, &dmc)); 10242 PetscCall(DMCopyDisc(dmFine, dmc)); 10243 PetscCall(DMGetDS(dmc, &ds)); 10244 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10245 PetscCall(PetscWeakFormClear(wf)); 10246 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10247 PetscCall(DMCreateMatrix(dmc, mass)); 10248 PetscCall(DMGetLocalVector(dmc, &u)); 10249 PetscCall(DMPlexGetDepth(dmc, &depth)); 10250 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10251 PetscCall(MatZeroEntries(*mass)); 10252 key.label = NULL; 10253 key.value = 0; 10254 key.field = 0; 10255 key.part = 0; 10256 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10257 PetscCall(ISDestroy(&cellIS)); 10258 PetscCall(DMRestoreLocalVector(dmc, &u)); 10259 PetscCall(DMDestroy(&dmc)); 10260 } else { 10261 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10262 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10263 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10264 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10265 10266 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10267 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10268 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10269 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10270 10271 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10272 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10273 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10274 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10275 } 10276 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10277 PetscFunctionReturn(PETSC_SUCCESS); 10278 } 10279 10280 /*@ 10281 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10282 10283 Input Parameter: 10284 . dm - The `DMPLEX` object 10285 10286 Output Parameter: 10287 . regular - The flag 10288 10289 Level: intermediate 10290 10291 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10292 @*/ 10293 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10294 { 10295 PetscFunctionBegin; 10296 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10297 PetscAssertPointer(regular, 2); 10298 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10299 PetscFunctionReturn(PETSC_SUCCESS); 10300 } 10301 10302 /*@ 10303 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10304 10305 Input Parameters: 10306 + dm - The `DMPLEX` object 10307 - regular - The flag 10308 10309 Level: intermediate 10310 10311 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10312 @*/ 10313 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10314 { 10315 PetscFunctionBegin; 10316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10317 ((DM_Plex *)dm->data)->regularRefinement = regular; 10318 PetscFunctionReturn(PETSC_SUCCESS); 10319 } 10320 10321 /*@ 10322 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10323 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10324 10325 Not Collective 10326 10327 Input Parameter: 10328 . dm - The `DMPLEX` object 10329 10330 Output Parameters: 10331 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10332 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10333 10334 Level: intermediate 10335 10336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10337 @*/ 10338 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10339 { 10340 DM_Plex *plex = (DM_Plex *)dm->data; 10341 10342 PetscFunctionBegin; 10343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10344 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10345 if (anchorSection) *anchorSection = plex->anchorSection; 10346 if (anchorIS) *anchorIS = plex->anchorIS; 10347 PetscFunctionReturn(PETSC_SUCCESS); 10348 } 10349 10350 /*@ 10351 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10352 10353 Collective 10354 10355 Input Parameters: 10356 + dm - The `DMPLEX` object 10357 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10358 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10359 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10360 10361 Level: intermediate 10362 10363 Notes: 10364 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10365 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10366 combination of other points' degrees of freedom. 10367 10368 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10369 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10370 10371 The reference counts of `anchorSection` and `anchorIS` are incremented. 10372 10373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10374 @*/ 10375 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10376 { 10377 DM_Plex *plex = (DM_Plex *)dm->data; 10378 PetscMPIInt result; 10379 10380 PetscFunctionBegin; 10381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10382 if (anchorSection) { 10383 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10384 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10385 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10386 } 10387 if (anchorIS) { 10388 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10389 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10390 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10391 } 10392 10393 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10394 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10395 plex->anchorSection = anchorSection; 10396 10397 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10398 PetscCall(ISDestroy(&plex->anchorIS)); 10399 plex->anchorIS = anchorIS; 10400 10401 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10402 PetscInt size, a, pStart, pEnd; 10403 const PetscInt *anchors; 10404 10405 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10406 PetscCall(ISGetLocalSize(anchorIS, &size)); 10407 PetscCall(ISGetIndices(anchorIS, &anchors)); 10408 for (a = 0; a < size; a++) { 10409 PetscInt p; 10410 10411 p = anchors[a]; 10412 if (p >= pStart && p < pEnd) { 10413 PetscInt dof; 10414 10415 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10416 if (dof) { 10417 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10418 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10419 } 10420 } 10421 } 10422 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10423 } 10424 /* reset the generic constraints */ 10425 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10426 PetscFunctionReturn(PETSC_SUCCESS); 10427 } 10428 10429 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10430 { 10431 PetscSection anchorSection; 10432 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10433 10434 PetscFunctionBegin; 10435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10436 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10437 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10438 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10439 if (numFields) { 10440 PetscInt f; 10441 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10442 10443 for (f = 0; f < numFields; f++) { 10444 PetscInt numComp; 10445 10446 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10447 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10448 } 10449 } 10450 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10451 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10452 pStart = PetscMax(pStart, sStart); 10453 pEnd = PetscMin(pEnd, sEnd); 10454 pEnd = PetscMax(pStart, pEnd); 10455 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10456 for (p = pStart; p < pEnd; p++) { 10457 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10458 if (dof) { 10459 PetscCall(PetscSectionGetDof(section, p, &dof)); 10460 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10461 for (f = 0; f < numFields; f++) { 10462 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10463 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10464 } 10465 } 10466 } 10467 PetscCall(PetscSectionSetUp(*cSec)); 10468 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10469 PetscFunctionReturn(PETSC_SUCCESS); 10470 } 10471 10472 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10473 { 10474 PetscSection aSec; 10475 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10476 const PetscInt *anchors; 10477 PetscInt numFields, f; 10478 IS aIS; 10479 MatType mtype; 10480 PetscBool iscuda, iskokkos; 10481 10482 PetscFunctionBegin; 10483 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10484 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10485 PetscCall(PetscSectionGetStorageSize(section, &n)); 10486 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10487 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10488 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10489 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10490 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10491 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10492 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10493 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10494 else mtype = MATSEQAIJ; 10495 PetscCall(MatSetType(*cMat, mtype)); 10496 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10497 PetscCall(ISGetIndices(aIS, &anchors)); 10498 /* cSec will be a subset of aSec and section */ 10499 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10500 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10501 PetscCall(PetscMalloc1(m + 1, &i)); 10502 i[0] = 0; 10503 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10504 for (p = pStart; p < pEnd; p++) { 10505 PetscInt rDof, rOff, r; 10506 10507 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10508 if (!rDof) continue; 10509 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10510 if (numFields) { 10511 for (f = 0; f < numFields; f++) { 10512 annz = 0; 10513 for (r = 0; r < rDof; r++) { 10514 a = anchors[rOff + r]; 10515 if (a < sStart || a >= sEnd) continue; 10516 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10517 annz += aDof; 10518 } 10519 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10520 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10521 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10522 } 10523 } else { 10524 annz = 0; 10525 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10526 for (q = 0; q < dof; q++) { 10527 a = anchors[rOff + q]; 10528 if (a < sStart || a >= sEnd) continue; 10529 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10530 annz += aDof; 10531 } 10532 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10533 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10534 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10535 } 10536 } 10537 nnz = i[m]; 10538 PetscCall(PetscMalloc1(nnz, &j)); 10539 offset = 0; 10540 for (p = pStart; p < pEnd; p++) { 10541 if (numFields) { 10542 for (f = 0; f < numFields; f++) { 10543 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10544 for (q = 0; q < dof; q++) { 10545 PetscInt rDof, rOff, r; 10546 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10547 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10548 for (r = 0; r < rDof; r++) { 10549 PetscInt s; 10550 10551 a = anchors[rOff + r]; 10552 if (a < sStart || a >= sEnd) continue; 10553 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10554 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10555 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10556 } 10557 } 10558 } 10559 } else { 10560 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10561 for (q = 0; q < dof; q++) { 10562 PetscInt rDof, rOff, r; 10563 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10564 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10565 for (r = 0; r < rDof; r++) { 10566 PetscInt s; 10567 10568 a = anchors[rOff + r]; 10569 if (a < sStart || a >= sEnd) continue; 10570 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10571 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10572 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10573 } 10574 } 10575 } 10576 } 10577 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10578 PetscCall(PetscFree(i)); 10579 PetscCall(PetscFree(j)); 10580 PetscCall(ISRestoreIndices(aIS, &anchors)); 10581 PetscFunctionReturn(PETSC_SUCCESS); 10582 } 10583 10584 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10585 { 10586 DM_Plex *plex = (DM_Plex *)dm->data; 10587 PetscSection anchorSection, section, cSec; 10588 Mat cMat; 10589 10590 PetscFunctionBegin; 10591 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10592 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10593 if (anchorSection) { 10594 PetscInt Nf; 10595 10596 PetscCall(DMGetLocalSection(dm, §ion)); 10597 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10598 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10599 PetscCall(DMGetNumFields(dm, &Nf)); 10600 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10601 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10602 PetscCall(PetscSectionDestroy(&cSec)); 10603 PetscCall(MatDestroy(&cMat)); 10604 } 10605 PetscFunctionReturn(PETSC_SUCCESS); 10606 } 10607 10608 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10609 { 10610 IS subis; 10611 PetscSection section, subsection; 10612 10613 PetscFunctionBegin; 10614 PetscCall(DMGetLocalSection(dm, §ion)); 10615 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10616 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10617 /* Create subdomain */ 10618 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10619 /* Create submodel */ 10620 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10621 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10622 PetscCall(DMSetLocalSection(*subdm, subsection)); 10623 PetscCall(PetscSectionDestroy(&subsection)); 10624 PetscCall(DMCopyDisc(dm, *subdm)); 10625 /* Create map from submodel to global model */ 10626 if (is) { 10627 PetscSection sectionGlobal, subsectionGlobal; 10628 IS spIS; 10629 const PetscInt *spmap; 10630 PetscInt *subIndices; 10631 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10632 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10633 10634 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10635 PetscCall(ISGetIndices(spIS, &spmap)); 10636 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10637 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10638 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10639 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10640 for (p = pStart; p < pEnd; ++p) { 10641 PetscInt gdof, pSubSize = 0; 10642 10643 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10644 if (gdof > 0) { 10645 for (f = 0; f < Nf; ++f) { 10646 PetscInt fdof, fcdof; 10647 10648 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10649 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10650 pSubSize += fdof - fcdof; 10651 } 10652 subSize += pSubSize; 10653 if (pSubSize) { 10654 if (bs < 0) { 10655 bs = pSubSize; 10656 } else if (bs != pSubSize) { 10657 /* Layout does not admit a pointwise block size */ 10658 bs = 1; 10659 } 10660 } 10661 } 10662 } 10663 /* Must have same blocksize on all procs (some might have no points) */ 10664 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10665 bsLocal[1] = bs; 10666 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10667 if (bsMinMax[0] != bsMinMax[1]) { 10668 bs = 1; 10669 } else { 10670 bs = bsMinMax[0]; 10671 } 10672 PetscCall(PetscMalloc1(subSize, &subIndices)); 10673 for (p = pStart; p < pEnd; ++p) { 10674 PetscInt gdof, goff; 10675 10676 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10677 if (gdof > 0) { 10678 const PetscInt point = spmap[p]; 10679 10680 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10681 for (f = 0; f < Nf; ++f) { 10682 PetscInt fdof, fcdof, fc, f2, poff = 0; 10683 10684 /* Can get rid of this loop by storing field information in the global section */ 10685 for (f2 = 0; f2 < f; ++f2) { 10686 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10687 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10688 poff += fdof - fcdof; 10689 } 10690 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10691 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10692 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10693 } 10694 } 10695 } 10696 PetscCall(ISRestoreIndices(spIS, &spmap)); 10697 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10698 if (bs > 1) { 10699 /* We need to check that the block size does not come from non-contiguous fields */ 10700 PetscInt i, j, set = 1; 10701 for (i = 0; i < subSize; i += bs) { 10702 for (j = 0; j < bs; ++j) { 10703 if (subIndices[i + j] != subIndices[i] + j) { 10704 set = 0; 10705 break; 10706 } 10707 } 10708 } 10709 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10710 } 10711 /* Attach nullspace */ 10712 for (f = 0; f < Nf; ++f) { 10713 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10714 if ((*subdm)->nullspaceConstructors[f]) break; 10715 } 10716 if (f < Nf) { 10717 MatNullSpace nullSpace; 10718 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10719 10720 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10721 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10722 } 10723 } 10724 PetscFunctionReturn(PETSC_SUCCESS); 10725 } 10726 10727 /*@ 10728 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10729 10730 Input Parameters: 10731 + dm - The `DM` 10732 - dummy - unused argument 10733 10734 Options Database Key: 10735 . -dm_plex_monitor_throughput - Activate the monitor 10736 10737 Level: developer 10738 10739 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10740 @*/ 10741 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10742 { 10743 PetscLogHandler default_handler; 10744 10745 PetscFunctionBegin; 10746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10747 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10748 if (default_handler) { 10749 PetscLogEvent event; 10750 PetscEventPerfInfo eventInfo; 10751 PetscReal cellRate, flopRate; 10752 PetscInt cStart, cEnd, Nf, N; 10753 const char *name; 10754 10755 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10756 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10757 PetscCall(DMGetNumFields(dm, &Nf)); 10758 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10759 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10760 N = (cEnd - cStart) * Nf * eventInfo.count; 10761 flopRate = eventInfo.flops / eventInfo.time; 10762 cellRate = N / eventInfo.time; 10763 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))); 10764 } else { 10765 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."); 10766 } 10767 PetscFunctionReturn(PETSC_SUCCESS); 10768 } 10769