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