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 } else if (ishdf5) { 675 #if defined(PETSC_HAVE_HDF5) 676 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 677 #else 678 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 679 #endif 680 } else if (isexodusii) { 681 #if defined(PETSC_HAVE_EXODUSII) 682 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 683 #else 684 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 685 #endif 686 } else { 687 PetscBool isseq; 688 689 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 690 if (isseq) PetscCall(VecView_Seq(v, viewer)); 691 else PetscCall(VecView_MPI(v, viewer)); 692 } 693 PetscFunctionReturn(PETSC_SUCCESS); 694 } 695 696 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 697 { 698 DM dm; 699 MPI_Comm comm; 700 PetscViewerFormat format; 701 Vec v; 702 PetscBool isvtk, ishdf5; 703 704 PetscFunctionBegin; 705 PetscCall(VecGetDM(originalv, &dm)); 706 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 707 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 708 PetscCall(PetscViewerGetFormat(viewer, &format)); 709 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 710 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 711 if (format == PETSC_VIEWER_NATIVE) { 712 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 713 /* this need a better fix */ 714 if (dm->useNatural) { 715 if (dm->sfNatural) { 716 const char *vecname; 717 PetscInt n, nroots; 718 719 PetscCall(VecGetLocalSize(originalv, &n)); 720 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 721 if (n == nroots) { 722 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 723 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 724 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 725 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 726 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 727 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 728 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 729 } else v = originalv; 730 } else v = originalv; 731 732 if (ishdf5) { 733 #if defined(PETSC_HAVE_HDF5) 734 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 735 #else 736 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 737 #endif 738 } else if (isvtk) { 739 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 740 } else { 741 PetscBool isseq; 742 743 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 744 if (isseq) PetscCall(VecView_Seq(v, viewer)); 745 else PetscCall(VecView_MPI(v, viewer)); 746 } 747 if (v != originalv) PetscCall(VecDestroy(&v)); 748 PetscFunctionReturn(PETSC_SUCCESS); 749 } 750 751 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 752 { 753 DM dm; 754 PetscBool ishdf5; 755 756 PetscFunctionBegin; 757 PetscCall(VecGetDM(v, &dm)); 758 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 759 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 760 if (ishdf5) { 761 DM dmBC; 762 Vec gv; 763 const char *name; 764 765 PetscCall(DMGetOutputDM(dm, &dmBC)); 766 PetscCall(DMGetGlobalVector(dmBC, &gv)); 767 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 768 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 769 PetscCall(VecLoad_Default(gv, viewer)); 770 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 771 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 772 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 773 } else PetscCall(VecLoad_Default(v, viewer)); 774 PetscFunctionReturn(PETSC_SUCCESS); 775 } 776 777 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 778 { 779 DM dm; 780 PetscBool ishdf5, isexodusii, iscgns; 781 782 PetscFunctionBegin; 783 PetscCall(VecGetDM(v, &dm)); 784 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 785 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 786 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 787 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 788 if (ishdf5) { 789 #if defined(PETSC_HAVE_HDF5) 790 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 791 #else 792 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 793 #endif 794 } else if (isexodusii) { 795 #if defined(PETSC_HAVE_EXODUSII) 796 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 797 #else 798 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 799 #endif 800 } else if (iscgns) { 801 #if defined(PETSC_HAVE_CGNS) 802 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 803 #else 804 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 805 #endif 806 } else PetscCall(VecLoad_Default(v, viewer)); 807 PetscFunctionReturn(PETSC_SUCCESS); 808 } 809 810 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 811 { 812 DM dm; 813 PetscViewerFormat format; 814 PetscBool ishdf5; 815 816 PetscFunctionBegin; 817 PetscCall(VecGetDM(originalv, &dm)); 818 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 819 PetscCall(PetscViewerGetFormat(viewer, &format)); 820 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 821 if (format == PETSC_VIEWER_NATIVE) { 822 if (dm->useNatural) { 823 if (dm->sfNatural) { 824 if (ishdf5) { 825 #if defined(PETSC_HAVE_HDF5) 826 Vec v; 827 const char *vecname; 828 829 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 830 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 831 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 832 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 833 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 834 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 835 PetscCall(VecDestroy(&v)); 836 #else 837 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 838 #endif 839 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 840 } 841 } else PetscCall(VecLoad_Default(originalv, viewer)); 842 } 843 PetscFunctionReturn(PETSC_SUCCESS); 844 } 845 846 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 847 { 848 PetscSection coordSection; 849 Vec coordinates; 850 DMLabel depthLabel, celltypeLabel; 851 const char *name[4]; 852 const PetscScalar *a; 853 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 854 855 PetscFunctionBegin; 856 PetscCall(DMGetDimension(dm, &dim)); 857 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 858 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 859 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 860 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 861 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 862 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 863 PetscCall(VecGetArrayRead(coordinates, &a)); 864 name[0] = "vertex"; 865 name[1] = "edge"; 866 name[dim - 1] = "face"; 867 name[dim] = "cell"; 868 for (c = cStart; c < cEnd; ++c) { 869 PetscInt *closure = NULL; 870 PetscInt closureSize, cl, ct; 871 872 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 873 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 874 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 875 PetscCall(PetscViewerASCIIPushTab(viewer)); 876 for (cl = 0; cl < closureSize * 2; cl += 2) { 877 PetscInt point = closure[cl], depth, dof, off, d, p; 878 879 if ((point < pStart) || (point >= pEnd)) continue; 880 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 881 if (!dof) continue; 882 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 883 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 884 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 885 for (p = 0; p < dof / dim; ++p) { 886 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 887 for (d = 0; d < dim; ++d) { 888 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 889 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 890 } 891 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 892 } 893 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 894 } 895 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 896 PetscCall(PetscViewerASCIIPopTab(viewer)); 897 } 898 PetscCall(VecRestoreArrayRead(coordinates, &a)); 899 PetscFunctionReturn(PETSC_SUCCESS); 900 } 901 902 typedef enum { 903 CS_CARTESIAN, 904 CS_POLAR, 905 CS_CYLINDRICAL, 906 CS_SPHERICAL 907 } CoordSystem; 908 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 909 910 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 911 { 912 PetscInt i; 913 914 PetscFunctionBegin; 915 if (dim > 3) { 916 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 917 } else { 918 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 919 920 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 921 switch (cs) { 922 case CS_CARTESIAN: 923 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 924 break; 925 case CS_POLAR: 926 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 927 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 928 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 929 break; 930 case CS_CYLINDRICAL: 931 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 932 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 933 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 934 trcoords[2] = coords[2]; 935 break; 936 case CS_SPHERICAL: 937 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 938 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 939 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 940 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 941 break; 942 } 943 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 944 } 945 PetscFunctionReturn(PETSC_SUCCESS); 946 } 947 948 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 949 { 950 DM_Plex *mesh = (DM_Plex *)dm->data; 951 DM cdm, cdmCell; 952 PetscSection coordSection, coordSectionCell; 953 Vec coordinates, coordinatesCell; 954 PetscViewerFormat format; 955 956 PetscFunctionBegin; 957 PetscCall(PetscViewerGetFormat(viewer, &format)); 958 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 959 const char *name; 960 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 961 PetscInt pStart, pEnd, p, numLabels, l; 962 PetscMPIInt rank, size; 963 964 PetscCall(DMGetCoordinateDM(dm, &cdm)); 965 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 966 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 967 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 968 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 969 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 970 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 971 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 972 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 973 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 974 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 975 PetscCall(DMGetDimension(dm, &dim)); 976 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 977 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 978 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 979 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 980 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 981 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 982 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 983 for (p = pStart; p < pEnd; ++p) { 984 PetscInt dof, off, s; 985 986 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 987 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 988 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 989 } 990 PetscCall(PetscViewerFlush(viewer)); 991 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 992 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 993 for (p = pStart; p < pEnd; ++p) { 994 PetscInt dof, off, c; 995 996 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 997 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 998 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])); 999 } 1000 PetscCall(PetscViewerFlush(viewer)); 1001 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1002 if (coordSection && coordinates) { 1003 CoordSystem cs = CS_CARTESIAN; 1004 const PetscScalar *array, *arrayCell = NULL; 1005 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1006 PetscMPIInt rank; 1007 const char *name; 1008 1009 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1010 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1011 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1012 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1013 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1014 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1015 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1016 pStart = PetscMin(pvStart, pcStart); 1017 pEnd = PetscMax(pvEnd, pcEnd); 1018 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1021 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1022 1023 PetscCall(VecGetArrayRead(coordinates, &array)); 1024 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1025 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1026 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1027 for (p = pStart; p < pEnd; ++p) { 1028 PetscInt dof, off; 1029 1030 if (p >= pvStart && p < pvEnd) { 1031 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1032 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1033 if (dof) { 1034 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1035 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1036 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1037 } 1038 } 1039 if (cdmCell && p >= pcStart && p < pcEnd) { 1040 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1041 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1042 if (dof) { 1043 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1044 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1046 } 1047 } 1048 } 1049 PetscCall(PetscViewerFlush(viewer)); 1050 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1051 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1052 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1053 } 1054 PetscCall(DMGetNumLabels(dm, &numLabels)); 1055 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1056 for (l = 0; l < numLabels; ++l) { 1057 DMLabel label; 1058 PetscBool isdepth; 1059 const char *name; 1060 1061 PetscCall(DMGetLabelName(dm, l, &name)); 1062 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1063 if (isdepth) continue; 1064 PetscCall(DMGetLabel(dm, name, &label)); 1065 PetscCall(DMLabelView(label, viewer)); 1066 } 1067 if (size > 1) { 1068 PetscSF sf; 1069 1070 PetscCall(DMGetPointSF(dm, &sf)); 1071 PetscCall(PetscSFView(sf, viewer)); 1072 } 1073 if (mesh->periodic.face_sfs) 1074 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1075 PetscCall(PetscViewerFlush(viewer)); 1076 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1077 const char *name, *color; 1078 const char *defcolors[3] = {"gray", "orange", "green"}; 1079 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1080 char lname[PETSC_MAX_PATH_LEN]; 1081 PetscReal scale = 2.0; 1082 PetscReal tikzscale = 1.0; 1083 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1084 double tcoords[3]; 1085 PetscScalar *coords; 1086 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; 1087 PetscMPIInt rank, size; 1088 char **names, **colors, **lcolors; 1089 PetscBool flg, lflg; 1090 PetscBT wp = NULL; 1091 PetscInt pEnd, pStart; 1092 1093 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1094 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1095 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1096 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1097 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1098 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1099 PetscCall(DMGetDimension(dm, &dim)); 1100 PetscCall(DMPlexGetDepth(dm, &depth)); 1101 PetscCall(DMGetNumLabels(dm, &numLabels)); 1102 numLabels = PetscMax(numLabels, 10); 1103 numColors = 10; 1104 numLColors = 10; 1105 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1106 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1107 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1108 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1109 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1110 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1111 n = 4; 1112 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1113 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1114 n = 4; 1115 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1116 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1117 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1118 if (!useLabels) numLabels = 0; 1119 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1120 if (!useColors) { 1121 numColors = 3; 1122 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1123 } 1124 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1125 if (!useColors) { 1126 numLColors = 4; 1127 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1128 } 1129 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1130 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1131 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1132 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1133 if (depth < dim) plotEdges = PETSC_FALSE; 1134 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1135 1136 /* filter points with labelvalue != labeldefaultvalue */ 1137 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1138 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1139 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1140 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1141 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1142 if (lflg) { 1143 DMLabel lbl; 1144 1145 PetscCall(DMGetLabel(dm, lname, &lbl)); 1146 if (lbl) { 1147 PetscInt val, defval; 1148 1149 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1150 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1151 for (c = pStart; c < pEnd; c++) { 1152 PetscInt *closure = NULL; 1153 PetscInt closureSize; 1154 1155 PetscCall(DMLabelGetValue(lbl, c, &val)); 1156 if (val == defval) continue; 1157 1158 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1159 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1160 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1161 } 1162 } 1163 } 1164 1165 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1166 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1167 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1169 \\documentclass[tikz]{standalone}\n\n\ 1170 \\usepackage{pgflibraryshapes}\n\ 1171 \\usetikzlibrary{backgrounds}\n\ 1172 \\usetikzlibrary{arrows}\n\ 1173 \\begin{document}\n")); 1174 if (size > 1) { 1175 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1176 for (p = 0; p < size; ++p) { 1177 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1178 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1179 } 1180 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1181 } 1182 if (drawHasse) { 1183 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1184 1185 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1186 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1187 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1188 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1189 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1190 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1191 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1192 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1193 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1194 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1195 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1196 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1197 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1198 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1199 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1200 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1201 } 1202 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1203 1204 /* Plot vertices */ 1205 PetscCall(VecGetArray(coordinates, &coords)); 1206 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1207 for (v = vStart; v < vEnd; ++v) { 1208 PetscInt off, dof, d; 1209 PetscBool isLabeled = PETSC_FALSE; 1210 1211 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1212 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1213 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1214 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1215 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1216 for (d = 0; d < dof; ++d) { 1217 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1218 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1219 } 1220 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1221 if (dim == 3) { 1222 PetscReal tmp = tcoords[1]; 1223 tcoords[1] = tcoords[2]; 1224 tcoords[2] = -tmp; 1225 } 1226 for (d = 0; d < dof; ++d) { 1227 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1228 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1229 } 1230 if (drawHasse) color = colors[0 % numColors]; 1231 else color = colors[rank % numColors]; 1232 for (l = 0; l < numLabels; ++l) { 1233 PetscInt val; 1234 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1235 if (val >= 0) { 1236 color = lcolors[l % numLColors]; 1237 isLabeled = PETSC_TRUE; 1238 break; 1239 } 1240 } 1241 if (drawNumbers[0]) { 1242 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1243 } else if (drawColors[0]) { 1244 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1245 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1246 } 1247 PetscCall(VecRestoreArray(coordinates, &coords)); 1248 PetscCall(PetscViewerFlush(viewer)); 1249 /* Plot edges */ 1250 if (plotEdges) { 1251 PetscCall(VecGetArray(coordinates, &coords)); 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1253 for (e = eStart; e < eEnd; ++e) { 1254 const PetscInt *cone; 1255 PetscInt coneSize, offA, offB, dof, d; 1256 1257 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1258 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1259 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1260 PetscCall(DMPlexGetCone(dm, e, &cone)); 1261 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1262 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1263 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1264 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1265 for (d = 0; d < dof; ++d) { 1266 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1267 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1268 } 1269 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1270 if (dim == 3) { 1271 PetscReal tmp = tcoords[1]; 1272 tcoords[1] = tcoords[2]; 1273 tcoords[2] = -tmp; 1274 } 1275 for (d = 0; d < dof; ++d) { 1276 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1277 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1278 } 1279 if (drawHasse) color = colors[1 % numColors]; 1280 else color = colors[rank % numColors]; 1281 for (l = 0; l < numLabels; ++l) { 1282 PetscInt val; 1283 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1284 if (val >= 0) { 1285 color = lcolors[l % numLColors]; 1286 break; 1287 } 1288 } 1289 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1290 } 1291 PetscCall(VecRestoreArray(coordinates, &coords)); 1292 PetscCall(PetscViewerFlush(viewer)); 1293 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1294 } 1295 /* Plot cells */ 1296 if (dim == 3 || !drawNumbers[1]) { 1297 for (e = eStart; e < eEnd; ++e) { 1298 const PetscInt *cone; 1299 1300 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1301 color = colors[rank % numColors]; 1302 for (l = 0; l < numLabels; ++l) { 1303 PetscInt val; 1304 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1305 if (val >= 0) { 1306 color = lcolors[l % numLColors]; 1307 break; 1308 } 1309 } 1310 PetscCall(DMPlexGetCone(dm, e, &cone)); 1311 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1312 } 1313 } else { 1314 DMPolytopeType ct; 1315 1316 /* Drawing a 2D polygon */ 1317 for (c = cStart; c < cEnd; ++c) { 1318 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1319 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1320 if (DMPolytopeTypeIsHybrid(ct)) { 1321 const PetscInt *cone; 1322 PetscInt coneSize, e; 1323 1324 PetscCall(DMPlexGetCone(dm, c, &cone)); 1325 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1326 for (e = 0; e < coneSize; ++e) { 1327 const PetscInt *econe; 1328 1329 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1330 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)); 1331 } 1332 } else { 1333 PetscInt *closure = NULL; 1334 PetscInt closureSize, Nv = 0, v; 1335 1336 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1337 for (p = 0; p < closureSize * 2; p += 2) { 1338 const PetscInt point = closure[p]; 1339 1340 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1341 } 1342 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1343 for (v = 0; v <= Nv; ++v) { 1344 const PetscInt vertex = closure[v % Nv]; 1345 1346 if (v > 0) { 1347 if (plotEdges) { 1348 const PetscInt *edge; 1349 PetscInt endpoints[2], ne; 1350 1351 endpoints[0] = closure[v - 1]; 1352 endpoints[1] = vertex; 1353 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1354 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1355 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1356 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1357 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1358 } 1359 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1360 } 1361 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1362 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1363 } 1364 } 1365 } 1366 for (c = cStart; c < cEnd; ++c) { 1367 double ccoords[3] = {0.0, 0.0, 0.0}; 1368 PetscBool isLabeled = PETSC_FALSE; 1369 PetscScalar *cellCoords = NULL; 1370 const PetscScalar *array; 1371 PetscInt numCoords, cdim, d; 1372 PetscBool isDG; 1373 1374 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1375 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1376 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1377 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1379 for (p = 0; p < numCoords / cdim; ++p) { 1380 for (d = 0; d < cdim; ++d) { 1381 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1382 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1383 } 1384 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1385 if (cdim == 3) { 1386 PetscReal tmp = tcoords[1]; 1387 tcoords[1] = tcoords[2]; 1388 tcoords[2] = -tmp; 1389 } 1390 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1391 } 1392 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1393 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1394 for (d = 0; d < cdim; ++d) { 1395 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1396 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1397 } 1398 if (drawHasse) color = colors[depth % numColors]; 1399 else color = colors[rank % numColors]; 1400 for (l = 0; l < numLabels; ++l) { 1401 PetscInt val; 1402 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1403 if (val >= 0) { 1404 color = lcolors[l % numLColors]; 1405 isLabeled = PETSC_TRUE; 1406 break; 1407 } 1408 } 1409 if (drawNumbers[dim]) { 1410 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1411 } else if (drawColors[dim]) { 1412 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1413 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1414 } 1415 if (drawHasse) { 1416 int height = 0; 1417 1418 color = colors[depth % numColors]; 1419 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1420 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1421 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1422 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1424 1425 if (depth > 2) { 1426 color = colors[1 % numColors]; 1427 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1429 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1430 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1431 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1432 } 1433 1434 color = colors[1 % numColors]; 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1436 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1437 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1438 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1439 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1440 1441 color = colors[0 % numColors]; 1442 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1443 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1444 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1445 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1446 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1447 1448 for (p = pStart; p < pEnd; ++p) { 1449 const PetscInt *cone; 1450 PetscInt coneSize, cp; 1451 1452 PetscCall(DMPlexGetCone(dm, p, &cone)); 1453 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1454 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1455 } 1456 } 1457 PetscCall(PetscViewerFlush(viewer)); 1458 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1459 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1460 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1461 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1462 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1463 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1464 PetscCall(PetscFree3(names, colors, lcolors)); 1465 PetscCall(PetscBTDestroy(&wp)); 1466 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1467 Vec cown, acown; 1468 VecScatter sct; 1469 ISLocalToGlobalMapping g2l; 1470 IS gid, acis; 1471 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1472 MPI_Group ggroup, ngroup; 1473 PetscScalar *array, nid; 1474 const PetscInt *idxs; 1475 PetscInt *idxs2, *start, *adjacency, *work; 1476 PetscInt64 lm[3], gm[3]; 1477 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1478 PetscMPIInt d1, d2, rank; 1479 1480 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1481 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1482 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1483 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1484 #endif 1485 if (ncomm != MPI_COMM_NULL) { 1486 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1487 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1488 d1 = 0; 1489 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1490 nid = d2; 1491 PetscCallMPI(MPI_Group_free(&ggroup)); 1492 PetscCallMPI(MPI_Group_free(&ngroup)); 1493 PetscCallMPI(MPI_Comm_free(&ncomm)); 1494 } else nid = 0.0; 1495 1496 /* Get connectivity */ 1497 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1498 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1499 1500 /* filter overlapped local cells */ 1501 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1502 PetscCall(ISGetIndices(gid, &idxs)); 1503 PetscCall(ISGetLocalSize(gid, &cum)); 1504 PetscCall(PetscMalloc1(cum, &idxs2)); 1505 for (c = cStart, cum = 0; c < cEnd; c++) { 1506 if (idxs[c - cStart] < 0) continue; 1507 idxs2[cum++] = idxs[c - cStart]; 1508 } 1509 PetscCall(ISRestoreIndices(gid, &idxs)); 1510 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1511 PetscCall(ISDestroy(&gid)); 1512 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1513 1514 /* support for node-aware cell locality */ 1515 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1516 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1517 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1518 PetscCall(VecGetArray(cown, &array)); 1519 for (c = 0; c < numVertices; c++) array[c] = nid; 1520 PetscCall(VecRestoreArray(cown, &array)); 1521 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1522 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1523 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1524 PetscCall(ISDestroy(&acis)); 1525 PetscCall(VecScatterDestroy(&sct)); 1526 PetscCall(VecDestroy(&cown)); 1527 1528 /* compute edgeCut */ 1529 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1530 PetscCall(PetscMalloc1(cum, &work)); 1531 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1532 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1533 PetscCall(ISDestroy(&gid)); 1534 PetscCall(VecGetArray(acown, &array)); 1535 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1536 PetscInt totl; 1537 1538 totl = start[c + 1] - start[c]; 1539 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1540 for (i = 0; i < totl; i++) { 1541 if (work[i] < 0) { 1542 ect += 1; 1543 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1544 } 1545 } 1546 } 1547 PetscCall(PetscFree(work)); 1548 PetscCall(VecRestoreArray(acown, &array)); 1549 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1550 lm[1] = -numVertices; 1551 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1552 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1553 lm[0] = ect; /* edgeCut */ 1554 lm[1] = ectn; /* node-aware edgeCut */ 1555 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1556 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1557 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1558 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1559 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1560 #else 1561 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1562 #endif 1563 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1564 PetscCall(PetscFree(start)); 1565 PetscCall(PetscFree(adjacency)); 1566 PetscCall(VecDestroy(&acown)); 1567 } else { 1568 const char *name; 1569 PetscInt *sizes, *hybsizes, *ghostsizes; 1570 PetscInt locDepth, depth, cellHeight, dim, d; 1571 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1572 PetscInt numLabels, l, maxSize = 17; 1573 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1574 MPI_Comm comm; 1575 PetscMPIInt size, rank; 1576 1577 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1578 PetscCallMPI(MPI_Comm_size(comm, &size)); 1579 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1580 PetscCall(DMGetDimension(dm, &dim)); 1581 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1582 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1583 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1584 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1585 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1586 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1587 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1588 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1589 gcNum = gcEnd - gcStart; 1590 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1591 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1592 for (d = 0; d <= depth; d++) { 1593 PetscInt Nc[2] = {0, 0}, ict; 1594 1595 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1596 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1597 ict = ct0; 1598 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1599 ct0 = (DMPolytopeType)ict; 1600 for (p = pStart; p < pEnd; ++p) { 1601 DMPolytopeType ct; 1602 1603 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1604 if (ct == ct0) ++Nc[0]; 1605 else ++Nc[1]; 1606 } 1607 if (size < maxSize) { 1608 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1609 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1610 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1611 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1612 for (p = 0; p < size; ++p) { 1613 if (rank == 0) { 1614 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1615 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1616 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1617 } 1618 } 1619 } else { 1620 PetscInt locMinMax[2]; 1621 1622 locMinMax[0] = Nc[0] + Nc[1]; 1623 locMinMax[1] = Nc[0] + Nc[1]; 1624 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1625 locMinMax[0] = Nc[1]; 1626 locMinMax[1] = Nc[1]; 1627 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1628 if (d == depth) { 1629 locMinMax[0] = gcNum; 1630 locMinMax[1] = gcNum; 1631 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1632 } 1633 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1634 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1635 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1636 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1637 } 1638 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1639 } 1640 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1641 { 1642 const PetscReal *maxCell; 1643 const PetscReal *L; 1644 PetscBool localized; 1645 1646 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1647 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1648 if (L || localized) { 1649 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1650 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1651 if (L) { 1652 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1653 for (d = 0; d < dim; ++d) { 1654 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1655 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1656 } 1657 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1658 } 1659 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1660 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1661 } 1662 } 1663 PetscCall(DMGetNumLabels(dm, &numLabels)); 1664 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1665 for (l = 0; l < numLabels; ++l) { 1666 DMLabel label; 1667 const char *name; 1668 PetscInt *values; 1669 PetscInt numValues, v; 1670 1671 PetscCall(DMGetLabelName(dm, l, &name)); 1672 PetscCall(DMGetLabel(dm, name, &label)); 1673 PetscCall(DMLabelGetNumValues(label, &numValues)); 1674 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1675 1676 { // Extract array of DMLabel values so it can be sorted 1677 IS is_values; 1678 const PetscInt *is_values_local = NULL; 1679 1680 PetscCall(DMLabelGetValueIS(label, &is_values)); 1681 PetscCall(ISGetIndices(is_values, &is_values_local)); 1682 PetscCall(PetscMalloc1(numValues, &values)); 1683 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1684 PetscCall(PetscSortInt(numValues, values)); 1685 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1686 PetscCall(ISDestroy(&is_values)); 1687 } 1688 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1689 for (v = 0; v < numValues; ++v) { 1690 PetscInt size; 1691 1692 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1693 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1694 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1695 } 1696 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1697 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1698 PetscCall(PetscFree(values)); 1699 } 1700 { 1701 char **labelNames; 1702 PetscInt Nl = numLabels; 1703 PetscBool flg; 1704 1705 PetscCall(PetscMalloc1(Nl, &labelNames)); 1706 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1707 for (l = 0; l < Nl; ++l) { 1708 DMLabel label; 1709 1710 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1711 if (flg) { 1712 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1713 PetscCall(DMLabelView(label, viewer)); 1714 } 1715 PetscCall(PetscFree(labelNames[l])); 1716 } 1717 PetscCall(PetscFree(labelNames)); 1718 } 1719 /* If no fields are specified, people do not want to see adjacency */ 1720 if (dm->Nf) { 1721 PetscInt f; 1722 1723 for (f = 0; f < dm->Nf; ++f) { 1724 const char *name; 1725 1726 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1727 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1728 PetscCall(PetscViewerASCIIPushTab(viewer)); 1729 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1730 if (dm->fields[f].adjacency[0]) { 1731 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1732 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1733 } else { 1734 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1735 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1736 } 1737 PetscCall(PetscViewerASCIIPopTab(viewer)); 1738 } 1739 } 1740 PetscCall(DMGetCoarseDM(dm, &cdm)); 1741 if (cdm) { 1742 PetscCall(PetscViewerASCIIPushTab(viewer)); 1743 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1744 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1745 PetscCall(PetscViewerASCIIPopTab(viewer)); 1746 } 1747 } 1748 PetscFunctionReturn(PETSC_SUCCESS); 1749 } 1750 1751 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1752 { 1753 DMPolytopeType ct; 1754 PetscMPIInt rank; 1755 PetscInt cdim; 1756 1757 PetscFunctionBegin; 1758 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1759 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1760 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1761 switch (ct) { 1762 case DM_POLYTOPE_SEGMENT: 1763 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1764 switch (cdim) { 1765 case 1: { 1766 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1767 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1768 1769 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1770 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1771 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1772 } break; 1773 case 2: { 1774 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1775 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1776 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1777 1778 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1779 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)); 1780 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)); 1781 } break; 1782 default: 1783 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1784 } 1785 break; 1786 case DM_POLYTOPE_TRIANGLE: 1787 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)); 1788 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1789 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1790 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1791 break; 1792 case DM_POLYTOPE_QUADRILATERAL: 1793 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)); 1794 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)); 1795 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1796 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1797 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1798 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1799 break; 1800 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1801 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)); 1802 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)); 1803 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1804 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1805 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1806 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1807 break; 1808 case DM_POLYTOPE_FV_GHOST: 1809 break; 1810 default: 1811 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1812 } 1813 PetscFunctionReturn(PETSC_SUCCESS); 1814 } 1815 1816 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1817 { 1818 PetscReal centroid[2] = {0., 0.}; 1819 PetscMPIInt rank; 1820 PetscMPIInt fillColor; 1821 1822 PetscFunctionBegin; 1823 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1824 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1825 for (PetscInt v = 0; v < Nv; ++v) { 1826 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1827 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1828 } 1829 for (PetscInt e = 0; e < Nv; ++e) { 1830 refCoords[0] = refVertices[e * 2 + 0]; 1831 refCoords[1] = refVertices[e * 2 + 1]; 1832 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1833 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1834 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1835 } 1836 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1837 for (PetscInt d = 0; d < edgeDiv; ++d) { 1838 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)); 1839 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1840 } 1841 } 1842 PetscFunctionReturn(PETSC_SUCCESS); 1843 } 1844 1845 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1846 { 1847 DMPolytopeType ct; 1848 1849 PetscFunctionBegin; 1850 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1851 switch (ct) { 1852 case DM_POLYTOPE_TRIANGLE: { 1853 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1854 1855 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1856 } break; 1857 case DM_POLYTOPE_QUADRILATERAL: { 1858 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1859 1860 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1861 } break; 1862 default: 1863 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1864 } 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1869 { 1870 PetscDraw draw; 1871 DM cdm; 1872 PetscSection coordSection; 1873 Vec coordinates; 1874 PetscReal xyl[3], xyr[3]; 1875 PetscReal *refCoords, *edgeCoords; 1876 PetscBool isnull, drawAffine; 1877 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1878 1879 PetscFunctionBegin; 1880 PetscCall(DMGetCoordinateDim(dm, &dim)); 1881 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1882 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1883 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1884 edgeDiv = cDegree + 1; 1885 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1886 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1887 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1888 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1889 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1890 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1891 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1892 1893 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1894 PetscCall(PetscDrawIsNull(draw, &isnull)); 1895 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1896 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1897 1898 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1899 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1900 PetscCall(PetscDrawClear(draw)); 1901 1902 for (c = cStart; c < cEnd; ++c) { 1903 PetscScalar *coords = NULL; 1904 const PetscScalar *coords_arr; 1905 PetscInt numCoords; 1906 PetscBool isDG; 1907 1908 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1909 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1910 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1911 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1912 } 1913 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1914 PetscCall(PetscDrawFlush(draw)); 1915 PetscCall(PetscDrawPause(draw)); 1916 PetscCall(PetscDrawSave(draw)); 1917 PetscFunctionReturn(PETSC_SUCCESS); 1918 } 1919 1920 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1921 { 1922 DM odm = dm, rdm = dm, cdm; 1923 PetscFE fe; 1924 PetscSpace sp; 1925 PetscClassId id; 1926 PetscInt degree; 1927 PetscBool hoView = PETSC_TRUE; 1928 1929 PetscFunctionBegin; 1930 PetscObjectOptionsBegin((PetscObject)dm); 1931 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1932 PetscOptionsEnd(); 1933 PetscCall(PetscObjectReference((PetscObject)dm)); 1934 *hdm = dm; 1935 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1936 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1937 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1938 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1939 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1940 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1941 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1942 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1943 DM cdm, rcdm; 1944 Mat In; 1945 Vec cl, rcl; 1946 1947 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1948 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1949 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1950 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1951 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1952 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1953 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1954 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1955 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1956 PetscCall(MatMult(In, cl, rcl)); 1957 PetscCall(MatDestroy(&In)); 1958 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1959 PetscCall(DMDestroy(&odm)); 1960 odm = rdm; 1961 } 1962 *hdm = rdm; 1963 PetscFunctionReturn(PETSC_SUCCESS); 1964 } 1965 1966 #if defined(PETSC_HAVE_EXODUSII) 1967 #include <exodusII.h> 1968 #include <petscviewerexodusii.h> 1969 #endif 1970 1971 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1972 { 1973 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 1974 char name[PETSC_MAX_PATH_LEN]; 1975 1976 PetscFunctionBegin; 1977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1978 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1979 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1980 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1981 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1982 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1983 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1984 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1985 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1986 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 1987 if (iascii) { 1988 PetscViewerFormat format; 1989 PetscCall(PetscViewerGetFormat(viewer, &format)); 1990 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1991 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1992 } else if (ishdf5) { 1993 #if defined(PETSC_HAVE_HDF5) 1994 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1995 #else 1996 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1997 #endif 1998 } else if (isvtk) { 1999 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2000 } else if (isdraw) { 2001 DM hdm; 2002 2003 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2004 PetscCall(DMPlexView_Draw(hdm, viewer)); 2005 PetscCall(DMDestroy(&hdm)); 2006 } else if (isglvis) { 2007 PetscCall(DMPlexView_GLVis(dm, viewer)); 2008 #if defined(PETSC_HAVE_EXODUSII) 2009 } else if (isexodus) { 2010 /* 2011 exodusII requires that all sets be part of exactly one cell set. 2012 If the dm does not have a "Cell Sets" label defined, we create one 2013 with ID 1, containing all cells. 2014 Note that if the Cell Sets label is defined but does not cover all cells, 2015 we may still have a problem. This should probably be checked here or in the viewer; 2016 */ 2017 PetscInt numCS; 2018 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2019 if (!numCS) { 2020 PetscInt cStart, cEnd, c; 2021 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2022 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2023 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2024 } 2025 PetscCall(DMView_PlexExodusII(dm, viewer)); 2026 #endif 2027 #if defined(PETSC_HAVE_CGNS) 2028 } else if (iscgns) { 2029 PetscCall(DMView_PlexCGNS(dm, viewer)); 2030 #endif 2031 } else if (ispython) { 2032 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2033 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2034 /* Optionally view the partition */ 2035 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2036 if (flg) { 2037 Vec ranks; 2038 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2039 PetscCall(VecView(ranks, viewer)); 2040 PetscCall(VecDestroy(&ranks)); 2041 } 2042 /* Optionally view a label */ 2043 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2044 if (flg) { 2045 DMLabel label; 2046 Vec val; 2047 2048 PetscCall(DMGetLabel(dm, name, &label)); 2049 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2050 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2051 PetscCall(VecView(val, viewer)); 2052 PetscCall(VecDestroy(&val)); 2053 } 2054 PetscFunctionReturn(PETSC_SUCCESS); 2055 } 2056 2057 /*@ 2058 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2059 2060 Collective 2061 2062 Input Parameters: 2063 + dm - The `DM` whose topology is to be saved 2064 - viewer - The `PetscViewer` to save it in 2065 2066 Level: advanced 2067 2068 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2069 @*/ 2070 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2071 { 2072 PetscBool ishdf5; 2073 2074 PetscFunctionBegin; 2075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2076 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2077 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2078 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2079 if (ishdf5) { 2080 #if defined(PETSC_HAVE_HDF5) 2081 PetscViewerFormat format; 2082 PetscCall(PetscViewerGetFormat(viewer, &format)); 2083 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2084 IS globalPointNumbering; 2085 2086 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2087 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2088 PetscCall(ISDestroy(&globalPointNumbering)); 2089 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2090 #else 2091 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2092 #endif 2093 } 2094 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2095 PetscFunctionReturn(PETSC_SUCCESS); 2096 } 2097 2098 /*@ 2099 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2100 2101 Collective 2102 2103 Input Parameters: 2104 + dm - The `DM` whose coordinates are to be saved 2105 - viewer - The `PetscViewer` for saving 2106 2107 Level: advanced 2108 2109 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2110 @*/ 2111 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2112 { 2113 PetscBool ishdf5; 2114 2115 PetscFunctionBegin; 2116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2117 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2118 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2119 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2120 if (ishdf5) { 2121 #if defined(PETSC_HAVE_HDF5) 2122 PetscViewerFormat format; 2123 PetscCall(PetscViewerGetFormat(viewer, &format)); 2124 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2125 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2126 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2127 #else 2128 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2129 #endif 2130 } 2131 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2132 PetscFunctionReturn(PETSC_SUCCESS); 2133 } 2134 2135 /*@ 2136 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2137 2138 Collective 2139 2140 Input Parameters: 2141 + dm - The `DM` whose labels are to be saved 2142 - viewer - The `PetscViewer` for saving 2143 2144 Level: advanced 2145 2146 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2147 @*/ 2148 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2149 { 2150 PetscBool ishdf5; 2151 2152 PetscFunctionBegin; 2153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2154 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2155 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2156 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2157 if (ishdf5) { 2158 #if defined(PETSC_HAVE_HDF5) 2159 IS globalPointNumbering; 2160 PetscViewerFormat format; 2161 2162 PetscCall(PetscViewerGetFormat(viewer, &format)); 2163 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2164 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2165 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2166 PetscCall(ISDestroy(&globalPointNumbering)); 2167 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2168 #else 2169 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2170 #endif 2171 } 2172 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2173 PetscFunctionReturn(PETSC_SUCCESS); 2174 } 2175 2176 /*@ 2177 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2178 2179 Collective 2180 2181 Input Parameters: 2182 + dm - The `DM` that contains the topology on which the section to be saved is defined 2183 . viewer - The `PetscViewer` for saving 2184 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2185 2186 Level: advanced 2187 2188 Notes: 2189 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. 2190 2191 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. 2192 2193 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2194 @*/ 2195 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2196 { 2197 PetscBool ishdf5; 2198 2199 PetscFunctionBegin; 2200 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2201 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2202 if (!sectiondm) sectiondm = dm; 2203 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2204 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2205 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2206 if (ishdf5) { 2207 #if defined(PETSC_HAVE_HDF5) 2208 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2209 #else 2210 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2211 #endif 2212 } 2213 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2214 PetscFunctionReturn(PETSC_SUCCESS); 2215 } 2216 2217 /*@ 2218 DMPlexGlobalVectorView - Saves a global vector 2219 2220 Collective 2221 2222 Input Parameters: 2223 + dm - The `DM` that represents the topology 2224 . viewer - The `PetscViewer` to save data with 2225 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2226 - vec - The global vector to be saved 2227 2228 Level: advanced 2229 2230 Notes: 2231 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. 2232 2233 Calling sequence: 2234 .vb 2235 DMCreate(PETSC_COMM_WORLD, &dm); 2236 DMSetType(dm, DMPLEX); 2237 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2238 DMClone(dm, §iondm); 2239 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2240 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2241 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2242 PetscSectionSetChart(section, pStart, pEnd); 2243 PetscSectionSetUp(section); 2244 DMSetLocalSection(sectiondm, section); 2245 PetscSectionDestroy(§ion); 2246 DMGetGlobalVector(sectiondm, &vec); 2247 PetscObjectSetName((PetscObject)vec, "vec_name"); 2248 DMPlexTopologyView(dm, viewer); 2249 DMPlexSectionView(dm, viewer, sectiondm); 2250 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2251 DMRestoreGlobalVector(sectiondm, &vec); 2252 DMDestroy(§iondm); 2253 DMDestroy(&dm); 2254 .ve 2255 2256 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2257 @*/ 2258 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2259 { 2260 PetscBool ishdf5; 2261 2262 PetscFunctionBegin; 2263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2264 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2265 if (!sectiondm) sectiondm = dm; 2266 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2267 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2268 /* Check consistency */ 2269 { 2270 PetscSection section; 2271 PetscBool includesConstraints; 2272 PetscInt m, m1; 2273 2274 PetscCall(VecGetLocalSize(vec, &m1)); 2275 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2276 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2277 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2278 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2279 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2280 } 2281 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2282 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2283 if (ishdf5) { 2284 #if defined(PETSC_HAVE_HDF5) 2285 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2286 #else 2287 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2288 #endif 2289 } 2290 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2291 PetscFunctionReturn(PETSC_SUCCESS); 2292 } 2293 2294 /*@ 2295 DMPlexLocalVectorView - Saves a local vector 2296 2297 Collective 2298 2299 Input Parameters: 2300 + dm - The `DM` that represents the topology 2301 . viewer - The `PetscViewer` to save data with 2302 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2303 - vec - The local vector to be saved 2304 2305 Level: advanced 2306 2307 Note: 2308 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. 2309 2310 Calling sequence: 2311 .vb 2312 DMCreate(PETSC_COMM_WORLD, &dm); 2313 DMSetType(dm, DMPLEX); 2314 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2315 DMClone(dm, §iondm); 2316 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2317 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2318 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2319 PetscSectionSetChart(section, pStart, pEnd); 2320 PetscSectionSetUp(section); 2321 DMSetLocalSection(sectiondm, section); 2322 DMGetLocalVector(sectiondm, &vec); 2323 PetscObjectSetName((PetscObject)vec, "vec_name"); 2324 DMPlexTopologyView(dm, viewer); 2325 DMPlexSectionView(dm, viewer, sectiondm); 2326 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2327 DMRestoreLocalVector(sectiondm, &vec); 2328 DMDestroy(§iondm); 2329 DMDestroy(&dm); 2330 .ve 2331 2332 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2333 @*/ 2334 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2335 { 2336 PetscBool ishdf5; 2337 2338 PetscFunctionBegin; 2339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2340 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2341 if (!sectiondm) sectiondm = dm; 2342 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2343 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2344 /* Check consistency */ 2345 { 2346 PetscSection section; 2347 PetscBool includesConstraints; 2348 PetscInt m, m1; 2349 2350 PetscCall(VecGetLocalSize(vec, &m1)); 2351 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2352 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2353 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2354 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2355 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2356 } 2357 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2358 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2359 if (ishdf5) { 2360 #if defined(PETSC_HAVE_HDF5) 2361 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2362 #else 2363 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2364 #endif 2365 } 2366 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2367 PetscFunctionReturn(PETSC_SUCCESS); 2368 } 2369 2370 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2371 { 2372 PetscBool ishdf5; 2373 2374 PetscFunctionBegin; 2375 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2376 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2377 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2378 if (ishdf5) { 2379 #if defined(PETSC_HAVE_HDF5) 2380 PetscViewerFormat format; 2381 PetscCall(PetscViewerGetFormat(viewer, &format)); 2382 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2383 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2384 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2385 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2386 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2387 PetscFunctionReturn(PETSC_SUCCESS); 2388 #else 2389 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2390 #endif 2391 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2392 } 2393 2394 /*@ 2395 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2396 2397 Collective 2398 2399 Input Parameters: 2400 + dm - The `DM` into which the topology is loaded 2401 - viewer - The `PetscViewer` for the saved topology 2402 2403 Output Parameter: 2404 . 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; 2405 `NULL` if unneeded 2406 2407 Level: advanced 2408 2409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2410 `PetscViewer`, `PetscSF` 2411 @*/ 2412 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2413 { 2414 PetscBool ishdf5; 2415 2416 PetscFunctionBegin; 2417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2418 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2419 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2420 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2421 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2422 if (ishdf5) { 2423 #if defined(PETSC_HAVE_HDF5) 2424 PetscViewerFormat format; 2425 PetscCall(PetscViewerGetFormat(viewer, &format)); 2426 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2427 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2428 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2429 #else 2430 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2431 #endif 2432 } 2433 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2434 PetscFunctionReturn(PETSC_SUCCESS); 2435 } 2436 2437 /*@ 2438 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2439 2440 Collective 2441 2442 Input Parameters: 2443 + dm - The `DM` into which the coordinates are loaded 2444 . viewer - The `PetscViewer` for the saved coordinates 2445 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2446 2447 Level: advanced 2448 2449 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2450 `PetscSF`, `PetscViewer` 2451 @*/ 2452 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2453 { 2454 PetscBool ishdf5; 2455 2456 PetscFunctionBegin; 2457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2458 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2459 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2460 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2461 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2462 if (ishdf5) { 2463 #if defined(PETSC_HAVE_HDF5) 2464 PetscViewerFormat format; 2465 PetscCall(PetscViewerGetFormat(viewer, &format)); 2466 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2467 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2468 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2469 #else 2470 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2471 #endif 2472 } 2473 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2474 PetscFunctionReturn(PETSC_SUCCESS); 2475 } 2476 2477 /*@ 2478 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2479 2480 Collective 2481 2482 Input Parameters: 2483 + dm - The `DM` into which the labels are loaded 2484 . viewer - The `PetscViewer` for the saved labels 2485 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2486 2487 Level: advanced 2488 2489 Note: 2490 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2491 2492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2493 `PetscSF`, `PetscViewer` 2494 @*/ 2495 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2496 { 2497 PetscBool ishdf5; 2498 2499 PetscFunctionBegin; 2500 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2501 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2502 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2503 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2504 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2505 if (ishdf5) { 2506 #if defined(PETSC_HAVE_HDF5) 2507 PetscViewerFormat format; 2508 2509 PetscCall(PetscViewerGetFormat(viewer, &format)); 2510 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2511 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2512 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2513 #else 2514 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2515 #endif 2516 } 2517 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2518 PetscFunctionReturn(PETSC_SUCCESS); 2519 } 2520 2521 /*@ 2522 DMPlexSectionLoad - Loads section into a `DMPLEX` 2523 2524 Collective 2525 2526 Input Parameters: 2527 + dm - The `DM` that represents the topology 2528 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2529 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2530 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2531 2532 Output Parameters: 2533 + 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) 2534 - 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) 2535 2536 Level: advanced 2537 2538 Notes: 2539 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. 2540 2541 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. 2542 2543 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. 2544 2545 Example using 2 processes: 2546 .vb 2547 NX (number of points on dm): 4 2548 sectionA : the on-disk section 2549 vecA : a vector associated with sectionA 2550 sectionB : sectiondm's local section constructed in this function 2551 vecB (local) : a vector associated with sectiondm's local section 2552 vecB (global) : a vector associated with sectiondm's global section 2553 2554 rank 0 rank 1 2555 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2556 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2557 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2558 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2559 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2560 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2561 sectionB->atlasDof : 1 0 1 | 1 3 2562 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2563 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2564 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2565 .ve 2566 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2567 2568 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2569 @*/ 2570 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2571 { 2572 PetscBool ishdf5; 2573 2574 PetscFunctionBegin; 2575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2576 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2577 if (!sectiondm) sectiondm = dm; 2578 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2579 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2580 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2581 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2582 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2583 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2584 if (ishdf5) { 2585 #if defined(PETSC_HAVE_HDF5) 2586 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2587 #else 2588 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2589 #endif 2590 } 2591 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2592 PetscFunctionReturn(PETSC_SUCCESS); 2593 } 2594 2595 /*@ 2596 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2597 2598 Collective 2599 2600 Input Parameters: 2601 + dm - The `DM` that represents the topology 2602 . viewer - The `PetscViewer` that represents the on-disk vector data 2603 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2604 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2605 - vec - The global vector to set values of 2606 2607 Level: advanced 2608 2609 Notes: 2610 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. 2611 2612 Calling sequence: 2613 .vb 2614 DMCreate(PETSC_COMM_WORLD, &dm); 2615 DMSetType(dm, DMPLEX); 2616 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2617 DMPlexTopologyLoad(dm, viewer, &sfX); 2618 DMClone(dm, §iondm); 2619 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2620 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2621 DMGetGlobalVector(sectiondm, &vec); 2622 PetscObjectSetName((PetscObject)vec, "vec_name"); 2623 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2624 DMRestoreGlobalVector(sectiondm, &vec); 2625 PetscSFDestroy(&gsf); 2626 PetscSFDestroy(&sfX); 2627 DMDestroy(§iondm); 2628 DMDestroy(&dm); 2629 .ve 2630 2631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2632 `PetscSF`, `PetscViewer` 2633 @*/ 2634 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2635 { 2636 PetscBool ishdf5; 2637 2638 PetscFunctionBegin; 2639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2640 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2641 if (!sectiondm) sectiondm = dm; 2642 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2643 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2644 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2645 /* Check consistency */ 2646 { 2647 PetscSection section; 2648 PetscBool includesConstraints; 2649 PetscInt m, m1; 2650 2651 PetscCall(VecGetLocalSize(vec, &m1)); 2652 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2653 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2654 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2655 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2656 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2657 } 2658 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2659 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2660 if (ishdf5) { 2661 #if defined(PETSC_HAVE_HDF5) 2662 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2663 #else 2664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2665 #endif 2666 } 2667 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2668 PetscFunctionReturn(PETSC_SUCCESS); 2669 } 2670 2671 /*@ 2672 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2673 2674 Collective 2675 2676 Input Parameters: 2677 + dm - The `DM` that represents the topology 2678 . viewer - The `PetscViewer` that represents the on-disk vector data 2679 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2680 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2681 - vec - The local vector to set values of 2682 2683 Level: advanced 2684 2685 Notes: 2686 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. 2687 2688 Calling sequence: 2689 .vb 2690 DMCreate(PETSC_COMM_WORLD, &dm); 2691 DMSetType(dm, DMPLEX); 2692 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2693 DMPlexTopologyLoad(dm, viewer, &sfX); 2694 DMClone(dm, §iondm); 2695 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2696 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2697 DMGetLocalVector(sectiondm, &vec); 2698 PetscObjectSetName((PetscObject)vec, "vec_name"); 2699 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2700 DMRestoreLocalVector(sectiondm, &vec); 2701 PetscSFDestroy(&lsf); 2702 PetscSFDestroy(&sfX); 2703 DMDestroy(§iondm); 2704 DMDestroy(&dm); 2705 .ve 2706 2707 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2708 `PetscSF`, `PetscViewer` 2709 @*/ 2710 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2711 { 2712 PetscBool ishdf5; 2713 2714 PetscFunctionBegin; 2715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2716 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2717 if (!sectiondm) sectiondm = dm; 2718 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2719 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2720 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2721 /* Check consistency */ 2722 { 2723 PetscSection section; 2724 PetscBool includesConstraints; 2725 PetscInt m, m1; 2726 2727 PetscCall(VecGetLocalSize(vec, &m1)); 2728 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2729 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2730 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2731 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2732 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2733 } 2734 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2735 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2736 if (ishdf5) { 2737 #if defined(PETSC_HAVE_HDF5) 2738 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2739 #else 2740 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2741 #endif 2742 } 2743 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2744 PetscFunctionReturn(PETSC_SUCCESS); 2745 } 2746 2747 PetscErrorCode DMDestroy_Plex(DM dm) 2748 { 2749 DM_Plex *mesh = (DM_Plex *)dm->data; 2750 2751 PetscFunctionBegin; 2752 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2753 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2754 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2755 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2756 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2757 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2758 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2759 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2760 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2761 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2762 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2763 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2764 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2765 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2766 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2767 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2768 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2769 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2770 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2771 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2772 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2773 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2774 PetscCall(PetscFree(mesh->cones)); 2775 PetscCall(PetscFree(mesh->coneOrientations)); 2776 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2777 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2778 PetscCall(PetscFree(mesh->supports)); 2779 PetscCall(PetscFree(mesh->cellTypes)); 2780 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2781 PetscCall(PetscFree(mesh->tetgenOpts)); 2782 PetscCall(PetscFree(mesh->triangleOpts)); 2783 PetscCall(PetscFree(mesh->transformType)); 2784 PetscCall(PetscFree(mesh->distributionName)); 2785 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2786 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2787 PetscCall(ISDestroy(&mesh->subpointIS)); 2788 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2789 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2790 if (mesh->periodic.face_sfs) { 2791 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2792 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2793 } 2794 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2795 if (mesh->periodic.periodic_points) { 2796 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2797 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2798 } 2799 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2800 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2801 PetscCall(ISDestroy(&mesh->anchorIS)); 2802 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2803 PetscCall(PetscFree(mesh->parents)); 2804 PetscCall(PetscFree(mesh->childIDs)); 2805 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2806 PetscCall(PetscFree(mesh->children)); 2807 PetscCall(DMDestroy(&mesh->referenceTree)); 2808 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2809 PetscCall(PetscFree(mesh->neighbors)); 2810 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2811 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2812 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2813 PetscCall(PetscFree(mesh)); 2814 PetscFunctionReturn(PETSC_SUCCESS); 2815 } 2816 2817 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2818 { 2819 PetscSection sectionGlobal, sectionLocal; 2820 PetscInt bs = -1, mbs; 2821 PetscInt localSize, localStart = 0; 2822 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2823 MatType mtype; 2824 ISLocalToGlobalMapping ltog; 2825 2826 PetscFunctionBegin; 2827 PetscCall(MatInitializePackage()); 2828 mtype = dm->mattype; 2829 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2830 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2831 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2832 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2833 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2834 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2835 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2836 PetscCall(MatSetType(*J, mtype)); 2837 PetscCall(MatSetFromOptions(*J)); 2838 PetscCall(MatGetBlockSize(*J, &mbs)); 2839 if (mbs > 1) bs = mbs; 2840 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2841 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2842 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2843 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2844 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2845 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2846 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2847 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2848 if (!isShell) { 2849 // There are three states with pblocks, since block starts can have no dofs: 2850 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2851 // TRUE) Block Start: The first entry in a block has been added 2852 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2853 PetscBT blst; 2854 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2855 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2856 const PetscInt *perm = NULL; 2857 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2858 PetscInt pStart, pEnd, dof, cdof, num_fields; 2859 2860 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2861 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2862 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2863 2864 PetscCall(PetscCalloc1(localSize, &pblocks)); 2865 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2866 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2867 // We need to process in the permuted order to get block sizes right 2868 for (PetscInt point = pStart; point < pEnd; ++point) { 2869 const PetscInt p = perm ? perm[point] : point; 2870 2871 switch (dm->blocking_type) { 2872 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2873 PetscInt bdof, offset; 2874 2875 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2876 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2877 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2878 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2879 if (dof > 0) { 2880 // State change 2881 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2882 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2883 2884 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2885 // Signal block concatenation 2886 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2887 } 2888 dof = dof < 0 ? -(dof + 1) : dof; 2889 bdof = cdof && (dof - cdof) ? 1 : dof; 2890 if (dof) { 2891 if (bs < 0) { 2892 bs = bdof; 2893 } else if (bs != bdof) { 2894 bs = 1; 2895 } 2896 } 2897 } break; 2898 case DM_BLOCKING_FIELD_NODE: { 2899 for (PetscInt field = 0; field < num_fields; field++) { 2900 PetscInt num_comp, bdof, offset; 2901 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2902 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2903 if (dof < 0) continue; 2904 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2905 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2906 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); 2907 PetscInt num_nodes = dof / num_comp; 2908 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2909 // Handle possibly constant block size (unlikely) 2910 bdof = cdof && (dof - cdof) ? 1 : dof; 2911 if (dof) { 2912 if (bs < 0) { 2913 bs = bdof; 2914 } else if (bs != bdof) { 2915 bs = 1; 2916 } 2917 } 2918 } 2919 } break; 2920 } 2921 } 2922 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2923 /* Must have same blocksize on all procs (some might have no points) */ 2924 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2925 bsLocal[1] = bs; 2926 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2927 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2928 else bs = bsMinMax[0]; 2929 bs = PetscMax(1, bs); 2930 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2931 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2932 PetscCall(MatSetBlockSize(*J, bs)); 2933 PetscCall(MatSetUp(*J)); 2934 } else { 2935 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2936 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2937 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2938 } 2939 if (pblocks) { // Consolidate blocks 2940 PetscInt nblocks = 0; 2941 pblocks[0] = PetscAbs(pblocks[0]); 2942 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2943 if (pblocks[i] == 0) continue; 2944 // Negative block size indicates the blocks should be concatenated 2945 if (pblocks[i] < 0) { 2946 pblocks[i] = -pblocks[i]; 2947 pblocks[nblocks - 1] += pblocks[i]; 2948 } else { 2949 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2950 } 2951 for (PetscInt j = 1; j < pblocks[i]; j++) 2952 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); 2953 } 2954 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2955 } 2956 PetscCall(PetscFree(pblocks)); 2957 } 2958 PetscCall(MatSetDM(*J, dm)); 2959 PetscFunctionReturn(PETSC_SUCCESS); 2960 } 2961 2962 /*@ 2963 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2964 2965 Not Collective 2966 2967 Input Parameter: 2968 . dm - The `DMPLEX` 2969 2970 Output Parameter: 2971 . subsection - The subdomain section 2972 2973 Level: developer 2974 2975 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2976 @*/ 2977 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2978 { 2979 DM_Plex *mesh = (DM_Plex *)dm->data; 2980 2981 PetscFunctionBegin; 2982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2983 if (!mesh->subdomainSection) { 2984 PetscSection section; 2985 PetscSF sf; 2986 2987 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2988 PetscCall(DMGetLocalSection(dm, §ion)); 2989 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2990 PetscCall(PetscSFDestroy(&sf)); 2991 } 2992 *subsection = mesh->subdomainSection; 2993 PetscFunctionReturn(PETSC_SUCCESS); 2994 } 2995 2996 /*@ 2997 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2998 2999 Not Collective 3000 3001 Input Parameter: 3002 . dm - The `DMPLEX` 3003 3004 Output Parameters: 3005 + pStart - The first mesh point 3006 - pEnd - The upper bound for mesh points 3007 3008 Level: beginner 3009 3010 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3011 @*/ 3012 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3013 { 3014 DM_Plex *mesh = (DM_Plex *)dm->data; 3015 3016 PetscFunctionBegin; 3017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3018 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3019 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3020 PetscFunctionReturn(PETSC_SUCCESS); 3021 } 3022 3023 /*@ 3024 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3025 3026 Not Collective 3027 3028 Input Parameters: 3029 + dm - The `DMPLEX` 3030 . pStart - The first mesh point 3031 - pEnd - The upper bound for mesh points 3032 3033 Level: beginner 3034 3035 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3036 @*/ 3037 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3038 { 3039 DM_Plex *mesh = (DM_Plex *)dm->data; 3040 3041 PetscFunctionBegin; 3042 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3043 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3044 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3045 PetscCall(PetscFree(mesh->cellTypes)); 3046 PetscFunctionReturn(PETSC_SUCCESS); 3047 } 3048 3049 /*@ 3050 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3051 3052 Not Collective 3053 3054 Input Parameters: 3055 + dm - The `DMPLEX` 3056 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3057 3058 Output Parameter: 3059 . size - The cone size for point `p` 3060 3061 Level: beginner 3062 3063 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3064 @*/ 3065 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3066 { 3067 DM_Plex *mesh = (DM_Plex *)dm->data; 3068 3069 PetscFunctionBegin; 3070 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3071 PetscAssertPointer(size, 3); 3072 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3073 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3074 PetscFunctionReturn(PETSC_SUCCESS); 3075 } 3076 3077 /*@ 3078 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3079 3080 Not Collective 3081 3082 Input Parameters: 3083 + dm - The `DMPLEX` 3084 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3085 - size - The cone size for point `p` 3086 3087 Level: beginner 3088 3089 Note: 3090 This should be called after `DMPlexSetChart()`. 3091 3092 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3093 @*/ 3094 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3095 { 3096 DM_Plex *mesh = (DM_Plex *)dm->data; 3097 3098 PetscFunctionBegin; 3099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3100 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3101 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3102 PetscFunctionReturn(PETSC_SUCCESS); 3103 } 3104 3105 /*@C 3106 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3107 3108 Not Collective 3109 3110 Input Parameters: 3111 + dm - The `DMPLEX` 3112 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3113 3114 Output Parameter: 3115 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3116 3117 Level: beginner 3118 3119 Fortran Notes: 3120 `cone` must be declared with 3121 .vb 3122 PetscInt, pointer :: cone(:) 3123 .ve 3124 3125 You must also call `DMPlexRestoreCone()` after you finish using the array. 3126 `DMPlexRestoreCone()` is not needed/available in C. 3127 3128 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3129 @*/ 3130 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3131 { 3132 DM_Plex *mesh = (DM_Plex *)dm->data; 3133 PetscInt off; 3134 3135 PetscFunctionBegin; 3136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3137 PetscAssertPointer(cone, 3); 3138 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3139 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3140 PetscFunctionReturn(PETSC_SUCCESS); 3141 } 3142 3143 /*@ 3144 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3145 3146 Not Collective 3147 3148 Input Parameters: 3149 + dm - The `DMPLEX` 3150 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3151 3152 Output Parameters: 3153 + pConesSection - `PetscSection` describing the layout of `pCones` 3154 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3155 3156 Level: intermediate 3157 3158 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3159 @*/ 3160 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3161 { 3162 PetscSection cs, newcs; 3163 PetscInt *cones; 3164 PetscInt *newarr = NULL; 3165 PetscInt n; 3166 3167 PetscFunctionBegin; 3168 PetscCall(DMPlexGetCones(dm, &cones)); 3169 PetscCall(DMPlexGetConeSection(dm, &cs)); 3170 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3171 if (pConesSection) *pConesSection = newcs; 3172 if (pCones) { 3173 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3174 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3175 } 3176 PetscFunctionReturn(PETSC_SUCCESS); 3177 } 3178 3179 /*@ 3180 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3181 3182 Not Collective 3183 3184 Input Parameters: 3185 + dm - The `DMPLEX` 3186 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3187 3188 Output Parameter: 3189 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3190 3191 Level: advanced 3192 3193 Notes: 3194 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3195 3196 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3197 3198 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3199 `DMPlexGetDepth()`, `IS` 3200 @*/ 3201 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3202 { 3203 IS *expandedPointsAll; 3204 PetscInt depth; 3205 3206 PetscFunctionBegin; 3207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3208 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3209 PetscAssertPointer(expandedPoints, 3); 3210 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3211 *expandedPoints = expandedPointsAll[0]; 3212 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3213 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3214 PetscFunctionReturn(PETSC_SUCCESS); 3215 } 3216 3217 /*@ 3218 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3219 (DAG points of depth 0, i.e., without cones). 3220 3221 Not Collective 3222 3223 Input Parameters: 3224 + dm - The `DMPLEX` 3225 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3226 3227 Output Parameters: 3228 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3229 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3230 - sections - (optional) An array of sections which describe mappings from points to their cone points 3231 3232 Level: advanced 3233 3234 Notes: 3235 Like `DMPlexGetConeTuple()` but recursive. 3236 3237 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. 3238 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3239 3240 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\: 3241 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3242 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3243 3244 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3245 `DMPlexGetDepth()`, `PetscSection`, `IS` 3246 @*/ 3247 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3248 { 3249 const PetscInt *arr0 = NULL, *cone = NULL; 3250 PetscInt *arr = NULL, *newarr = NULL; 3251 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3252 IS *expandedPoints_; 3253 PetscSection *sections_; 3254 3255 PetscFunctionBegin; 3256 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3257 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3258 if (depth) PetscAssertPointer(depth, 3); 3259 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3260 if (sections) PetscAssertPointer(sections, 5); 3261 PetscCall(ISGetLocalSize(points, &n)); 3262 PetscCall(ISGetIndices(points, &arr0)); 3263 PetscCall(DMPlexGetDepth(dm, &depth_)); 3264 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3265 PetscCall(PetscCalloc1(depth_, §ions_)); 3266 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3267 for (d = depth_ - 1; d >= 0; d--) { 3268 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3269 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3270 for (i = 0; i < n; i++) { 3271 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3272 if (arr[i] >= start && arr[i] < end) { 3273 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3274 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3275 } else { 3276 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3277 } 3278 } 3279 PetscCall(PetscSectionSetUp(sections_[d])); 3280 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3281 PetscCall(PetscMalloc1(newn, &newarr)); 3282 for (i = 0; i < n; i++) { 3283 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3284 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3285 if (cn > 1) { 3286 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3287 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3288 } else { 3289 newarr[co] = arr[i]; 3290 } 3291 } 3292 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3293 arr = newarr; 3294 n = newn; 3295 } 3296 PetscCall(ISRestoreIndices(points, &arr0)); 3297 *depth = depth_; 3298 if (expandedPoints) *expandedPoints = expandedPoints_; 3299 else { 3300 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3301 PetscCall(PetscFree(expandedPoints_)); 3302 } 3303 if (sections) *sections = sections_; 3304 else { 3305 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3306 PetscCall(PetscFree(sections_)); 3307 } 3308 PetscFunctionReturn(PETSC_SUCCESS); 3309 } 3310 3311 /*@ 3312 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3313 3314 Not Collective 3315 3316 Input Parameters: 3317 + dm - The `DMPLEX` 3318 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3319 3320 Output Parameters: 3321 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3322 . expandedPoints - (optional) An array of recursively expanded cones 3323 - sections - (optional) An array of sections which describe mappings from points to their cone points 3324 3325 Level: advanced 3326 3327 Note: 3328 See `DMPlexGetConeRecursive()` 3329 3330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3331 `DMPlexGetDepth()`, `IS`, `PetscSection` 3332 @*/ 3333 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3334 { 3335 PetscInt d, depth_; 3336 3337 PetscFunctionBegin; 3338 PetscCall(DMPlexGetDepth(dm, &depth_)); 3339 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3340 if (depth) *depth = 0; 3341 if (expandedPoints) { 3342 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3343 PetscCall(PetscFree(*expandedPoints)); 3344 } 3345 if (sections) { 3346 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3347 PetscCall(PetscFree(*sections)); 3348 } 3349 PetscFunctionReturn(PETSC_SUCCESS); 3350 } 3351 3352 /*@ 3353 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 3354 3355 Not Collective 3356 3357 Input Parameters: 3358 + dm - The `DMPLEX` 3359 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3360 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3361 3362 Level: beginner 3363 3364 Note: 3365 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3366 3367 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3368 @*/ 3369 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3370 { 3371 DM_Plex *mesh = (DM_Plex *)dm->data; 3372 PetscInt dof, off, c; 3373 3374 PetscFunctionBegin; 3375 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3376 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3377 if (dof) PetscAssertPointer(cone, 3); 3378 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3379 if (PetscDefined(USE_DEBUG)) { 3380 PetscInt pStart, pEnd; 3381 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3382 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); 3383 for (c = 0; c < dof; ++c) { 3384 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); 3385 mesh->cones[off + c] = cone[c]; 3386 } 3387 } else { 3388 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3389 } 3390 PetscFunctionReturn(PETSC_SUCCESS); 3391 } 3392 3393 /*@C 3394 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3395 3396 Not Collective 3397 3398 Input Parameters: 3399 + dm - The `DMPLEX` 3400 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3401 3402 Output Parameter: 3403 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3404 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3405 3406 Level: beginner 3407 3408 Note: 3409 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3410 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3411 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3412 with the identity. 3413 3414 Fortran Notes: 3415 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3416 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3417 3418 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3419 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3420 @*/ 3421 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3422 { 3423 DM_Plex *mesh = (DM_Plex *)dm->data; 3424 PetscInt off; 3425 3426 PetscFunctionBegin; 3427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3428 if (PetscDefined(USE_DEBUG)) { 3429 PetscInt dof; 3430 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3431 if (dof) PetscAssertPointer(coneOrientation, 3); 3432 } 3433 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3434 3435 *coneOrientation = &mesh->coneOrientations[off]; 3436 PetscFunctionReturn(PETSC_SUCCESS); 3437 } 3438 3439 /*@ 3440 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3441 3442 Not Collective 3443 3444 Input Parameters: 3445 + dm - The `DMPLEX` 3446 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3447 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3448 3449 Level: beginner 3450 3451 Notes: 3452 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3453 3454 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3455 3456 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3457 @*/ 3458 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3459 { 3460 DM_Plex *mesh = (DM_Plex *)dm->data; 3461 PetscInt pStart, pEnd; 3462 PetscInt dof, off, c; 3463 3464 PetscFunctionBegin; 3465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3466 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3467 if (dof) PetscAssertPointer(coneOrientation, 3); 3468 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3469 if (PetscDefined(USE_DEBUG)) { 3470 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3471 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); 3472 for (c = 0; c < dof; ++c) { 3473 PetscInt cdof, o = coneOrientation[c]; 3474 3475 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3476 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); 3477 mesh->coneOrientations[off + c] = o; 3478 } 3479 } else { 3480 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3481 } 3482 PetscFunctionReturn(PETSC_SUCCESS); 3483 } 3484 3485 /*@ 3486 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3487 3488 Not Collective 3489 3490 Input Parameters: 3491 + dm - The `DMPLEX` 3492 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3493 . conePos - The local index in the cone where the point should be put 3494 - conePoint - The mesh point to insert 3495 3496 Level: beginner 3497 3498 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3499 @*/ 3500 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3501 { 3502 DM_Plex *mesh = (DM_Plex *)dm->data; 3503 PetscInt pStart, pEnd; 3504 PetscInt dof, off; 3505 3506 PetscFunctionBegin; 3507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3508 if (PetscDefined(USE_DEBUG)) { 3509 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3510 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); 3511 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); 3512 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3513 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); 3514 } 3515 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3516 mesh->cones[off + conePos] = conePoint; 3517 PetscFunctionReturn(PETSC_SUCCESS); 3518 } 3519 3520 /*@ 3521 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3522 3523 Not Collective 3524 3525 Input Parameters: 3526 + dm - The `DMPLEX` 3527 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3528 . conePos - The local index in the cone where the point should be put 3529 - coneOrientation - The point orientation to insert 3530 3531 Level: beginner 3532 3533 Note: 3534 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3535 3536 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3537 @*/ 3538 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3539 { 3540 DM_Plex *mesh = (DM_Plex *)dm->data; 3541 PetscInt pStart, pEnd; 3542 PetscInt dof, off; 3543 3544 PetscFunctionBegin; 3545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3546 if (PetscDefined(USE_DEBUG)) { 3547 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3548 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); 3549 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3550 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); 3551 } 3552 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3553 mesh->coneOrientations[off + conePos] = coneOrientation; 3554 PetscFunctionReturn(PETSC_SUCCESS); 3555 } 3556 3557 /*@C 3558 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3559 3560 Not collective 3561 3562 Input Parameters: 3563 + dm - The DMPlex 3564 - p - The point, which must lie in the chart set with DMPlexSetChart() 3565 3566 Output Parameters: 3567 + cone - An array of points which are on the in-edges for point `p` 3568 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3569 integer giving the prescription for cone traversal. 3570 3571 Level: beginner 3572 3573 Notes: 3574 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3575 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3576 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3577 with the identity. 3578 3579 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3580 3581 Fortran Notes: 3582 `cone` and `ornt` must be declared with 3583 .vb 3584 PetscInt, pointer :: cone(:) 3585 PetscInt, pointer :: ornt(:) 3586 .ve 3587 3588 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3589 @*/ 3590 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3591 { 3592 DM_Plex *mesh = (DM_Plex *)dm->data; 3593 3594 PetscFunctionBegin; 3595 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3596 if (mesh->tr) { 3597 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3598 } else { 3599 PetscInt off; 3600 if (PetscDefined(USE_DEBUG)) { 3601 PetscInt dof; 3602 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3603 if (dof) { 3604 if (cone) PetscAssertPointer(cone, 3); 3605 if (ornt) PetscAssertPointer(ornt, 4); 3606 } 3607 } 3608 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3609 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3610 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3611 } 3612 PetscFunctionReturn(PETSC_SUCCESS); 3613 } 3614 3615 /*@C 3616 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3617 3618 Not Collective 3619 3620 Input Parameters: 3621 + dm - The DMPlex 3622 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3623 . cone - An array of points which are on the in-edges for point p 3624 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3625 integer giving the prescription for cone traversal. 3626 3627 Level: beginner 3628 3629 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3630 @*/ 3631 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3632 { 3633 DM_Plex *mesh = (DM_Plex *)dm->data; 3634 3635 PetscFunctionBegin; 3636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3637 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3638 PetscFunctionReturn(PETSC_SUCCESS); 3639 } 3640 3641 /*@ 3642 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3643 3644 Not Collective 3645 3646 Input Parameters: 3647 + dm - The `DMPLEX` 3648 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3649 3650 Output Parameter: 3651 . size - The support size for point `p` 3652 3653 Level: beginner 3654 3655 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3656 @*/ 3657 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3658 { 3659 DM_Plex *mesh = (DM_Plex *)dm->data; 3660 3661 PetscFunctionBegin; 3662 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3663 PetscAssertPointer(size, 3); 3664 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3665 PetscFunctionReturn(PETSC_SUCCESS); 3666 } 3667 3668 /*@ 3669 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3670 3671 Not Collective 3672 3673 Input Parameters: 3674 + dm - The `DMPLEX` 3675 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3676 - size - The support size for point `p` 3677 3678 Level: beginner 3679 3680 Note: 3681 This should be called after `DMPlexSetChart()`. 3682 3683 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3684 @*/ 3685 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3686 { 3687 DM_Plex *mesh = (DM_Plex *)dm->data; 3688 3689 PetscFunctionBegin; 3690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3691 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3692 PetscFunctionReturn(PETSC_SUCCESS); 3693 } 3694 3695 /*@C 3696 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3697 3698 Not Collective 3699 3700 Input Parameters: 3701 + dm - The `DMPLEX` 3702 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3703 3704 Output Parameter: 3705 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3706 3707 Level: beginner 3708 3709 Fortran Notes: 3710 `support` must be declared with 3711 .vb 3712 PetscInt, pointer :: support(:) 3713 .ve 3714 3715 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3716 `DMPlexRestoreSupport()` is not needed/available in C. 3717 3718 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3719 @*/ 3720 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3721 { 3722 DM_Plex *mesh = (DM_Plex *)dm->data; 3723 PetscInt off; 3724 3725 PetscFunctionBegin; 3726 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3727 PetscAssertPointer(support, 3); 3728 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3729 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3730 PetscFunctionReturn(PETSC_SUCCESS); 3731 } 3732 3733 /*@ 3734 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3735 3736 Not Collective 3737 3738 Input Parameters: 3739 + dm - The `DMPLEX` 3740 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3741 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3742 3743 Level: beginner 3744 3745 Note: 3746 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3747 3748 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3749 @*/ 3750 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3751 { 3752 DM_Plex *mesh = (DM_Plex *)dm->data; 3753 PetscInt pStart, pEnd; 3754 PetscInt dof, off, c; 3755 3756 PetscFunctionBegin; 3757 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3758 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3759 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3760 if (dof) PetscAssertPointer(support, 3); 3761 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3762 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); 3763 for (c = 0; c < dof; ++c) { 3764 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); 3765 mesh->supports[off + c] = support[c]; 3766 } 3767 PetscFunctionReturn(PETSC_SUCCESS); 3768 } 3769 3770 /*@ 3771 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3772 3773 Not Collective 3774 3775 Input Parameters: 3776 + dm - The `DMPLEX` 3777 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3778 . supportPos - The local index in the cone where the point should be put 3779 - supportPoint - The mesh point to insert 3780 3781 Level: beginner 3782 3783 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3784 @*/ 3785 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3786 { 3787 DM_Plex *mesh = (DM_Plex *)dm->data; 3788 PetscInt pStart, pEnd; 3789 PetscInt dof, off; 3790 3791 PetscFunctionBegin; 3792 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3793 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3794 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3795 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3796 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); 3797 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); 3798 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); 3799 mesh->supports[off + supportPos] = supportPoint; 3800 PetscFunctionReturn(PETSC_SUCCESS); 3801 } 3802 3803 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3804 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3805 { 3806 switch (ct) { 3807 case DM_POLYTOPE_SEGMENT: 3808 if (o == -1) return -2; 3809 break; 3810 case DM_POLYTOPE_TRIANGLE: 3811 if (o == -3) return -1; 3812 if (o == -2) return -3; 3813 if (o == -1) return -2; 3814 break; 3815 case DM_POLYTOPE_QUADRILATERAL: 3816 if (o == -4) return -2; 3817 if (o == -3) return -1; 3818 if (o == -2) return -4; 3819 if (o == -1) return -3; 3820 break; 3821 default: 3822 return o; 3823 } 3824 return o; 3825 } 3826 3827 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3828 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3829 { 3830 switch (ct) { 3831 case DM_POLYTOPE_SEGMENT: 3832 if ((o == -2) || (o == 1)) return -1; 3833 if (o == -1) return 0; 3834 break; 3835 case DM_POLYTOPE_TRIANGLE: 3836 if (o == -3) return -2; 3837 if (o == -2) return -1; 3838 if (o == -1) return -3; 3839 break; 3840 case DM_POLYTOPE_QUADRILATERAL: 3841 if (o == -4) return -2; 3842 if (o == -3) return -1; 3843 if (o == -2) return -4; 3844 if (o == -1) return -3; 3845 break; 3846 default: 3847 return o; 3848 } 3849 return o; 3850 } 3851 3852 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3853 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3854 { 3855 PetscInt pStart, pEnd, p; 3856 3857 PetscFunctionBegin; 3858 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3859 for (p = pStart; p < pEnd; ++p) { 3860 const PetscInt *cone, *ornt; 3861 PetscInt coneSize, c; 3862 3863 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3864 PetscCall(DMPlexGetCone(dm, p, &cone)); 3865 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3866 for (c = 0; c < coneSize; ++c) { 3867 DMPolytopeType ct; 3868 const PetscInt o = ornt[c]; 3869 3870 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3871 switch (ct) { 3872 case DM_POLYTOPE_SEGMENT: 3873 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3874 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3875 break; 3876 case DM_POLYTOPE_TRIANGLE: 3877 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3878 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3879 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3880 break; 3881 case DM_POLYTOPE_QUADRILATERAL: 3882 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3883 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3884 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3885 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3886 break; 3887 default: 3888 break; 3889 } 3890 } 3891 } 3892 PetscFunctionReturn(PETSC_SUCCESS); 3893 } 3894 3895 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3896 { 3897 DM_Plex *mesh = (DM_Plex *)dm->data; 3898 3899 PetscFunctionBeginHot; 3900 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3901 if (useCone) { 3902 PetscCall(DMPlexGetConeSize(dm, p, size)); 3903 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3904 } else { 3905 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3906 PetscCall(DMPlexGetSupport(dm, p, arr)); 3907 } 3908 } else { 3909 if (useCone) { 3910 const PetscSection s = mesh->coneSection; 3911 const PetscInt ps = p - s->pStart; 3912 const PetscInt off = s->atlasOff[ps]; 3913 3914 *size = s->atlasDof[ps]; 3915 *arr = mesh->cones + off; 3916 *ornt = mesh->coneOrientations + off; 3917 } else { 3918 const PetscSection s = mesh->supportSection; 3919 const PetscInt ps = p - s->pStart; 3920 const PetscInt off = s->atlasOff[ps]; 3921 3922 *size = s->atlasDof[ps]; 3923 *arr = mesh->supports + off; 3924 } 3925 } 3926 PetscFunctionReturn(PETSC_SUCCESS); 3927 } 3928 3929 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3930 { 3931 DM_Plex *mesh = (DM_Plex *)dm->data; 3932 3933 PetscFunctionBeginHot; 3934 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3935 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3936 } 3937 PetscFunctionReturn(PETSC_SUCCESS); 3938 } 3939 3940 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3941 { 3942 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3943 PetscInt *closure; 3944 const PetscInt *tmp = NULL, *tmpO = NULL; 3945 PetscInt off = 0, tmpSize, t; 3946 3947 PetscFunctionBeginHot; 3948 if (ornt) { 3949 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3950 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; 3951 } 3952 if (*points) { 3953 closure = *points; 3954 } else { 3955 PetscInt maxConeSize, maxSupportSize; 3956 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3957 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3958 } 3959 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3960 if (ct == DM_POLYTOPE_UNKNOWN) { 3961 closure[off++] = p; 3962 closure[off++] = 0; 3963 for (t = 0; t < tmpSize; ++t) { 3964 closure[off++] = tmp[t]; 3965 closure[off++] = tmpO ? tmpO[t] : 0; 3966 } 3967 } else { 3968 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3969 3970 /* We assume that cells with a valid type have faces with a valid type */ 3971 closure[off++] = p; 3972 closure[off++] = ornt; 3973 for (t = 0; t < tmpSize; ++t) { 3974 DMPolytopeType ft; 3975 3976 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3977 closure[off++] = tmp[arr[t]]; 3978 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3979 } 3980 } 3981 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3982 if (numPoints) *numPoints = tmpSize + 1; 3983 if (points) *points = closure; 3984 PetscFunctionReturn(PETSC_SUCCESS); 3985 } 3986 3987 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3988 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3989 { 3990 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3991 const PetscInt *cone, *ornt; 3992 PetscInt *pts, *closure = NULL; 3993 DMPolytopeType ft; 3994 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3995 PetscInt dim, coneSize, c, d, clSize, cl; 3996 3997 PetscFunctionBeginHot; 3998 PetscCall(DMGetDimension(dm, &dim)); 3999 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4000 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4001 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4002 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4003 maxSize = PetscMax(coneSeries, supportSeries); 4004 if (*points) { 4005 pts = *points; 4006 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4007 c = 0; 4008 pts[c++] = point; 4009 pts[c++] = o; 4010 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4011 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4012 for (cl = 0; cl < clSize * 2; cl += 2) { 4013 pts[c++] = closure[cl]; 4014 pts[c++] = closure[cl + 1]; 4015 } 4016 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4017 for (cl = 0; cl < clSize * 2; cl += 2) { 4018 pts[c++] = closure[cl]; 4019 pts[c++] = closure[cl + 1]; 4020 } 4021 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4022 for (d = 2; d < coneSize; ++d) { 4023 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4024 pts[c++] = cone[arr[d * 2 + 0]]; 4025 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4026 } 4027 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4028 if (dim >= 3) { 4029 for (d = 2; d < coneSize; ++d) { 4030 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4031 const PetscInt *fcone, *fornt; 4032 PetscInt fconeSize, fc, i; 4033 4034 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4035 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4036 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4037 for (fc = 0; fc < fconeSize; ++fc) { 4038 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4039 const PetscInt co = farr[fc * 2 + 1]; 4040 4041 for (i = 0; i < c; i += 2) 4042 if (pts[i] == cp) break; 4043 if (i == c) { 4044 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4045 pts[c++] = cp; 4046 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4047 } 4048 } 4049 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4050 } 4051 } 4052 *numPoints = c / 2; 4053 *points = pts; 4054 PetscFunctionReturn(PETSC_SUCCESS); 4055 } 4056 4057 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4058 { 4059 DMPolytopeType ct; 4060 PetscInt *closure, *fifo; 4061 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4062 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4063 PetscInt depth, maxSize; 4064 4065 PetscFunctionBeginHot; 4066 PetscCall(DMPlexGetDepth(dm, &depth)); 4067 if (depth == 1) { 4068 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4069 PetscFunctionReturn(PETSC_SUCCESS); 4070 } 4071 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4072 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; 4073 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4074 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4075 PetscFunctionReturn(PETSC_SUCCESS); 4076 } 4077 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4078 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4079 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4080 maxSize = PetscMax(coneSeries, supportSeries); 4081 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4082 if (*points) { 4083 closure = *points; 4084 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4085 closure[closureSize++] = p; 4086 closure[closureSize++] = ornt; 4087 fifo[fifoSize++] = p; 4088 fifo[fifoSize++] = ornt; 4089 fifo[fifoSize++] = ct; 4090 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4091 while (fifoSize - fifoStart) { 4092 const PetscInt q = fifo[fifoStart++]; 4093 const PetscInt o = fifo[fifoStart++]; 4094 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4095 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4096 const PetscInt *tmp, *tmpO = NULL; 4097 PetscInt tmpSize, t; 4098 4099 if (PetscDefined(USE_DEBUG)) { 4100 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4101 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); 4102 } 4103 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4104 for (t = 0; t < tmpSize; ++t) { 4105 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4106 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4107 const PetscInt cp = tmp[ip]; 4108 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4109 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4110 PetscInt c; 4111 4112 /* Check for duplicate */ 4113 for (c = 0; c < closureSize; c += 2) { 4114 if (closure[c] == cp) break; 4115 } 4116 if (c == closureSize) { 4117 closure[closureSize++] = cp; 4118 closure[closureSize++] = co; 4119 fifo[fifoSize++] = cp; 4120 fifo[fifoSize++] = co; 4121 fifo[fifoSize++] = ct; 4122 } 4123 } 4124 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4125 } 4126 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4127 if (numPoints) *numPoints = closureSize / 2; 4128 if (points) *points = closure; 4129 PetscFunctionReturn(PETSC_SUCCESS); 4130 } 4131 4132 /*@C 4133 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4134 4135 Not Collective 4136 4137 Input Parameters: 4138 + dm - The `DMPLEX` 4139 . p - The mesh point 4140 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4141 4142 Input/Output Parameter: 4143 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4144 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4145 otherwise the provided array is used to hold the values 4146 4147 Output Parameter: 4148 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4149 4150 Level: beginner 4151 4152 Note: 4153 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4154 4155 Fortran Notes: 4156 `points` must be declared with 4157 .vb 4158 PetscInt, pointer :: points(:) 4159 .ve 4160 and is always allocated by the function. 4161 4162 The `numPoints` argument is not present in the Fortran binding. 4163 4164 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4165 @*/ 4166 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4167 { 4168 PetscFunctionBeginHot; 4169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4170 if (numPoints) PetscAssertPointer(numPoints, 4); 4171 if (points) PetscAssertPointer(points, 5); 4172 if (PetscDefined(USE_DEBUG)) { 4173 PetscInt pStart, pEnd; 4174 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4175 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); 4176 } 4177 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4178 PetscFunctionReturn(PETSC_SUCCESS); 4179 } 4180 4181 /*@C 4182 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4183 4184 Not Collective 4185 4186 Input Parameters: 4187 + dm - The `DMPLEX` 4188 . p - The mesh point 4189 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4190 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4191 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4192 4193 Level: beginner 4194 4195 Note: 4196 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4197 4198 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4199 @*/ 4200 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4201 { 4202 PetscFunctionBeginHot; 4203 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4204 if (numPoints) *numPoints = 0; 4205 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4206 PetscFunctionReturn(PETSC_SUCCESS); 4207 } 4208 4209 /*@ 4210 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4211 4212 Not Collective 4213 4214 Input Parameter: 4215 . dm - The `DMPLEX` 4216 4217 Output Parameters: 4218 + maxConeSize - The maximum number of in-edges 4219 - maxSupportSize - The maximum number of out-edges 4220 4221 Level: beginner 4222 4223 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4224 @*/ 4225 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4226 { 4227 DM_Plex *mesh = (DM_Plex *)dm->data; 4228 4229 PetscFunctionBegin; 4230 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4231 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4232 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4233 PetscFunctionReturn(PETSC_SUCCESS); 4234 } 4235 4236 PetscErrorCode DMSetUp_Plex(DM dm) 4237 { 4238 DM_Plex *mesh = (DM_Plex *)dm->data; 4239 PetscInt size, maxSupportSize; 4240 4241 PetscFunctionBegin; 4242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4243 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4244 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4245 PetscCall(PetscMalloc1(size, &mesh->cones)); 4246 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4247 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4248 if (maxSupportSize) { 4249 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4250 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4251 PetscCall(PetscMalloc1(size, &mesh->supports)); 4252 } 4253 PetscFunctionReturn(PETSC_SUCCESS); 4254 } 4255 4256 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4257 { 4258 PetscFunctionBegin; 4259 if (subdm) PetscCall(DMClone(dm, subdm)); 4260 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4261 if (subdm) (*subdm)->useNatural = dm->useNatural; 4262 if (dm->useNatural && dm->sfMigration) { 4263 PetscSF sfNatural; 4264 4265 (*subdm)->sfMigration = dm->sfMigration; 4266 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4267 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4268 (*subdm)->sfNatural = sfNatural; 4269 } 4270 PetscFunctionReturn(PETSC_SUCCESS); 4271 } 4272 4273 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4274 { 4275 PetscInt i = 0; 4276 4277 PetscFunctionBegin; 4278 PetscCall(DMClone(dms[0], superdm)); 4279 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4280 (*superdm)->useNatural = PETSC_FALSE; 4281 for (i = 0; i < len; i++) { 4282 if (dms[i]->useNatural && dms[i]->sfMigration) { 4283 PetscSF sfNatural; 4284 4285 (*superdm)->sfMigration = dms[i]->sfMigration; 4286 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4287 (*superdm)->useNatural = PETSC_TRUE; 4288 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4289 (*superdm)->sfNatural = sfNatural; 4290 break; 4291 } 4292 } 4293 PetscFunctionReturn(PETSC_SUCCESS); 4294 } 4295 4296 /*@ 4297 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4298 4299 Not Collective 4300 4301 Input Parameter: 4302 . dm - The `DMPLEX` 4303 4304 Level: beginner 4305 4306 Note: 4307 This should be called after all calls to `DMPlexSetCone()` 4308 4309 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4310 @*/ 4311 PetscErrorCode DMPlexSymmetrize(DM dm) 4312 { 4313 DM_Plex *mesh = (DM_Plex *)dm->data; 4314 PetscInt *offsets; 4315 PetscInt supportSize; 4316 PetscInt pStart, pEnd, p; 4317 4318 PetscFunctionBegin; 4319 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4320 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4321 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4322 /* Calculate support sizes */ 4323 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4324 for (p = pStart; p < pEnd; ++p) { 4325 PetscInt dof, off, c; 4326 4327 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4328 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4329 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4330 } 4331 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4332 /* Calculate supports */ 4333 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4334 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4335 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4336 for (p = pStart; p < pEnd; ++p) { 4337 PetscInt dof, off, c; 4338 4339 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4340 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4341 for (c = off; c < off + dof; ++c) { 4342 const PetscInt q = mesh->cones[c]; 4343 PetscInt offS; 4344 4345 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4346 4347 mesh->supports[offS + offsets[q]] = p; 4348 ++offsets[q]; 4349 } 4350 } 4351 PetscCall(PetscFree(offsets)); 4352 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4353 PetscFunctionReturn(PETSC_SUCCESS); 4354 } 4355 4356 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4357 { 4358 IS stratumIS; 4359 4360 PetscFunctionBegin; 4361 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4362 if (PetscDefined(USE_DEBUG)) { 4363 PetscInt qStart, qEnd, numLevels, level; 4364 PetscBool overlap = PETSC_FALSE; 4365 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4366 for (level = 0; level < numLevels; level++) { 4367 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4368 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4369 overlap = PETSC_TRUE; 4370 break; 4371 } 4372 } 4373 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); 4374 } 4375 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4376 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4377 PetscCall(ISDestroy(&stratumIS)); 4378 PetscFunctionReturn(PETSC_SUCCESS); 4379 } 4380 4381 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4382 { 4383 PetscInt *pMin, *pMax; 4384 PetscInt pStart, pEnd; 4385 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4386 4387 PetscFunctionBegin; 4388 { 4389 DMLabel label2; 4390 4391 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4392 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4393 } 4394 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4395 for (PetscInt p = pStart; p < pEnd; ++p) { 4396 DMPolytopeType ct; 4397 4398 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4399 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4400 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4401 } 4402 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4403 for (PetscInt d = dmin; d <= dmax; ++d) { 4404 pMin[d] = PETSC_INT_MAX; 4405 pMax[d] = PETSC_INT_MIN; 4406 } 4407 for (PetscInt p = pStart; p < pEnd; ++p) { 4408 DMPolytopeType ct; 4409 PetscInt d; 4410 4411 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4412 d = DMPolytopeTypeGetDim(ct); 4413 pMin[d] = PetscMin(p, pMin[d]); 4414 pMax[d] = PetscMax(p, pMax[d]); 4415 } 4416 for (PetscInt d = dmin; d <= dmax; ++d) { 4417 if (pMin[d] > pMax[d]) continue; 4418 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4419 } 4420 PetscCall(PetscFree2(pMin, pMax)); 4421 PetscFunctionReturn(PETSC_SUCCESS); 4422 } 4423 4424 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4425 { 4426 PetscInt pStart, pEnd; 4427 PetscInt numRoots = 0, numLeaves = 0; 4428 4429 PetscFunctionBegin; 4430 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4431 { 4432 /* Initialize roots and count leaves */ 4433 PetscInt sMin = PETSC_INT_MAX; 4434 PetscInt sMax = PETSC_INT_MIN; 4435 PetscInt coneSize, supportSize; 4436 4437 for (PetscInt p = pStart; p < pEnd; ++p) { 4438 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4439 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4440 if (!coneSize && supportSize) { 4441 sMin = PetscMin(p, sMin); 4442 sMax = PetscMax(p, sMax); 4443 ++numRoots; 4444 } else if (!supportSize && coneSize) { 4445 ++numLeaves; 4446 } else if (!supportSize && !coneSize) { 4447 /* Isolated points */ 4448 sMin = PetscMin(p, sMin); 4449 sMax = PetscMax(p, sMax); 4450 } 4451 } 4452 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4453 } 4454 4455 if (numRoots + numLeaves == (pEnd - pStart)) { 4456 PetscInt sMin = PETSC_INT_MAX; 4457 PetscInt sMax = PETSC_INT_MIN; 4458 PetscInt coneSize, supportSize; 4459 4460 for (PetscInt p = pStart; p < pEnd; ++p) { 4461 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4462 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4463 if (!supportSize && coneSize) { 4464 sMin = PetscMin(p, sMin); 4465 sMax = PetscMax(p, sMax); 4466 } 4467 } 4468 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4469 } else { 4470 PetscInt level = 0; 4471 PetscInt qStart, qEnd; 4472 4473 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4474 while (qEnd > qStart) { 4475 PetscInt sMin = PETSC_INT_MAX; 4476 PetscInt sMax = PETSC_INT_MIN; 4477 4478 for (PetscInt q = qStart; q < qEnd; ++q) { 4479 const PetscInt *support; 4480 PetscInt supportSize; 4481 4482 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4483 PetscCall(DMPlexGetSupport(dm, q, &support)); 4484 for (PetscInt s = 0; s < supportSize; ++s) { 4485 sMin = PetscMin(support[s], sMin); 4486 sMax = PetscMax(support[s], sMax); 4487 } 4488 } 4489 PetscCall(DMLabelGetNumValues(label, &level)); 4490 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4491 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4492 } 4493 } 4494 PetscFunctionReturn(PETSC_SUCCESS); 4495 } 4496 4497 /*@ 4498 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4499 4500 Collective 4501 4502 Input Parameter: 4503 . dm - The `DMPLEX` 4504 4505 Level: beginner 4506 4507 Notes: 4508 The strata group all points of the same grade, and this function calculates the strata. This 4509 grade can be seen as the height (or depth) of the point in the DAG. 4510 4511 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4512 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4513 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4514 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4515 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4516 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4517 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4518 4519 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4520 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4521 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 4522 to interpolate only that one (e0), so that 4523 .vb 4524 cone(c0) = {e0, v2} 4525 cone(e0) = {v0, v1} 4526 .ve 4527 If `DMPlexStratify()` is run on this mesh, it will give depths 4528 .vb 4529 depth 0 = {v0, v1, v2} 4530 depth 1 = {e0, c0} 4531 .ve 4532 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4533 4534 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4535 4536 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4537 @*/ 4538 PetscErrorCode DMPlexStratify(DM dm) 4539 { 4540 DM_Plex *mesh = (DM_Plex *)dm->data; 4541 DMLabel label; 4542 PetscBool flg = PETSC_FALSE; 4543 4544 PetscFunctionBegin; 4545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4546 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4547 4548 // Create depth label 4549 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4550 PetscCall(DMCreateLabel(dm, "depth")); 4551 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4552 4553 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4554 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4555 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4556 4557 { /* just in case there is an empty process */ 4558 PetscInt numValues, maxValues = 0, v; 4559 4560 PetscCall(DMLabelGetNumValues(label, &numValues)); 4561 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4562 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4563 } 4564 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4565 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4566 PetscFunctionReturn(PETSC_SUCCESS); 4567 } 4568 4569 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4570 { 4571 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4572 PetscInt dim, depth, pheight, coneSize; 4573 4574 PetscFunctionBeginHot; 4575 PetscCall(DMGetDimension(dm, &dim)); 4576 PetscCall(DMPlexGetDepth(dm, &depth)); 4577 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4578 pheight = depth - pdepth; 4579 if (depth <= 1) { 4580 switch (pdepth) { 4581 case 0: 4582 ct = DM_POLYTOPE_POINT; 4583 break; 4584 case 1: 4585 switch (coneSize) { 4586 case 2: 4587 ct = DM_POLYTOPE_SEGMENT; 4588 break; 4589 case 3: 4590 ct = DM_POLYTOPE_TRIANGLE; 4591 break; 4592 case 4: 4593 switch (dim) { 4594 case 2: 4595 ct = DM_POLYTOPE_QUADRILATERAL; 4596 break; 4597 case 3: 4598 ct = DM_POLYTOPE_TETRAHEDRON; 4599 break; 4600 default: 4601 break; 4602 } 4603 break; 4604 case 5: 4605 ct = DM_POLYTOPE_PYRAMID; 4606 break; 4607 case 6: 4608 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4609 break; 4610 case 8: 4611 ct = DM_POLYTOPE_HEXAHEDRON; 4612 break; 4613 default: 4614 break; 4615 } 4616 } 4617 } else { 4618 if (pdepth == 0) { 4619 ct = DM_POLYTOPE_POINT; 4620 } else if (pheight == 0) { 4621 switch (dim) { 4622 case 1: 4623 switch (coneSize) { 4624 case 2: 4625 ct = DM_POLYTOPE_SEGMENT; 4626 break; 4627 default: 4628 break; 4629 } 4630 break; 4631 case 2: 4632 switch (coneSize) { 4633 case 3: 4634 ct = DM_POLYTOPE_TRIANGLE; 4635 break; 4636 case 4: 4637 ct = DM_POLYTOPE_QUADRILATERAL; 4638 break; 4639 default: 4640 break; 4641 } 4642 break; 4643 case 3: 4644 switch (coneSize) { 4645 case 4: 4646 ct = DM_POLYTOPE_TETRAHEDRON; 4647 break; 4648 case 5: { 4649 const PetscInt *cone; 4650 PetscInt faceConeSize; 4651 4652 PetscCall(DMPlexGetCone(dm, p, &cone)); 4653 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4654 switch (faceConeSize) { 4655 case 3: 4656 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4657 break; 4658 case 4: 4659 ct = DM_POLYTOPE_PYRAMID; 4660 break; 4661 } 4662 } break; 4663 case 6: 4664 ct = DM_POLYTOPE_HEXAHEDRON; 4665 break; 4666 default: 4667 break; 4668 } 4669 break; 4670 default: 4671 break; 4672 } 4673 } else if (pheight > 0) { 4674 switch (coneSize) { 4675 case 2: 4676 ct = DM_POLYTOPE_SEGMENT; 4677 break; 4678 case 3: 4679 ct = DM_POLYTOPE_TRIANGLE; 4680 break; 4681 case 4: 4682 ct = DM_POLYTOPE_QUADRILATERAL; 4683 break; 4684 default: 4685 break; 4686 } 4687 } 4688 } 4689 *pt = ct; 4690 PetscFunctionReturn(PETSC_SUCCESS); 4691 } 4692 4693 /*@ 4694 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4695 4696 Collective 4697 4698 Input Parameter: 4699 . dm - The `DMPLEX` 4700 4701 Level: developer 4702 4703 Note: 4704 This function is normally called automatically when a cell type is requested. It creates an 4705 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4706 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4707 4708 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4709 4710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4711 @*/ 4712 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4713 { 4714 DM_Plex *mesh; 4715 DMLabel ctLabel; 4716 PetscInt pStart, pEnd, p; 4717 4718 PetscFunctionBegin; 4719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4720 mesh = (DM_Plex *)dm->data; 4721 PetscCall(DMCreateLabel(dm, "celltype")); 4722 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4723 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4724 PetscCall(PetscFree(mesh->cellTypes)); 4725 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4726 for (p = pStart; p < pEnd; ++p) { 4727 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4728 PetscInt pdepth; 4729 4730 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4731 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4732 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]); 4733 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4734 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4735 } 4736 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4737 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4738 PetscFunctionReturn(PETSC_SUCCESS); 4739 } 4740 4741 /*@C 4742 DMPlexGetJoin - Get an array for the join of the set of points 4743 4744 Not Collective 4745 4746 Input Parameters: 4747 + dm - The `DMPLEX` object 4748 . numPoints - The number of input points for the join 4749 - points - The input points 4750 4751 Output Parameters: 4752 + numCoveredPoints - The number of points in the join 4753 - coveredPoints - The points in the join 4754 4755 Level: intermediate 4756 4757 Note: 4758 Currently, this is restricted to a single level join 4759 4760 Fortran Notes: 4761 `converedPoints` must be declared with 4762 .vb 4763 PetscInt, pointer :: coveredPints(:) 4764 .ve 4765 4766 The `numCoveredPoints` argument is not present in the Fortran binding. 4767 4768 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4769 @*/ 4770 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4771 { 4772 DM_Plex *mesh = (DM_Plex *)dm->data; 4773 PetscInt *join[2]; 4774 PetscInt joinSize, i = 0; 4775 PetscInt dof, off, p, c, m; 4776 PetscInt maxSupportSize; 4777 4778 PetscFunctionBegin; 4779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4780 PetscAssertPointer(points, 3); 4781 PetscAssertPointer(numCoveredPoints, 4); 4782 PetscAssertPointer(coveredPoints, 5); 4783 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4784 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4785 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4786 /* Copy in support of first point */ 4787 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4788 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4789 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4790 /* Check each successive support */ 4791 for (p = 1; p < numPoints; ++p) { 4792 PetscInt newJoinSize = 0; 4793 4794 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4795 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4796 for (c = 0; c < dof; ++c) { 4797 const PetscInt point = mesh->supports[off + c]; 4798 4799 for (m = 0; m < joinSize; ++m) { 4800 if (point == join[i][m]) { 4801 join[1 - i][newJoinSize++] = point; 4802 break; 4803 } 4804 } 4805 } 4806 joinSize = newJoinSize; 4807 i = 1 - i; 4808 } 4809 *numCoveredPoints = joinSize; 4810 *coveredPoints = join[i]; 4811 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4812 PetscFunctionReturn(PETSC_SUCCESS); 4813 } 4814 4815 /*@C 4816 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4817 4818 Not Collective 4819 4820 Input Parameters: 4821 + dm - The `DMPLEX` object 4822 . numPoints - The number of input points for the join 4823 - points - The input points 4824 4825 Output Parameters: 4826 + numCoveredPoints - The number of points in the join 4827 - coveredPoints - The points in the join 4828 4829 Level: intermediate 4830 4831 Fortran Notes: 4832 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4833 4834 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4835 @*/ 4836 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4837 { 4838 PetscFunctionBegin; 4839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4840 if (points) PetscAssertPointer(points, 3); 4841 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4842 PetscAssertPointer(coveredPoints, 5); 4843 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4844 if (numCoveredPoints) *numCoveredPoints = 0; 4845 PetscFunctionReturn(PETSC_SUCCESS); 4846 } 4847 4848 /*@C 4849 DMPlexGetFullJoin - Get an array for the join of the set of points 4850 4851 Not Collective 4852 4853 Input Parameters: 4854 + dm - The `DMPLEX` object 4855 . numPoints - The number of input points for the join 4856 - points - The input points, its length is `numPoints` 4857 4858 Output Parameters: 4859 + numCoveredPoints - The number of points in the join 4860 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4861 4862 Level: intermediate 4863 4864 Fortran Notes: 4865 `points` and `converedPoints` must be declared with 4866 .vb 4867 PetscInt, pointer :: points(:) 4868 PetscInt, pointer :: coveredPints(:) 4869 .ve 4870 4871 The `numCoveredPoints` argument is not present in the Fortran binding. 4872 4873 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4874 @*/ 4875 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4876 { 4877 PetscInt *offsets, **closures; 4878 PetscInt *join[2]; 4879 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4880 PetscInt p, d, c, m, ms; 4881 4882 PetscFunctionBegin; 4883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4884 PetscAssertPointer(points, 3); 4885 PetscAssertPointer(numCoveredPoints, 4); 4886 PetscAssertPointer(coveredPoints, 5); 4887 4888 PetscCall(DMPlexGetDepth(dm, &depth)); 4889 PetscCall(PetscCalloc1(numPoints, &closures)); 4890 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4891 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4892 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4893 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4894 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4895 4896 for (p = 0; p < numPoints; ++p) { 4897 PetscInt closureSize; 4898 4899 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4900 4901 offsets[p * (depth + 2) + 0] = 0; 4902 for (d = 0; d < depth + 1; ++d) { 4903 PetscInt pStart, pEnd, i; 4904 4905 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4906 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4907 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4908 offsets[p * (depth + 2) + d + 1] = i; 4909 break; 4910 } 4911 } 4912 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4913 } 4914 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); 4915 } 4916 for (d = 0; d < depth + 1; ++d) { 4917 PetscInt dof; 4918 4919 /* Copy in support of first point */ 4920 dof = offsets[d + 1] - offsets[d]; 4921 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4922 /* Check each successive cone */ 4923 for (p = 1; p < numPoints && joinSize; ++p) { 4924 PetscInt newJoinSize = 0; 4925 4926 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4927 for (c = 0; c < dof; ++c) { 4928 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4929 4930 for (m = 0; m < joinSize; ++m) { 4931 if (point == join[i][m]) { 4932 join[1 - i][newJoinSize++] = point; 4933 break; 4934 } 4935 } 4936 } 4937 joinSize = newJoinSize; 4938 i = 1 - i; 4939 } 4940 if (joinSize) break; 4941 } 4942 *numCoveredPoints = joinSize; 4943 *coveredPoints = join[i]; 4944 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4945 PetscCall(PetscFree(closures)); 4946 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4947 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4948 PetscFunctionReturn(PETSC_SUCCESS); 4949 } 4950 4951 /*@C 4952 DMPlexGetMeet - Get an array for the meet of the set of points 4953 4954 Not Collective 4955 4956 Input Parameters: 4957 + dm - The `DMPLEX` object 4958 . numPoints - The number of input points for the meet 4959 - points - The input points, of length `numPoints` 4960 4961 Output Parameters: 4962 + numCoveringPoints - The number of points in the meet 4963 - coveringPoints - The points in the meet, of length `numCoveringPoints` 4964 4965 Level: intermediate 4966 4967 Note: 4968 Currently, this is restricted to a single level meet 4969 4970 Fortran Notes: 4971 `coveringPoints` must be declared with 4972 .vb 4973 PetscInt, pointer :: coveringPoints(:) 4974 .ve 4975 4976 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4977 4978 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4979 @*/ 4980 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 4981 { 4982 DM_Plex *mesh = (DM_Plex *)dm->data; 4983 PetscInt *meet[2]; 4984 PetscInt meetSize, i = 0; 4985 PetscInt dof, off, p, c, m; 4986 PetscInt maxConeSize; 4987 4988 PetscFunctionBegin; 4989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4990 PetscAssertPointer(points, 3); 4991 PetscAssertPointer(numCoveringPoints, 4); 4992 PetscAssertPointer(coveringPoints, 5); 4993 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4994 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4995 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4996 /* Copy in cone of first point */ 4997 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4998 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4999 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5000 /* Check each successive cone */ 5001 for (p = 1; p < numPoints; ++p) { 5002 PetscInt newMeetSize = 0; 5003 5004 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5005 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5006 for (c = 0; c < dof; ++c) { 5007 const PetscInt point = mesh->cones[off + c]; 5008 5009 for (m = 0; m < meetSize; ++m) { 5010 if (point == meet[i][m]) { 5011 meet[1 - i][newMeetSize++] = point; 5012 break; 5013 } 5014 } 5015 } 5016 meetSize = newMeetSize; 5017 i = 1 - i; 5018 } 5019 *numCoveringPoints = meetSize; 5020 *coveringPoints = meet[i]; 5021 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5022 PetscFunctionReturn(PETSC_SUCCESS); 5023 } 5024 5025 /*@C 5026 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5027 5028 Not Collective 5029 5030 Input Parameters: 5031 + dm - The `DMPLEX` object 5032 . numPoints - The number of input points for the meet 5033 - points - The input points 5034 5035 Output Parameters: 5036 + numCoveredPoints - The number of points in the meet 5037 - coveredPoints - The points in the meet 5038 5039 Level: intermediate 5040 5041 Fortran Notes: 5042 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5043 5044 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5045 @*/ 5046 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5047 { 5048 PetscFunctionBegin; 5049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5050 if (points) PetscAssertPointer(points, 3); 5051 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5052 PetscAssertPointer(coveredPoints, 5); 5053 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5054 if (numCoveredPoints) *numCoveredPoints = 0; 5055 PetscFunctionReturn(PETSC_SUCCESS); 5056 } 5057 5058 /*@C 5059 DMPlexGetFullMeet - Get an array for the meet of the set of points 5060 5061 Not Collective 5062 5063 Input Parameters: 5064 + dm - The `DMPLEX` object 5065 . numPoints - The number of input points for the meet 5066 - points - The input points, of length `numPoints` 5067 5068 Output Parameters: 5069 + numCoveredPoints - The number of points in the meet 5070 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5071 5072 Level: intermediate 5073 5074 Fortran Notes: 5075 `points` and `coveredPoints` must be declared with 5076 .vb 5077 PetscInt, pointer :: points(:) 5078 PetscInt, pointer :: coveredPoints(:) 5079 .ve 5080 5081 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5082 5083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5084 @*/ 5085 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5086 { 5087 PetscInt *offsets, **closures; 5088 PetscInt *meet[2]; 5089 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5090 PetscInt p, h, c, m, mc; 5091 5092 PetscFunctionBegin; 5093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5094 PetscAssertPointer(points, 3); 5095 PetscAssertPointer(numCoveredPoints, 4); 5096 PetscAssertPointer(coveredPoints, 5); 5097 5098 PetscCall(DMPlexGetDepth(dm, &height)); 5099 PetscCall(PetscMalloc1(numPoints, &closures)); 5100 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5101 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5102 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5103 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5104 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5105 5106 for (p = 0; p < numPoints; ++p) { 5107 PetscInt closureSize; 5108 5109 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5110 5111 offsets[p * (height + 2) + 0] = 0; 5112 for (h = 0; h < height + 1; ++h) { 5113 PetscInt pStart, pEnd, i; 5114 5115 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5116 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5117 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5118 offsets[p * (height + 2) + h + 1] = i; 5119 break; 5120 } 5121 } 5122 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5123 } 5124 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); 5125 } 5126 for (h = 0; h < height + 1; ++h) { 5127 PetscInt dof; 5128 5129 /* Copy in cone of first point */ 5130 dof = offsets[h + 1] - offsets[h]; 5131 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5132 /* Check each successive cone */ 5133 for (p = 1; p < numPoints && meetSize; ++p) { 5134 PetscInt newMeetSize = 0; 5135 5136 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5137 for (c = 0; c < dof; ++c) { 5138 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5139 5140 for (m = 0; m < meetSize; ++m) { 5141 if (point == meet[i][m]) { 5142 meet[1 - i][newMeetSize++] = point; 5143 break; 5144 } 5145 } 5146 } 5147 meetSize = newMeetSize; 5148 i = 1 - i; 5149 } 5150 if (meetSize) break; 5151 } 5152 *numCoveredPoints = meetSize; 5153 *coveredPoints = meet[i]; 5154 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5155 PetscCall(PetscFree(closures)); 5156 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5157 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5158 PetscFunctionReturn(PETSC_SUCCESS); 5159 } 5160 5161 /*@ 5162 DMPlexEqual - Determine if two `DM` have the same topology 5163 5164 Not Collective 5165 5166 Input Parameters: 5167 + dmA - A `DMPLEX` object 5168 - dmB - A `DMPLEX` object 5169 5170 Output Parameter: 5171 . equal - `PETSC_TRUE` if the topologies are identical 5172 5173 Level: intermediate 5174 5175 Note: 5176 We are not solving graph isomorphism, so we do not permute. 5177 5178 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5179 @*/ 5180 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5181 { 5182 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5183 5184 PetscFunctionBegin; 5185 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5186 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5187 PetscAssertPointer(equal, 3); 5188 5189 *equal = PETSC_FALSE; 5190 PetscCall(DMPlexGetDepth(dmA, &depth)); 5191 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5192 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5193 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5194 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5195 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5196 for (p = pStart; p < pEnd; ++p) { 5197 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5198 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5199 5200 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5201 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5202 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5203 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5204 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5205 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5206 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5207 for (c = 0; c < coneSize; ++c) { 5208 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5209 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5210 } 5211 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5212 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5213 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5214 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5215 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5216 for (s = 0; s < supportSize; ++s) { 5217 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5218 } 5219 } 5220 *equal = PETSC_TRUE; 5221 PetscFunctionReturn(PETSC_SUCCESS); 5222 } 5223 5224 /*@ 5225 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5226 5227 Not Collective 5228 5229 Input Parameters: 5230 + dm - The `DMPLEX` 5231 . cellDim - The cell dimension 5232 - numCorners - The number of vertices on a cell 5233 5234 Output Parameter: 5235 . numFaceVertices - The number of vertices on a face 5236 5237 Level: developer 5238 5239 Note: 5240 Of course this can only work for a restricted set of symmetric shapes 5241 5242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5243 @*/ 5244 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5245 { 5246 MPI_Comm comm; 5247 5248 PetscFunctionBegin; 5249 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5250 PetscAssertPointer(numFaceVertices, 4); 5251 switch (cellDim) { 5252 case 0: 5253 *numFaceVertices = 0; 5254 break; 5255 case 1: 5256 *numFaceVertices = 1; 5257 break; 5258 case 2: 5259 switch (numCorners) { 5260 case 3: /* triangle */ 5261 *numFaceVertices = 2; /* Edge has 2 vertices */ 5262 break; 5263 case 4: /* quadrilateral */ 5264 *numFaceVertices = 2; /* Edge has 2 vertices */ 5265 break; 5266 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5267 *numFaceVertices = 3; /* Edge has 3 vertices */ 5268 break; 5269 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5270 *numFaceVertices = 3; /* Edge has 3 vertices */ 5271 break; 5272 default: 5273 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5274 } 5275 break; 5276 case 3: 5277 switch (numCorners) { 5278 case 4: /* tetradehdron */ 5279 *numFaceVertices = 3; /* Face has 3 vertices */ 5280 break; 5281 case 6: /* tet cohesive cells */ 5282 *numFaceVertices = 4; /* Face has 4 vertices */ 5283 break; 5284 case 8: /* hexahedron */ 5285 *numFaceVertices = 4; /* Face has 4 vertices */ 5286 break; 5287 case 9: /* tet cohesive Lagrange cells */ 5288 *numFaceVertices = 6; /* Face has 6 vertices */ 5289 break; 5290 case 10: /* quadratic tetrahedron */ 5291 *numFaceVertices = 6; /* Face has 6 vertices */ 5292 break; 5293 case 12: /* hex cohesive Lagrange cells */ 5294 *numFaceVertices = 6; /* Face has 6 vertices */ 5295 break; 5296 case 18: /* quadratic tet cohesive Lagrange cells */ 5297 *numFaceVertices = 6; /* Face has 6 vertices */ 5298 break; 5299 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5300 *numFaceVertices = 9; /* Face has 9 vertices */ 5301 break; 5302 default: 5303 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5304 } 5305 break; 5306 default: 5307 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5308 } 5309 PetscFunctionReturn(PETSC_SUCCESS); 5310 } 5311 5312 /*@ 5313 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5314 5315 Not Collective 5316 5317 Input Parameter: 5318 . dm - The `DMPLEX` object 5319 5320 Output Parameter: 5321 . depthLabel - The `DMLabel` recording point depth 5322 5323 Level: developer 5324 5325 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5326 @*/ 5327 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5328 { 5329 PetscFunctionBegin; 5330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5331 PetscAssertPointer(depthLabel, 2); 5332 *depthLabel = dm->depthLabel; 5333 PetscFunctionReturn(PETSC_SUCCESS); 5334 } 5335 5336 /*@ 5337 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5338 5339 Not Collective 5340 5341 Input Parameter: 5342 . dm - The `DMPLEX` object 5343 5344 Output Parameter: 5345 . depth - The number of strata (breadth first levels) in the DAG 5346 5347 Level: developer 5348 5349 Notes: 5350 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5351 5352 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5353 5354 An empty mesh gives -1. 5355 5356 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5357 @*/ 5358 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5359 { 5360 DM_Plex *mesh = (DM_Plex *)dm->data; 5361 DMLabel label; 5362 PetscInt d = -1; 5363 5364 PetscFunctionBegin; 5365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5366 PetscAssertPointer(depth, 2); 5367 if (mesh->tr) { 5368 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5369 } else { 5370 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5371 // Allow missing depths 5372 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5373 *depth = d; 5374 } 5375 PetscFunctionReturn(PETSC_SUCCESS); 5376 } 5377 5378 /*@ 5379 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5380 5381 Not Collective 5382 5383 Input Parameters: 5384 + dm - The `DMPLEX` object 5385 - depth - The requested depth 5386 5387 Output Parameters: 5388 + start - The first point at this `depth` 5389 - end - One beyond the last point at this `depth` 5390 5391 Level: developer 5392 5393 Notes: 5394 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5395 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5396 higher dimension, e.g., "edges". 5397 5398 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5399 @*/ 5400 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5401 { 5402 DM_Plex *mesh = (DM_Plex *)dm->data; 5403 DMLabel label; 5404 PetscInt pStart, pEnd; 5405 5406 PetscFunctionBegin; 5407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5408 if (start) { 5409 PetscAssertPointer(start, 3); 5410 *start = 0; 5411 } 5412 if (end) { 5413 PetscAssertPointer(end, 4); 5414 *end = 0; 5415 } 5416 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5417 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5418 if (depth < 0) { 5419 if (start) *start = pStart; 5420 if (end) *end = pEnd; 5421 PetscFunctionReturn(PETSC_SUCCESS); 5422 } 5423 if (mesh->tr) { 5424 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5425 } else { 5426 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5427 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5428 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5429 } 5430 PetscFunctionReturn(PETSC_SUCCESS); 5431 } 5432 5433 /*@ 5434 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5435 5436 Not Collective 5437 5438 Input Parameters: 5439 + dm - The `DMPLEX` object 5440 - height - The requested height 5441 5442 Output Parameters: 5443 + start - The first point at this `height` 5444 - end - One beyond the last point at this `height` 5445 5446 Level: developer 5447 5448 Notes: 5449 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5450 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5451 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5452 5453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5454 @*/ 5455 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5456 { 5457 DMLabel label; 5458 PetscInt depth, pStart, pEnd; 5459 5460 PetscFunctionBegin; 5461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5462 if (start) { 5463 PetscAssertPointer(start, 3); 5464 *start = 0; 5465 } 5466 if (end) { 5467 PetscAssertPointer(end, 4); 5468 *end = 0; 5469 } 5470 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5471 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5472 if (height < 0) { 5473 if (start) *start = pStart; 5474 if (end) *end = pEnd; 5475 PetscFunctionReturn(PETSC_SUCCESS); 5476 } 5477 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5478 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5479 else PetscCall(DMGetDimension(dm, &depth)); 5480 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5481 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5482 PetscFunctionReturn(PETSC_SUCCESS); 5483 } 5484 5485 /*@ 5486 DMPlexGetPointDepth - Get the `depth` of a given point 5487 5488 Not Collective 5489 5490 Input Parameters: 5491 + dm - The `DMPLEX` object 5492 - point - The point 5493 5494 Output Parameter: 5495 . depth - The depth of the `point` 5496 5497 Level: intermediate 5498 5499 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5500 @*/ 5501 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5502 { 5503 PetscFunctionBegin; 5504 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5505 PetscAssertPointer(depth, 3); 5506 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5507 PetscFunctionReturn(PETSC_SUCCESS); 5508 } 5509 5510 /*@ 5511 DMPlexGetPointHeight - Get the `height` of a given point 5512 5513 Not Collective 5514 5515 Input Parameters: 5516 + dm - The `DMPLEX` object 5517 - point - The point 5518 5519 Output Parameter: 5520 . height - The height of the `point` 5521 5522 Level: intermediate 5523 5524 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5525 @*/ 5526 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5527 { 5528 PetscInt n, pDepth; 5529 5530 PetscFunctionBegin; 5531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5532 PetscAssertPointer(height, 3); 5533 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5534 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5535 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5536 PetscFunctionReturn(PETSC_SUCCESS); 5537 } 5538 5539 /*@ 5540 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5541 5542 Not Collective 5543 5544 Input Parameter: 5545 . dm - The `DMPLEX` object 5546 5547 Output Parameter: 5548 . celltypeLabel - The `DMLabel` recording cell polytope type 5549 5550 Level: developer 5551 5552 Note: 5553 This function will trigger automatica computation of cell types. This can be disabled by calling 5554 `DMCreateLabel`(dm, "celltype") beforehand. 5555 5556 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5557 @*/ 5558 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5559 { 5560 PetscFunctionBegin; 5561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5562 PetscAssertPointer(celltypeLabel, 2); 5563 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5564 *celltypeLabel = dm->celltypeLabel; 5565 PetscFunctionReturn(PETSC_SUCCESS); 5566 } 5567 5568 /*@ 5569 DMPlexGetCellType - Get the polytope type of a given cell 5570 5571 Not Collective 5572 5573 Input Parameters: 5574 + dm - The `DMPLEX` object 5575 - cell - The cell 5576 5577 Output Parameter: 5578 . celltype - The polytope type of the cell 5579 5580 Level: intermediate 5581 5582 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5583 @*/ 5584 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5585 { 5586 DM_Plex *mesh = (DM_Plex *)dm->data; 5587 DMLabel label; 5588 PetscInt ct; 5589 5590 PetscFunctionBegin; 5591 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5592 PetscAssertPointer(celltype, 3); 5593 if (mesh->tr) { 5594 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5595 } else { 5596 PetscInt pStart, pEnd; 5597 5598 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5599 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5600 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5601 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5602 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5603 for (PetscInt p = pStart; p < pEnd; p++) { 5604 PetscCall(DMLabelGetValue(label, p, &ct)); 5605 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5606 } 5607 } 5608 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5609 if (PetscDefined(USE_DEBUG)) { 5610 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5611 PetscCall(DMLabelGetValue(label, cell, &ct)); 5612 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5613 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5614 } 5615 } 5616 PetscFunctionReturn(PETSC_SUCCESS); 5617 } 5618 5619 /*@ 5620 DMPlexSetCellType - Set the polytope type of a given cell 5621 5622 Not Collective 5623 5624 Input Parameters: 5625 + dm - The `DMPLEX` object 5626 . cell - The cell 5627 - celltype - The polytope type of the cell 5628 5629 Level: advanced 5630 5631 Note: 5632 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5633 is executed. This function will override the computed type. However, if automatic classification will not succeed 5634 and a user wants to manually specify all types, the classification must be disabled by calling 5635 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5636 5637 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5638 @*/ 5639 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5640 { 5641 DM_Plex *mesh = (DM_Plex *)dm->data; 5642 DMLabel label; 5643 PetscInt pStart, pEnd; 5644 5645 PetscFunctionBegin; 5646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5647 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5648 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5649 PetscCall(DMLabelSetValue(label, cell, celltype)); 5650 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5651 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5652 PetscFunctionReturn(PETSC_SUCCESS); 5653 } 5654 5655 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5656 { 5657 PetscSection section; 5658 PetscInt maxHeight; 5659 const char *prefix; 5660 5661 PetscFunctionBegin; 5662 PetscCall(DMClone(dm, cdm)); 5663 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5664 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5665 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5666 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5667 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5668 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5669 PetscCall(DMSetLocalSection(*cdm, section)); 5670 PetscCall(PetscSectionDestroy(§ion)); 5671 5672 PetscCall(DMSetNumFields(*cdm, 1)); 5673 PetscCall(DMCreateDS(*cdm)); 5674 (*cdm)->cloneOpts = PETSC_TRUE; 5675 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5676 PetscFunctionReturn(PETSC_SUCCESS); 5677 } 5678 5679 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5680 { 5681 Vec coordsLocal, cellCoordsLocal; 5682 DM coordsDM, cellCoordsDM; 5683 5684 PetscFunctionBegin; 5685 *field = NULL; 5686 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5687 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5688 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5689 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5690 if (coordsLocal && coordsDM) { 5691 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5692 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5693 } 5694 PetscFunctionReturn(PETSC_SUCCESS); 5695 } 5696 5697 /*@ 5698 DMPlexGetConeSection - Return a section which describes the layout of cone data 5699 5700 Not Collective 5701 5702 Input Parameter: 5703 . dm - The `DMPLEX` object 5704 5705 Output Parameter: 5706 . section - The `PetscSection` object 5707 5708 Level: developer 5709 5710 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5711 @*/ 5712 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5713 { 5714 DM_Plex *mesh = (DM_Plex *)dm->data; 5715 5716 PetscFunctionBegin; 5717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5718 if (section) *section = mesh->coneSection; 5719 PetscFunctionReturn(PETSC_SUCCESS); 5720 } 5721 5722 /*@ 5723 DMPlexGetSupportSection - Return a section which describes the layout of support data 5724 5725 Not Collective 5726 5727 Input Parameter: 5728 . dm - The `DMPLEX` object 5729 5730 Output Parameter: 5731 . section - The `PetscSection` object 5732 5733 Level: developer 5734 5735 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5736 @*/ 5737 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5738 { 5739 DM_Plex *mesh = (DM_Plex *)dm->data; 5740 5741 PetscFunctionBegin; 5742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5743 if (section) *section = mesh->supportSection; 5744 PetscFunctionReturn(PETSC_SUCCESS); 5745 } 5746 5747 /*@C 5748 DMPlexGetCones - Return cone data 5749 5750 Not Collective 5751 5752 Input Parameter: 5753 . dm - The `DMPLEX` object 5754 5755 Output Parameter: 5756 . cones - The cone for each point 5757 5758 Level: developer 5759 5760 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5761 @*/ 5762 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5763 { 5764 DM_Plex *mesh = (DM_Plex *)dm->data; 5765 5766 PetscFunctionBegin; 5767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5768 if (cones) *cones = mesh->cones; 5769 PetscFunctionReturn(PETSC_SUCCESS); 5770 } 5771 5772 /*@C 5773 DMPlexGetConeOrientations - Return cone orientation data 5774 5775 Not Collective 5776 5777 Input Parameter: 5778 . dm - The `DMPLEX` object 5779 5780 Output Parameter: 5781 . coneOrientations - The array of cone orientations for all points 5782 5783 Level: developer 5784 5785 Notes: 5786 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5787 as returned by `DMPlexGetConeOrientation()`. 5788 5789 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5790 5791 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5792 @*/ 5793 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5794 { 5795 DM_Plex *mesh = (DM_Plex *)dm->data; 5796 5797 PetscFunctionBegin; 5798 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5799 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5800 PetscFunctionReturn(PETSC_SUCCESS); 5801 } 5802 5803 /* FEM Support */ 5804 5805 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5806 { 5807 PetscInt depth; 5808 5809 PetscFunctionBegin; 5810 PetscCall(DMPlexGetDepth(plex, &depth)); 5811 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5812 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5813 PetscFunctionReturn(PETSC_SUCCESS); 5814 } 5815 5816 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5817 { 5818 PetscInt depth; 5819 5820 PetscFunctionBegin; 5821 PetscCall(DMPlexGetDepth(plex, &depth)); 5822 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5823 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5824 PetscFunctionReturn(PETSC_SUCCESS); 5825 } 5826 5827 /* 5828 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5829 representing a line in the section. 5830 */ 5831 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5832 { 5833 PetscObject obj; 5834 PetscClassId id; 5835 PetscFE fe = NULL; 5836 5837 PetscFunctionBeginHot; 5838 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5839 PetscCall(DMGetField(dm, field, NULL, &obj)); 5840 PetscCall(PetscObjectGetClassId(obj, &id)); 5841 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5842 5843 if (!fe) { 5844 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5845 /* An order k SEM disc has k-1 dofs on an edge */ 5846 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5847 *k = *k / *Nc + 1; 5848 } else { 5849 PetscInt dual_space_size, dim; 5850 PetscDualSpace dsp; 5851 5852 PetscCall(DMGetDimension(dm, &dim)); 5853 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5854 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5855 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5856 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5857 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5858 } 5859 PetscFunctionReturn(PETSC_SUCCESS); 5860 } 5861 5862 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5863 { 5864 PetscFunctionBeginHot; 5865 if (tensor) { 5866 *dof = PetscPowInt(k + 1, dim); 5867 } else { 5868 switch (dim) { 5869 case 1: 5870 *dof = k + 1; 5871 break; 5872 case 2: 5873 *dof = ((k + 1) * (k + 2)) / 2; 5874 break; 5875 case 3: 5876 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5877 break; 5878 default: 5879 *dof = 0; 5880 } 5881 } 5882 PetscFunctionReturn(PETSC_SUCCESS); 5883 } 5884 5885 /*@ 5886 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5887 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5888 section provided (or the section of the `DM`). 5889 5890 Input Parameters: 5891 + dm - The `DM` 5892 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5893 - section - The `PetscSection` to reorder, or `NULL` for the default section 5894 5895 Example: 5896 A typical interpolated single-quad mesh might order points as 5897 .vb 5898 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5899 5900 v4 -- e6 -- v3 5901 | | 5902 e7 c0 e8 5903 | | 5904 v1 -- e5 -- v2 5905 .ve 5906 5907 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5908 dofs in the order of points, e.g., 5909 .vb 5910 c0 -> [0,1,2,3] 5911 v1 -> [4] 5912 ... 5913 e5 -> [8, 9] 5914 .ve 5915 5916 which corresponds to the dofs 5917 .vb 5918 6 10 11 7 5919 13 2 3 15 5920 12 0 1 14 5921 4 8 9 5 5922 .ve 5923 5924 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5925 .vb 5926 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5927 .ve 5928 5929 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5930 .vb 5931 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5932 .ve 5933 5934 Level: developer 5935 5936 Notes: 5937 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5938 degree of the basis. 5939 5940 This is required to run with libCEED. 5941 5942 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5943 @*/ 5944 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5945 { 5946 DMLabel label; 5947 PetscInt dim, depth = -1, eStart = -1, Nf; 5948 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5949 5950 PetscFunctionBegin; 5951 PetscCall(DMGetDimension(dm, &dim)); 5952 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5953 if (point < 0) { 5954 PetscInt sStart, sEnd; 5955 5956 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5957 point = sEnd - sStart ? sStart : point; 5958 } 5959 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5960 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5961 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5962 if (depth == 1) { 5963 eStart = point; 5964 } else if (depth == dim) { 5965 const PetscInt *cone; 5966 5967 PetscCall(DMPlexGetCone(dm, point, &cone)); 5968 if (dim == 2) eStart = cone[0]; 5969 else if (dim == 3) { 5970 const PetscInt *cone2; 5971 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5972 eStart = cone2[0]; 5973 } 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); 5974 } 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); 5975 5976 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5977 for (PetscInt d = 1; d <= dim; d++) { 5978 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5979 PetscInt *perm; 5980 5981 for (f = 0; f < Nf; ++f) { 5982 PetscInt dof; 5983 5984 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5985 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5986 if (!continuous && d < dim) continue; 5987 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5988 size += dof * Nc; 5989 } 5990 PetscCall(PetscMalloc1(size, &perm)); 5991 for (f = 0; f < Nf; ++f) { 5992 switch (d) { 5993 case 1: 5994 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5995 if (!continuous && d < dim) continue; 5996 /* 5997 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5998 We want [ vtx0; edge of length k-1; vtx1 ] 5999 */ 6000 if (continuous) { 6001 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6002 for (i = 0; i < k - 1; i++) 6003 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6004 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6005 foffset = offset; 6006 } else { 6007 PetscInt dof; 6008 6009 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6010 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6011 foffset = offset; 6012 } 6013 break; 6014 case 2: 6015 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6016 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6017 if (!continuous && d < dim) continue; 6018 /* The SEM order is 6019 6020 v_lb, {e_b}, v_rb, 6021 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6022 v_lt, reverse {e_t}, v_rt 6023 */ 6024 if (continuous) { 6025 const PetscInt of = 0; 6026 const PetscInt oeb = of + PetscSqr(k - 1); 6027 const PetscInt oer = oeb + (k - 1); 6028 const PetscInt oet = oer + (k - 1); 6029 const PetscInt oel = oet + (k - 1); 6030 const PetscInt ovlb = oel + (k - 1); 6031 const PetscInt ovrb = ovlb + 1; 6032 const PetscInt ovrt = ovrb + 1; 6033 const PetscInt ovlt = ovrt + 1; 6034 PetscInt o; 6035 6036 /* bottom */ 6037 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6038 for (o = oeb; o < oer; ++o) 6039 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6040 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6041 /* middle */ 6042 for (i = 0; i < k - 1; ++i) { 6043 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6044 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6045 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6046 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6047 } 6048 /* top */ 6049 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6050 for (o = oel - 1; o >= oet; --o) 6051 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6052 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6053 foffset = offset; 6054 } else { 6055 PetscInt dof; 6056 6057 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6058 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6059 foffset = offset; 6060 } 6061 break; 6062 case 3: 6063 /* The original hex closure is 6064 6065 {c, 6066 f_b, f_t, f_f, f_b, f_r, f_l, 6067 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6068 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6069 */ 6070 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6071 if (!continuous && d < dim) continue; 6072 /* The SEM order is 6073 Bottom Slice 6074 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6075 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6076 v_blb, {e_bb}, v_brb, 6077 6078 Middle Slice (j) 6079 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6080 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6081 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6082 6083 Top Slice 6084 v_tlf, {e_tf}, v_trf, 6085 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6086 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6087 */ 6088 if (continuous) { 6089 const PetscInt oc = 0; 6090 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6091 const PetscInt oft = ofb + PetscSqr(k - 1); 6092 const PetscInt off = oft + PetscSqr(k - 1); 6093 const PetscInt ofk = off + PetscSqr(k - 1); 6094 const PetscInt ofr = ofk + PetscSqr(k - 1); 6095 const PetscInt ofl = ofr + PetscSqr(k - 1); 6096 const PetscInt oebl = ofl + PetscSqr(k - 1); 6097 const PetscInt oebb = oebl + (k - 1); 6098 const PetscInt oebr = oebb + (k - 1); 6099 const PetscInt oebf = oebr + (k - 1); 6100 const PetscInt oetf = oebf + (k - 1); 6101 const PetscInt oetr = oetf + (k - 1); 6102 const PetscInt oetb = oetr + (k - 1); 6103 const PetscInt oetl = oetb + (k - 1); 6104 const PetscInt oerf = oetl + (k - 1); 6105 const PetscInt oelf = oerf + (k - 1); 6106 const PetscInt oelb = oelf + (k - 1); 6107 const PetscInt oerb = oelb + (k - 1); 6108 const PetscInt ovblf = oerb + (k - 1); 6109 const PetscInt ovblb = ovblf + 1; 6110 const PetscInt ovbrb = ovblb + 1; 6111 const PetscInt ovbrf = ovbrb + 1; 6112 const PetscInt ovtlf = ovbrf + 1; 6113 const PetscInt ovtrf = ovtlf + 1; 6114 const PetscInt ovtrb = ovtrf + 1; 6115 const PetscInt ovtlb = ovtrb + 1; 6116 PetscInt o, n; 6117 6118 /* Bottom Slice */ 6119 /* bottom */ 6120 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6121 for (o = oetf - 1; o >= oebf; --o) 6122 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6123 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6124 /* middle */ 6125 for (i = 0; i < k - 1; ++i) { 6126 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6127 for (n = 0; n < k - 1; ++n) { 6128 o = ofb + n * (k - 1) + i; 6129 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6130 } 6131 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6132 } 6133 /* top */ 6134 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6135 for (o = oebb; o < oebr; ++o) 6136 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6137 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6138 6139 /* Middle Slice */ 6140 for (j = 0; j < k - 1; ++j) { 6141 /* bottom */ 6142 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6143 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6144 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6145 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6146 /* middle */ 6147 for (i = 0; i < k - 1; ++i) { 6148 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6149 for (n = 0; n < k - 1; ++n) 6150 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6151 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6152 } 6153 /* top */ 6154 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6155 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6156 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6157 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6158 } 6159 6160 /* Top Slice */ 6161 /* bottom */ 6162 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6163 for (o = oetf; o < oetr; ++o) 6164 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6165 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6166 /* middle */ 6167 for (i = 0; i < k - 1; ++i) { 6168 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6169 for (n = 0; n < k - 1; ++n) 6170 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6171 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6172 } 6173 /* top */ 6174 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6175 for (o = oetl - 1; o >= oetb; --o) 6176 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6177 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6178 6179 foffset = offset; 6180 } else { 6181 PetscInt dof; 6182 6183 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6184 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6185 foffset = offset; 6186 } 6187 break; 6188 default: 6189 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6190 } 6191 } 6192 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6193 /* Check permutation */ 6194 { 6195 PetscInt *check; 6196 6197 PetscCall(PetscMalloc1(size, &check)); 6198 for (i = 0; i < size; ++i) { 6199 check[i] = -1; 6200 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6201 } 6202 for (i = 0; i < size; ++i) check[perm[i]] = i; 6203 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6204 PetscCall(PetscFree(check)); 6205 } 6206 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6207 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6208 PetscInt *loc_perm; 6209 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6210 for (PetscInt i = 0; i < size; i++) { 6211 loc_perm[i] = perm[i]; 6212 loc_perm[size + i] = size + perm[i]; 6213 } 6214 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6215 } 6216 } 6217 PetscFunctionReturn(PETSC_SUCCESS); 6218 } 6219 6220 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6221 { 6222 PetscDS prob; 6223 PetscInt depth, Nf, h; 6224 DMLabel label; 6225 6226 PetscFunctionBeginHot; 6227 PetscCall(DMGetDS(dm, &prob)); 6228 Nf = prob->Nf; 6229 label = dm->depthLabel; 6230 *dspace = NULL; 6231 if (field < Nf) { 6232 PetscObject disc = prob->disc[field]; 6233 6234 if (disc->classid == PETSCFE_CLASSID) { 6235 PetscDualSpace dsp; 6236 6237 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6238 PetscCall(DMLabelGetNumValues(label, &depth)); 6239 PetscCall(DMLabelGetValue(label, point, &h)); 6240 h = depth - 1 - h; 6241 if (h) { 6242 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6243 } else { 6244 *dspace = dsp; 6245 } 6246 } 6247 } 6248 PetscFunctionReturn(PETSC_SUCCESS); 6249 } 6250 6251 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6252 { 6253 PetscScalar *array; 6254 const PetscScalar *vArray; 6255 const PetscInt *cone, *coneO; 6256 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6257 6258 PetscFunctionBeginHot; 6259 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6260 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6261 PetscCall(DMPlexGetCone(dm, point, &cone)); 6262 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6263 if (!values || !*values) { 6264 if ((point >= pStart) && (point < pEnd)) { 6265 PetscInt dof; 6266 6267 PetscCall(PetscSectionGetDof(section, point, &dof)); 6268 size += dof; 6269 } 6270 for (p = 0; p < numPoints; ++p) { 6271 const PetscInt cp = cone[p]; 6272 PetscInt dof; 6273 6274 if ((cp < pStart) || (cp >= pEnd)) continue; 6275 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6276 size += dof; 6277 } 6278 if (!values) { 6279 if (csize) *csize = size; 6280 PetscFunctionReturn(PETSC_SUCCESS); 6281 } 6282 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6283 } else { 6284 array = *values; 6285 } 6286 size = 0; 6287 PetscCall(VecGetArrayRead(v, &vArray)); 6288 if ((point >= pStart) && (point < pEnd)) { 6289 PetscInt dof, off, d; 6290 const PetscScalar *varr; 6291 6292 PetscCall(PetscSectionGetDof(section, point, &dof)); 6293 PetscCall(PetscSectionGetOffset(section, point, &off)); 6294 varr = PetscSafePointerPlusOffset(vArray, off); 6295 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6296 size += dof; 6297 } 6298 for (p = 0; p < numPoints; ++p) { 6299 const PetscInt cp = cone[p]; 6300 PetscInt o = coneO[p]; 6301 PetscInt dof, off, d; 6302 const PetscScalar *varr; 6303 6304 if ((cp < pStart) || (cp >= pEnd)) continue; 6305 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6306 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6307 varr = PetscSafePointerPlusOffset(vArray, off); 6308 if (o >= 0) { 6309 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6310 } else { 6311 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6312 } 6313 size += dof; 6314 } 6315 PetscCall(VecRestoreArrayRead(v, &vArray)); 6316 if (!*values) { 6317 if (csize) *csize = size; 6318 *values = array; 6319 } else { 6320 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6321 *csize = size; 6322 } 6323 PetscFunctionReturn(PETSC_SUCCESS); 6324 } 6325 6326 /* Compress out points not in the section */ 6327 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6328 { 6329 const PetscInt np = *numPoints; 6330 PetscInt pStart, pEnd, p, q; 6331 6332 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6333 for (p = 0, q = 0; p < np; ++p) { 6334 const PetscInt r = points[p * 2]; 6335 if ((r >= pStart) && (r < pEnd)) { 6336 points[q * 2] = r; 6337 points[q * 2 + 1] = points[p * 2 + 1]; 6338 ++q; 6339 } 6340 } 6341 *numPoints = q; 6342 return PETSC_SUCCESS; 6343 } 6344 6345 /* Compressed closure does not apply closure permutation */ 6346 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6347 { 6348 const PetscInt *cla = NULL; 6349 PetscInt np, *pts = NULL; 6350 6351 PetscFunctionBeginHot; 6352 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6353 if (!ornt && *clPoints) { 6354 PetscInt dof, off; 6355 6356 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6357 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6358 PetscCall(ISGetIndices(*clPoints, &cla)); 6359 np = dof / 2; 6360 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6361 } else { 6362 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6363 PetscCall(CompressPoints_Private(section, &np, pts)); 6364 } 6365 *numPoints = np; 6366 *points = pts; 6367 *clp = cla; 6368 PetscFunctionReturn(PETSC_SUCCESS); 6369 } 6370 6371 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6372 { 6373 PetscFunctionBeginHot; 6374 if (!*clPoints) { 6375 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6376 } else { 6377 PetscCall(ISRestoreIndices(*clPoints, clp)); 6378 } 6379 *numPoints = 0; 6380 *points = NULL; 6381 *clSec = NULL; 6382 *clPoints = NULL; 6383 *clp = NULL; 6384 PetscFunctionReturn(PETSC_SUCCESS); 6385 } 6386 6387 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6388 { 6389 PetscInt offset = 0, p; 6390 const PetscInt **perms = NULL; 6391 const PetscScalar **flips = NULL; 6392 6393 PetscFunctionBeginHot; 6394 *size = 0; 6395 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6396 for (p = 0; p < numPoints; p++) { 6397 const PetscInt point = points[2 * p]; 6398 const PetscInt *perm = perms ? perms[p] : NULL; 6399 const PetscScalar *flip = flips ? flips[p] : NULL; 6400 PetscInt dof, off, d; 6401 const PetscScalar *varr; 6402 6403 PetscCall(PetscSectionGetDof(section, point, &dof)); 6404 PetscCall(PetscSectionGetOffset(section, point, &off)); 6405 varr = PetscSafePointerPlusOffset(vArray, off); 6406 if (clperm) { 6407 if (perm) { 6408 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6409 } else { 6410 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6411 } 6412 if (flip) { 6413 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6414 } 6415 } else { 6416 if (perm) { 6417 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6418 } else { 6419 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6420 } 6421 if (flip) { 6422 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6423 } 6424 } 6425 offset += dof; 6426 } 6427 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6428 *size = offset; 6429 PetscFunctionReturn(PETSC_SUCCESS); 6430 } 6431 6432 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[]) 6433 { 6434 PetscInt offset = 0, f; 6435 6436 PetscFunctionBeginHot; 6437 *size = 0; 6438 for (f = 0; f < numFields; ++f) { 6439 PetscInt p; 6440 const PetscInt **perms = NULL; 6441 const PetscScalar **flips = NULL; 6442 6443 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6444 for (p = 0; p < numPoints; p++) { 6445 const PetscInt point = points[2 * p]; 6446 PetscInt fdof, foff, b; 6447 const PetscScalar *varr; 6448 const PetscInt *perm = perms ? perms[p] : NULL; 6449 const PetscScalar *flip = flips ? flips[p] : NULL; 6450 6451 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6452 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6453 varr = &vArray[foff]; 6454 if (clperm) { 6455 if (perm) { 6456 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6457 } else { 6458 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6459 } 6460 if (flip) { 6461 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6462 } 6463 } else { 6464 if (perm) { 6465 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6466 } else { 6467 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6468 } 6469 if (flip) { 6470 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6471 } 6472 } 6473 offset += fdof; 6474 } 6475 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6476 } 6477 *size = offset; 6478 PetscFunctionReturn(PETSC_SUCCESS); 6479 } 6480 6481 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6482 { 6483 PetscSection clSection; 6484 IS clPoints; 6485 PetscInt *points = NULL; 6486 const PetscInt *clp, *perm = NULL; 6487 PetscInt depth, numFields, numPoints, asize; 6488 6489 PetscFunctionBeginHot; 6490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6491 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6492 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6493 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6494 PetscCall(DMPlexGetDepth(dm, &depth)); 6495 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6496 if (depth == 1 && numFields < 2) { 6497 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6498 PetscFunctionReturn(PETSC_SUCCESS); 6499 } 6500 /* Get points */ 6501 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6502 /* Get sizes */ 6503 asize = 0; 6504 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6505 PetscInt dof; 6506 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6507 asize += dof; 6508 } 6509 if (values) { 6510 const PetscScalar *vArray; 6511 PetscInt size; 6512 6513 if (*values) { 6514 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); 6515 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6516 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6517 PetscCall(VecGetArrayRead(v, &vArray)); 6518 /* Get values */ 6519 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6520 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6521 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6522 /* Cleanup array */ 6523 PetscCall(VecRestoreArrayRead(v, &vArray)); 6524 } 6525 if (csize) *csize = asize; 6526 /* Cleanup points */ 6527 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6528 PetscFunctionReturn(PETSC_SUCCESS); 6529 } 6530 6531 /*@C 6532 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6533 6534 Not collective 6535 6536 Input Parameters: 6537 + dm - The `DM` 6538 . section - The section describing the layout in `v`, or `NULL` to use the default section 6539 . v - The local vector 6540 - point - The point in the `DM` 6541 6542 Input/Output Parameters: 6543 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6544 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6545 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6546 6547 Level: intermediate 6548 6549 Notes: 6550 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6551 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6552 assembly function, and a user may already have allocated storage for this operation. 6553 6554 A typical use could be 6555 .vb 6556 values = NULL; 6557 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6558 for (cl = 0; cl < clSize; ++cl) { 6559 <Compute on closure> 6560 } 6561 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6562 .ve 6563 or 6564 .vb 6565 PetscMalloc1(clMaxSize, &values); 6566 for (p = pStart; p < pEnd; ++p) { 6567 clSize = clMaxSize; 6568 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6569 for (cl = 0; cl < clSize; ++cl) { 6570 <Compute on closure> 6571 } 6572 } 6573 PetscFree(values); 6574 .ve 6575 6576 Fortran Notes: 6577 The `csize` argument is not present in the Fortran binding. 6578 6579 `values` must be declared with 6580 .vb 6581 PetscScalar,dimension(:),pointer :: values 6582 .ve 6583 and it will be allocated internally by PETSc to hold the values returned 6584 6585 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6586 @*/ 6587 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6588 { 6589 PetscFunctionBeginHot; 6590 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6591 PetscFunctionReturn(PETSC_SUCCESS); 6592 } 6593 6594 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6595 { 6596 DMLabel depthLabel; 6597 PetscSection clSection; 6598 IS clPoints; 6599 PetscScalar *array; 6600 const PetscScalar *vArray; 6601 PetscInt *points = NULL; 6602 const PetscInt *clp, *perm = NULL; 6603 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6604 6605 PetscFunctionBeginHot; 6606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6607 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6608 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6609 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6610 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6611 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6612 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6613 if (mdepth == 1 && numFields < 2) { 6614 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6615 PetscFunctionReturn(PETSC_SUCCESS); 6616 } 6617 /* Get points */ 6618 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6619 for (clsize = 0, p = 0; p < Np; p++) { 6620 PetscInt dof; 6621 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6622 clsize += dof; 6623 } 6624 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6625 /* Filter points */ 6626 for (p = 0; p < numPoints * 2; p += 2) { 6627 PetscInt dep; 6628 6629 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6630 if (dep != depth) continue; 6631 points[Np * 2 + 0] = points[p]; 6632 points[Np * 2 + 1] = points[p + 1]; 6633 ++Np; 6634 } 6635 /* Get array */ 6636 if (!values || !*values) { 6637 PetscInt asize = 0, dof; 6638 6639 for (p = 0; p < Np * 2; p += 2) { 6640 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6641 asize += dof; 6642 } 6643 if (!values) { 6644 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6645 if (csize) *csize = asize; 6646 PetscFunctionReturn(PETSC_SUCCESS); 6647 } 6648 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6649 } else { 6650 array = *values; 6651 } 6652 PetscCall(VecGetArrayRead(v, &vArray)); 6653 /* Get values */ 6654 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6655 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6656 /* Cleanup points */ 6657 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6658 /* Cleanup array */ 6659 PetscCall(VecRestoreArrayRead(v, &vArray)); 6660 if (!*values) { 6661 if (csize) *csize = size; 6662 *values = array; 6663 } else { 6664 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6665 *csize = size; 6666 } 6667 PetscFunctionReturn(PETSC_SUCCESS); 6668 } 6669 6670 /*@C 6671 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6672 6673 Not collective 6674 6675 Input Parameters: 6676 + dm - The `DM` 6677 . section - The section describing the layout in `v`, or `NULL` to use the default section 6678 . v - The local vector 6679 . point - The point in the `DM` 6680 . csize - The number of values in the closure, or `NULL` 6681 - values - The array of values 6682 6683 Level: intermediate 6684 6685 Note: 6686 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6687 6688 Fortran Note: 6689 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6690 6691 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6692 @*/ 6693 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6694 { 6695 PetscInt size = 0; 6696 6697 PetscFunctionBegin; 6698 /* Should work without recalculating size */ 6699 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6700 *values = NULL; 6701 PetscFunctionReturn(PETSC_SUCCESS); 6702 } 6703 6704 static inline void add(PetscScalar *x, PetscScalar y) 6705 { 6706 *x += y; 6707 } 6708 static inline void insert(PetscScalar *x, PetscScalar y) 6709 { 6710 *x = y; 6711 } 6712 6713 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[]) 6714 { 6715 PetscInt cdof; /* The number of constraints on this point */ 6716 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6717 PetscScalar *a; 6718 PetscInt off, cind = 0, k; 6719 6720 PetscFunctionBegin; 6721 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6722 PetscCall(PetscSectionGetOffset(section, point, &off)); 6723 a = &array[off]; 6724 if (!cdof || setBC) { 6725 if (clperm) { 6726 if (perm) { 6727 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6728 } else { 6729 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6730 } 6731 } else { 6732 if (perm) { 6733 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6734 } else { 6735 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6736 } 6737 } 6738 } else { 6739 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6740 if (clperm) { 6741 if (perm) { 6742 for (k = 0; k < dof; ++k) { 6743 if ((cind < cdof) && (k == cdofs[cind])) { 6744 ++cind; 6745 continue; 6746 } 6747 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6748 } 6749 } else { 6750 for (k = 0; k < dof; ++k) { 6751 if ((cind < cdof) && (k == cdofs[cind])) { 6752 ++cind; 6753 continue; 6754 } 6755 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6756 } 6757 } 6758 } else { 6759 if (perm) { 6760 for (k = 0; k < dof; ++k) { 6761 if ((cind < cdof) && (k == cdofs[cind])) { 6762 ++cind; 6763 continue; 6764 } 6765 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6766 } 6767 } else { 6768 for (k = 0; k < dof; ++k) { 6769 if ((cind < cdof) && (k == cdofs[cind])) { 6770 ++cind; 6771 continue; 6772 } 6773 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6774 } 6775 } 6776 } 6777 } 6778 PetscFunctionReturn(PETSC_SUCCESS); 6779 } 6780 6781 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[]) 6782 { 6783 PetscInt cdof; /* The number of constraints on this point */ 6784 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6785 PetscScalar *a; 6786 PetscInt off, cind = 0, k; 6787 6788 PetscFunctionBegin; 6789 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6790 PetscCall(PetscSectionGetOffset(section, point, &off)); 6791 a = &array[off]; 6792 if (cdof) { 6793 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6794 if (clperm) { 6795 if (perm) { 6796 for (k = 0; k < dof; ++k) { 6797 if ((cind < cdof) && (k == cdofs[cind])) { 6798 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6799 cind++; 6800 } 6801 } 6802 } else { 6803 for (k = 0; k < dof; ++k) { 6804 if ((cind < cdof) && (k == cdofs[cind])) { 6805 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6806 cind++; 6807 } 6808 } 6809 } 6810 } else { 6811 if (perm) { 6812 for (k = 0; k < dof; ++k) { 6813 if ((cind < cdof) && (k == cdofs[cind])) { 6814 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6815 cind++; 6816 } 6817 } 6818 } else { 6819 for (k = 0; k < dof; ++k) { 6820 if ((cind < cdof) && (k == cdofs[cind])) { 6821 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6822 cind++; 6823 } 6824 } 6825 } 6826 } 6827 } 6828 PetscFunctionReturn(PETSC_SUCCESS); 6829 } 6830 6831 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[]) 6832 { 6833 PetscScalar *a; 6834 PetscInt fdof, foff, fcdof, foffset = *offset; 6835 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6836 PetscInt cind = 0, b; 6837 6838 PetscFunctionBegin; 6839 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6840 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6841 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6842 a = &array[foff]; 6843 if (!fcdof || setBC) { 6844 if (clperm) { 6845 if (perm) { 6846 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6847 } else { 6848 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6849 } 6850 } else { 6851 if (perm) { 6852 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6853 } else { 6854 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6855 } 6856 } 6857 } else { 6858 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6859 if (clperm) { 6860 if (perm) { 6861 for (b = 0; b < fdof; b++) { 6862 if ((cind < fcdof) && (b == fcdofs[cind])) { 6863 ++cind; 6864 continue; 6865 } 6866 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6867 } 6868 } else { 6869 for (b = 0; b < fdof; b++) { 6870 if ((cind < fcdof) && (b == fcdofs[cind])) { 6871 ++cind; 6872 continue; 6873 } 6874 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6875 } 6876 } 6877 } else { 6878 if (perm) { 6879 for (b = 0; b < fdof; b++) { 6880 if ((cind < fcdof) && (b == fcdofs[cind])) { 6881 ++cind; 6882 continue; 6883 } 6884 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6885 } 6886 } else { 6887 for (b = 0; b < fdof; b++) { 6888 if ((cind < fcdof) && (b == fcdofs[cind])) { 6889 ++cind; 6890 continue; 6891 } 6892 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6893 } 6894 } 6895 } 6896 } 6897 *offset += fdof; 6898 PetscFunctionReturn(PETSC_SUCCESS); 6899 } 6900 6901 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[]) 6902 { 6903 PetscScalar *a; 6904 PetscInt fdof, foff, fcdof, foffset = *offset; 6905 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6906 PetscInt Nc, cind = 0, ncind = 0, b; 6907 PetscBool ncSet, fcSet; 6908 6909 PetscFunctionBegin; 6910 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6911 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6912 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6913 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6914 a = &array[foff]; 6915 if (fcdof) { 6916 /* We just override fcdof and fcdofs with Ncc and comps */ 6917 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6918 if (clperm) { 6919 if (perm) { 6920 if (comps) { 6921 for (b = 0; b < fdof; b++) { 6922 ncSet = fcSet = PETSC_FALSE; 6923 if (b % Nc == comps[ncind]) { 6924 ncind = (ncind + 1) % Ncc; 6925 ncSet = PETSC_TRUE; 6926 } 6927 if ((cind < fcdof) && (b == fcdofs[cind])) { 6928 ++cind; 6929 fcSet = PETSC_TRUE; 6930 } 6931 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6932 } 6933 } else { 6934 for (b = 0; b < fdof; b++) { 6935 if ((cind < fcdof) && (b == fcdofs[cind])) { 6936 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6937 ++cind; 6938 } 6939 } 6940 } 6941 } else { 6942 if (comps) { 6943 for (b = 0; b < fdof; b++) { 6944 ncSet = fcSet = PETSC_FALSE; 6945 if (b % Nc == comps[ncind]) { 6946 ncind = (ncind + 1) % Ncc; 6947 ncSet = PETSC_TRUE; 6948 } 6949 if ((cind < fcdof) && (b == fcdofs[cind])) { 6950 ++cind; 6951 fcSet = PETSC_TRUE; 6952 } 6953 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6954 } 6955 } else { 6956 for (b = 0; b < fdof; b++) { 6957 if ((cind < fcdof) && (b == fcdofs[cind])) { 6958 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6959 ++cind; 6960 } 6961 } 6962 } 6963 } 6964 } else { 6965 if (perm) { 6966 if (comps) { 6967 for (b = 0; b < fdof; b++) { 6968 ncSet = fcSet = PETSC_FALSE; 6969 if (b % Nc == comps[ncind]) { 6970 ncind = (ncind + 1) % Ncc; 6971 ncSet = PETSC_TRUE; 6972 } 6973 if ((cind < fcdof) && (b == fcdofs[cind])) { 6974 ++cind; 6975 fcSet = PETSC_TRUE; 6976 } 6977 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6978 } 6979 } else { 6980 for (b = 0; b < fdof; b++) { 6981 if ((cind < fcdof) && (b == fcdofs[cind])) { 6982 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6983 ++cind; 6984 } 6985 } 6986 } 6987 } else { 6988 if (comps) { 6989 for (b = 0; b < fdof; b++) { 6990 ncSet = fcSet = PETSC_FALSE; 6991 if (b % Nc == comps[ncind]) { 6992 ncind = (ncind + 1) % Ncc; 6993 ncSet = PETSC_TRUE; 6994 } 6995 if ((cind < fcdof) && (b == fcdofs[cind])) { 6996 ++cind; 6997 fcSet = PETSC_TRUE; 6998 } 6999 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7000 } 7001 } else { 7002 for (b = 0; b < fdof; b++) { 7003 if ((cind < fcdof) && (b == fcdofs[cind])) { 7004 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7005 ++cind; 7006 } 7007 } 7008 } 7009 } 7010 } 7011 } 7012 *offset += fdof; 7013 PetscFunctionReturn(PETSC_SUCCESS); 7014 } 7015 7016 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7017 { 7018 PetscScalar *array; 7019 const PetscInt *cone, *coneO; 7020 PetscInt pStart, pEnd, p, numPoints, off, dof; 7021 7022 PetscFunctionBeginHot; 7023 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7024 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7025 PetscCall(DMPlexGetCone(dm, point, &cone)); 7026 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7027 PetscCall(VecGetArray(v, &array)); 7028 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7029 const PetscInt cp = !p ? point : cone[p - 1]; 7030 const PetscInt o = !p ? 0 : coneO[p - 1]; 7031 7032 if ((cp < pStart) || (cp >= pEnd)) { 7033 dof = 0; 7034 continue; 7035 } 7036 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7037 /* ADD_VALUES */ 7038 { 7039 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7040 PetscScalar *a; 7041 PetscInt cdof, coff, cind = 0, k; 7042 7043 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7044 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7045 a = &array[coff]; 7046 if (!cdof) { 7047 if (o >= 0) { 7048 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7049 } else { 7050 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7051 } 7052 } else { 7053 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7054 if (o >= 0) { 7055 for (k = 0; k < dof; ++k) { 7056 if ((cind < cdof) && (k == cdofs[cind])) { 7057 ++cind; 7058 continue; 7059 } 7060 a[k] += values[off + k]; 7061 } 7062 } else { 7063 for (k = 0; k < dof; ++k) { 7064 if ((cind < cdof) && (k == cdofs[cind])) { 7065 ++cind; 7066 continue; 7067 } 7068 a[k] += values[off + dof - k - 1]; 7069 } 7070 } 7071 } 7072 } 7073 } 7074 PetscCall(VecRestoreArray(v, &array)); 7075 PetscFunctionReturn(PETSC_SUCCESS); 7076 } 7077 7078 /*@C 7079 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7080 7081 Not collective 7082 7083 Input Parameters: 7084 + dm - The `DM` 7085 . section - The section describing the layout in `v`, or `NULL` to use the default section 7086 . v - The local vector 7087 . point - The point in the `DM` 7088 . values - The array of values 7089 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7090 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7091 7092 Level: intermediate 7093 7094 Note: 7095 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7096 7097 Fortran Note: 7098 `values` must be declared with 7099 .vb 7100 PetscScalar,dimension(:),pointer :: values 7101 .ve 7102 7103 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7104 @*/ 7105 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7106 { 7107 PetscSection clSection; 7108 IS clPoints; 7109 PetscScalar *array; 7110 PetscInt *points = NULL; 7111 const PetscInt *clp, *clperm = NULL; 7112 PetscInt depth, numFields, numPoints, p, clsize; 7113 7114 PetscFunctionBeginHot; 7115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7116 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7117 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7118 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7119 PetscCall(DMPlexGetDepth(dm, &depth)); 7120 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7121 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7122 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7123 PetscFunctionReturn(PETSC_SUCCESS); 7124 } 7125 /* Get points */ 7126 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7127 for (clsize = 0, p = 0; p < numPoints; p++) { 7128 PetscInt dof; 7129 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7130 clsize += dof; 7131 } 7132 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7133 /* Get array */ 7134 PetscCall(VecGetArray(v, &array)); 7135 /* Get values */ 7136 if (numFields > 0) { 7137 PetscInt offset = 0, f; 7138 for (f = 0; f < numFields; ++f) { 7139 const PetscInt **perms = NULL; 7140 const PetscScalar **flips = NULL; 7141 7142 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7143 switch (mode) { 7144 case INSERT_VALUES: 7145 for (p = 0; p < numPoints; p++) { 7146 const PetscInt point = points[2 * p]; 7147 const PetscInt *perm = perms ? perms[p] : NULL; 7148 const PetscScalar *flip = flips ? flips[p] : NULL; 7149 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7150 } 7151 break; 7152 case INSERT_ALL_VALUES: 7153 for (p = 0; p < numPoints; p++) { 7154 const PetscInt point = points[2 * p]; 7155 const PetscInt *perm = perms ? perms[p] : NULL; 7156 const PetscScalar *flip = flips ? flips[p] : NULL; 7157 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7158 } 7159 break; 7160 case INSERT_BC_VALUES: 7161 for (p = 0; p < numPoints; p++) { 7162 const PetscInt point = points[2 * p]; 7163 const PetscInt *perm = perms ? perms[p] : NULL; 7164 const PetscScalar *flip = flips ? flips[p] : NULL; 7165 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7166 } 7167 break; 7168 case ADD_VALUES: 7169 for (p = 0; p < numPoints; p++) { 7170 const PetscInt point = points[2 * p]; 7171 const PetscInt *perm = perms ? perms[p] : NULL; 7172 const PetscScalar *flip = flips ? flips[p] : NULL; 7173 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7174 } 7175 break; 7176 case ADD_ALL_VALUES: 7177 for (p = 0; p < numPoints; p++) { 7178 const PetscInt point = points[2 * p]; 7179 const PetscInt *perm = perms ? perms[p] : NULL; 7180 const PetscScalar *flip = flips ? flips[p] : NULL; 7181 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7182 } 7183 break; 7184 case ADD_BC_VALUES: 7185 for (p = 0; p < numPoints; p++) { 7186 const PetscInt point = points[2 * p]; 7187 const PetscInt *perm = perms ? perms[p] : NULL; 7188 const PetscScalar *flip = flips ? flips[p] : NULL; 7189 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7190 } 7191 break; 7192 default: 7193 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7194 } 7195 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7196 } 7197 } else { 7198 PetscInt dof, off; 7199 const PetscInt **perms = NULL; 7200 const PetscScalar **flips = NULL; 7201 7202 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7203 switch (mode) { 7204 case INSERT_VALUES: 7205 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7206 const PetscInt point = points[2 * p]; 7207 const PetscInt *perm = perms ? perms[p] : NULL; 7208 const PetscScalar *flip = flips ? flips[p] : NULL; 7209 PetscCall(PetscSectionGetDof(section, point, &dof)); 7210 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7211 } 7212 break; 7213 case INSERT_ALL_VALUES: 7214 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7215 const PetscInt point = points[2 * p]; 7216 const PetscInt *perm = perms ? perms[p] : NULL; 7217 const PetscScalar *flip = flips ? flips[p] : NULL; 7218 PetscCall(PetscSectionGetDof(section, point, &dof)); 7219 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7220 } 7221 break; 7222 case INSERT_BC_VALUES: 7223 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7224 const PetscInt point = points[2 * p]; 7225 const PetscInt *perm = perms ? perms[p] : NULL; 7226 const PetscScalar *flip = flips ? flips[p] : NULL; 7227 PetscCall(PetscSectionGetDof(section, point, &dof)); 7228 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7229 } 7230 break; 7231 case ADD_VALUES: 7232 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7233 const PetscInt point = points[2 * p]; 7234 const PetscInt *perm = perms ? perms[p] : NULL; 7235 const PetscScalar *flip = flips ? flips[p] : NULL; 7236 PetscCall(PetscSectionGetDof(section, point, &dof)); 7237 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7238 } 7239 break; 7240 case ADD_ALL_VALUES: 7241 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7242 const PetscInt point = points[2 * p]; 7243 const PetscInt *perm = perms ? perms[p] : NULL; 7244 const PetscScalar *flip = flips ? flips[p] : NULL; 7245 PetscCall(PetscSectionGetDof(section, point, &dof)); 7246 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7247 } 7248 break; 7249 case ADD_BC_VALUES: 7250 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7251 const PetscInt point = points[2 * p]; 7252 const PetscInt *perm = perms ? perms[p] : NULL; 7253 const PetscScalar *flip = flips ? flips[p] : NULL; 7254 PetscCall(PetscSectionGetDof(section, point, &dof)); 7255 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7256 } 7257 break; 7258 default: 7259 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7260 } 7261 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7262 } 7263 /* Cleanup points */ 7264 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7265 /* Cleanup array */ 7266 PetscCall(VecRestoreArray(v, &array)); 7267 PetscFunctionReturn(PETSC_SUCCESS); 7268 } 7269 7270 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7271 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7272 { 7273 PetscFunctionBegin; 7274 *contains = PETSC_TRUE; 7275 if (label) { 7276 PetscInt fdof; 7277 7278 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7279 if (!*contains) { 7280 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7281 *offset += fdof; 7282 PetscFunctionReturn(PETSC_SUCCESS); 7283 } 7284 } 7285 PetscFunctionReturn(PETSC_SUCCESS); 7286 } 7287 7288 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7289 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) 7290 { 7291 PetscSection clSection; 7292 IS clPoints; 7293 PetscScalar *array; 7294 PetscInt *points = NULL; 7295 const PetscInt *clp; 7296 PetscInt numFields, numPoints, p; 7297 PetscInt offset = 0, f; 7298 7299 PetscFunctionBeginHot; 7300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7301 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7302 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7303 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7304 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7305 /* Get points */ 7306 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7307 /* Get array */ 7308 PetscCall(VecGetArray(v, &array)); 7309 /* Get values */ 7310 for (f = 0; f < numFields; ++f) { 7311 const PetscInt **perms = NULL; 7312 const PetscScalar **flips = NULL; 7313 PetscBool contains; 7314 7315 if (!fieldActive[f]) { 7316 for (p = 0; p < numPoints * 2; p += 2) { 7317 PetscInt fdof; 7318 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7319 offset += fdof; 7320 } 7321 continue; 7322 } 7323 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7324 switch (mode) { 7325 case INSERT_VALUES: 7326 for (p = 0; p < numPoints; p++) { 7327 const PetscInt point = points[2 * p]; 7328 const PetscInt *perm = perms ? perms[p] : NULL; 7329 const PetscScalar *flip = flips ? flips[p] : NULL; 7330 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7331 if (!contains) continue; 7332 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7333 } 7334 break; 7335 case INSERT_ALL_VALUES: 7336 for (p = 0; p < numPoints; p++) { 7337 const PetscInt point = points[2 * p]; 7338 const PetscInt *perm = perms ? perms[p] : NULL; 7339 const PetscScalar *flip = flips ? flips[p] : NULL; 7340 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7341 if (!contains) continue; 7342 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7343 } 7344 break; 7345 case INSERT_BC_VALUES: 7346 for (p = 0; p < numPoints; p++) { 7347 const PetscInt point = points[2 * p]; 7348 const PetscInt *perm = perms ? perms[p] : NULL; 7349 const PetscScalar *flip = flips ? flips[p] : NULL; 7350 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7351 if (!contains) continue; 7352 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7353 } 7354 break; 7355 case ADD_VALUES: 7356 for (p = 0; p < numPoints; p++) { 7357 const PetscInt point = points[2 * p]; 7358 const PetscInt *perm = perms ? perms[p] : NULL; 7359 const PetscScalar *flip = flips ? flips[p] : NULL; 7360 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7361 if (!contains) continue; 7362 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7363 } 7364 break; 7365 case ADD_ALL_VALUES: 7366 for (p = 0; p < numPoints; p++) { 7367 const PetscInt point = points[2 * p]; 7368 const PetscInt *perm = perms ? perms[p] : NULL; 7369 const PetscScalar *flip = flips ? flips[p] : NULL; 7370 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7371 if (!contains) continue; 7372 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7373 } 7374 break; 7375 default: 7376 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7377 } 7378 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7379 } 7380 /* Cleanup points */ 7381 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7382 /* Cleanup array */ 7383 PetscCall(VecRestoreArray(v, &array)); 7384 PetscFunctionReturn(PETSC_SUCCESS); 7385 } 7386 7387 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7388 { 7389 PetscMPIInt rank; 7390 PetscInt i, j; 7391 7392 PetscFunctionBegin; 7393 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7394 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7395 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7396 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7397 numCIndices = numCIndices ? numCIndices : numRIndices; 7398 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7399 for (i = 0; i < numRIndices; i++) { 7400 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7401 for (j = 0; j < numCIndices; j++) { 7402 #if defined(PETSC_USE_COMPLEX) 7403 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7404 #else 7405 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7406 #endif 7407 } 7408 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7409 } 7410 PetscFunctionReturn(PETSC_SUCCESS); 7411 } 7412 7413 /* 7414 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7415 7416 Input Parameters: 7417 + section - The section for this data layout 7418 . islocal - Is the section (and thus indices being requested) local or global? 7419 . point - The point contributing dofs with these indices 7420 . off - The global offset of this point 7421 . loff - The local offset of each field 7422 . setBC - The flag determining whether to include indices of boundary values 7423 . perm - A permutation of the dofs on this point, or NULL 7424 - indperm - A permutation of the entire indices array, or NULL 7425 7426 Output Parameter: 7427 . indices - Indices for dofs on this point 7428 7429 Level: developer 7430 7431 Note: The indices could be local or global, depending on the value of 'off'. 7432 */ 7433 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7434 { 7435 PetscInt dof; /* The number of unknowns on this point */ 7436 PetscInt cdof; /* The number of constraints on this point */ 7437 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7438 PetscInt cind = 0, k; 7439 7440 PetscFunctionBegin; 7441 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7442 PetscCall(PetscSectionGetDof(section, point, &dof)); 7443 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7444 if (!cdof || setBC) { 7445 for (k = 0; k < dof; ++k) { 7446 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7447 const PetscInt ind = indperm ? indperm[preind] : preind; 7448 7449 indices[ind] = off + k; 7450 } 7451 } else { 7452 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7453 for (k = 0; k < dof; ++k) { 7454 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7455 const PetscInt ind = indperm ? indperm[preind] : preind; 7456 7457 if ((cind < cdof) && (k == cdofs[cind])) { 7458 /* Insert check for returning constrained indices */ 7459 indices[ind] = -(off + k + 1); 7460 ++cind; 7461 } else { 7462 indices[ind] = off + k - (islocal ? 0 : cind); 7463 } 7464 } 7465 } 7466 *loff += dof; 7467 PetscFunctionReturn(PETSC_SUCCESS); 7468 } 7469 7470 /* 7471 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7472 7473 Input Parameters: 7474 + section - a section (global or local) 7475 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7476 . point - point within section 7477 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7478 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7479 . setBC - identify constrained (boundary condition) points via involution. 7480 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7481 . permsoff - offset 7482 - indperm - index permutation 7483 7484 Output Parameter: 7485 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7486 . indices - array to hold indices (as defined by section) of each dof associated with point 7487 7488 Notes: 7489 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7490 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7491 in the local vector. 7492 7493 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7494 significant). It is invalid to call with a global section and setBC=true. 7495 7496 Developer Note: 7497 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7498 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7499 offset could be obtained from the section instead of passing it explicitly as we do now. 7500 7501 Example: 7502 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7503 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7504 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7505 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. 7506 7507 Level: developer 7508 */ 7509 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[]) 7510 { 7511 PetscInt numFields, foff, f; 7512 7513 PetscFunctionBegin; 7514 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7515 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7516 for (f = 0, foff = 0; f < numFields; ++f) { 7517 PetscInt fdof, cfdof; 7518 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7519 PetscInt cind = 0, b; 7520 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7521 7522 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7523 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7524 if (!cfdof || setBC) { 7525 for (b = 0; b < fdof; ++b) { 7526 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7527 const PetscInt ind = indperm ? indperm[preind] : preind; 7528 7529 indices[ind] = off + foff + b; 7530 } 7531 } else { 7532 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7533 for (b = 0; b < fdof; ++b) { 7534 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7535 const PetscInt ind = indperm ? indperm[preind] : preind; 7536 7537 if ((cind < cfdof) && (b == fcdofs[cind])) { 7538 indices[ind] = -(off + foff + b + 1); 7539 ++cind; 7540 } else { 7541 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7542 } 7543 } 7544 } 7545 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7546 foffs[f] += fdof; 7547 } 7548 PetscFunctionReturn(PETSC_SUCCESS); 7549 } 7550 7551 /* 7552 This version believes the globalSection offsets for each field, rather than just the point offset 7553 7554 . foffs - The offset into 'indices' for each field, since it is segregated by field 7555 7556 Notes: 7557 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7558 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7559 */ 7560 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7561 { 7562 PetscInt numFields, foff, f; 7563 7564 PetscFunctionBegin; 7565 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7566 for (f = 0; f < numFields; ++f) { 7567 PetscInt fdof, cfdof; 7568 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7569 PetscInt cind = 0, b; 7570 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7571 7572 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7573 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7574 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7575 if (!cfdof) { 7576 for (b = 0; b < fdof; ++b) { 7577 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7578 const PetscInt ind = indperm ? indperm[preind] : preind; 7579 7580 indices[ind] = foff + b; 7581 } 7582 } else { 7583 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7584 for (b = 0; b < fdof; ++b) { 7585 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7586 const PetscInt ind = indperm ? indperm[preind] : preind; 7587 7588 if ((cind < cfdof) && (b == fcdofs[cind])) { 7589 indices[ind] = -(foff + b + 1); 7590 ++cind; 7591 } else { 7592 indices[ind] = foff + b - cind; 7593 } 7594 } 7595 } 7596 foffs[f] += fdof; 7597 } 7598 PetscFunctionReturn(PETSC_SUCCESS); 7599 } 7600 7601 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7602 { 7603 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7604 7605 PetscFunctionBegin; 7606 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7607 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7608 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7609 for (PetscInt p = 0; p < nPoints; p++) { 7610 PetscInt b = pnts[2 * p]; 7611 PetscInt bSecDof = 0, bOff; 7612 PetscInt cSecDof = 0; 7613 PetscSection indices_section; 7614 7615 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7616 if (!bSecDof) continue; 7617 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7618 indices_section = cSecDof > 0 ? cSec : section; 7619 if (numFields) { 7620 PetscInt fStart[32], fEnd[32]; 7621 7622 fStart[0] = 0; 7623 fEnd[0] = 0; 7624 for (PetscInt f = 0; f < numFields; f++) { 7625 PetscInt fDof = 0; 7626 7627 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7628 fStart[f + 1] = fStart[f] + fDof; 7629 fEnd[f + 1] = fStart[f + 1]; 7630 } 7631 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7632 // only apply permutations on one side 7633 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7634 for (PetscInt f = 0; f < numFields; f++) { 7635 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7636 } 7637 } else { 7638 PetscInt bEnd = 0; 7639 7640 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7641 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7642 7643 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7644 } 7645 } 7646 PetscFunctionReturn(PETSC_SUCCESS); 7647 } 7648 7649 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[]) 7650 { 7651 Mat cMat; 7652 PetscSection aSec, cSec; 7653 IS aIS; 7654 PetscInt aStart = -1, aEnd = -1; 7655 PetscInt sStart = -1, sEnd = -1; 7656 PetscInt cStart = -1, cEnd = -1; 7657 const PetscInt *anchors; 7658 PetscInt numFields, p; 7659 PetscInt newNumPoints = 0, newNumIndices = 0; 7660 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7661 PetscInt oldOffsets[32]; 7662 PetscInt newOffsets[32]; 7663 PetscInt oldOffsetsCopy[32]; 7664 PetscInt newOffsetsCopy[32]; 7665 PetscScalar *modMat = NULL; 7666 PetscBool anyConstrained = PETSC_FALSE; 7667 7668 PetscFunctionBegin; 7669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7670 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7671 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7672 7673 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7674 /* if there are point-to-point constraints */ 7675 if (aSec) { 7676 PetscCall(PetscArrayzero(newOffsets, 32)); 7677 PetscCall(PetscArrayzero(oldOffsets, 32)); 7678 PetscCall(ISGetIndices(aIS, &anchors)); 7679 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7680 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7681 /* figure out how many points are going to be in the new element matrix 7682 * (we allow double counting, because it's all just going to be summed 7683 * into the global matrix anyway) */ 7684 for (p = 0; p < 2 * numPoints; p += 2) { 7685 PetscInt b = points[p]; 7686 PetscInt bDof = 0, bSecDof = 0; 7687 7688 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7689 if (!bSecDof) continue; 7690 7691 for (PetscInt f = 0; f < numFields; f++) { 7692 PetscInt fDof = 0; 7693 7694 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7695 oldOffsets[f + 1] += fDof; 7696 } 7697 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7698 if (bDof) { 7699 /* this point is constrained */ 7700 /* it is going to be replaced by its anchors */ 7701 PetscInt bOff, q; 7702 7703 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7704 for (q = 0; q < bDof; q++) { 7705 PetscInt a = anchors[bOff + q]; 7706 PetscInt aDof = 0; 7707 7708 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7709 if (aDof) { 7710 anyConstrained = PETSC_TRUE; 7711 newNumPoints += 1; 7712 } 7713 newNumIndices += aDof; 7714 for (PetscInt f = 0; f < numFields; ++f) { 7715 PetscInt fDof = 0; 7716 7717 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7718 newOffsets[f + 1] += fDof; 7719 } 7720 } 7721 } else { 7722 /* this point is not constrained */ 7723 newNumPoints++; 7724 newNumIndices += bSecDof; 7725 for (PetscInt f = 0; f < numFields; ++f) { 7726 PetscInt fDof; 7727 7728 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7729 newOffsets[f + 1] += fDof; 7730 } 7731 } 7732 } 7733 } 7734 if (!anyConstrained) { 7735 if (outNumPoints) *outNumPoints = 0; 7736 if (outNumIndices) *outNumIndices = 0; 7737 if (outPoints) *outPoints = NULL; 7738 if (outMat) *outMat = NULL; 7739 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7740 PetscFunctionReturn(PETSC_SUCCESS); 7741 } 7742 7743 if (outNumPoints) *outNumPoints = newNumPoints; 7744 if (outNumIndices) *outNumIndices = newNumIndices; 7745 7746 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7747 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7748 7749 if (!outPoints && !outMat) { 7750 if (offsets) { 7751 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7752 } 7753 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7754 PetscFunctionReturn(PETSC_SUCCESS); 7755 } 7756 7757 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7758 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7759 7760 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7761 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7762 7763 /* output arrays */ 7764 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7765 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7766 7767 // get the new Points 7768 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7769 PetscInt b = points[2 * p]; 7770 PetscInt bDof = 0, bSecDof = 0, bOff; 7771 7772 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7773 if (!bSecDof) continue; 7774 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7775 if (bDof) { 7776 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7777 for (PetscInt q = 0; q < bDof; q++) { 7778 PetscInt a = anchors[bOff + q], aDof = 0; 7779 7780 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7781 if (aDof) { 7782 newPoints[2 * newP] = a; 7783 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7784 newP++; 7785 } 7786 } 7787 } else { 7788 newPoints[2 * newP] = b; 7789 newPoints[2 * newP + 1] = points[2 * p + 1]; 7790 newP++; 7791 } 7792 } 7793 7794 if (outMat) { 7795 PetscScalar *tmpMat; 7796 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7797 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7798 7799 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7800 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7801 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7802 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7803 7804 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7805 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7806 7807 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7808 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7809 7810 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7811 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7812 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7813 // for each field, insert the anchor modification into modMat 7814 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7815 PetscInt fStart = oldOffsets[f]; 7816 PetscInt fNewStart = newOffsets[f]; 7817 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7818 PetscInt b = points[2 * p]; 7819 PetscInt bDof = 0, bSecDof = 0, bOff; 7820 7821 if (b >= sStart && b < sEnd) { 7822 if (numFields) { 7823 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7824 } else { 7825 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7826 } 7827 } 7828 if (!bSecDof) continue; 7829 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7830 if (bDof) { 7831 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7832 for (PetscInt q = 0; q < bDof; q++, newP++) { 7833 PetscInt a = anchors[bOff + q], aDof = 0; 7834 7835 if (a >= sStart && a < sEnd) { 7836 if (numFields) { 7837 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7838 } else { 7839 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7840 } 7841 } 7842 if (aDof) { 7843 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7844 for (PetscInt d = 0; d < bSecDof; d++) { 7845 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7846 } 7847 } 7848 oNew += aDof; 7849 } 7850 } else { 7851 // Insert the identity matrix in this block 7852 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7853 oNew += bSecDof; 7854 newP++; 7855 } 7856 o += bSecDof; 7857 } 7858 } 7859 7860 *outMat = modMat; 7861 7862 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7863 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7864 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7865 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7866 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7867 } 7868 PetscCall(ISRestoreIndices(aIS, &anchors)); 7869 7870 /* output */ 7871 if (outPoints) { 7872 *outPoints = newPoints; 7873 } else { 7874 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7875 } 7876 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7877 PetscFunctionReturn(PETSC_SUCCESS); 7878 } 7879 7880 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) 7881 { 7882 PetscScalar *modMat = NULL; 7883 PetscInt newNumIndices = -1; 7884 7885 PetscFunctionBegin; 7886 /* 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. 7887 modMat is that matrix C */ 7888 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7889 if (outNumIndices) *outNumIndices = newNumIndices; 7890 if (modMat) { 7891 const PetscScalar *newValues = values; 7892 7893 if (multiplyRight) { 7894 PetscScalar *newNewValues = NULL; 7895 PetscBLASInt M, N, K; 7896 PetscScalar a = 1.0, b = 0.0; 7897 7898 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); 7899 7900 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7901 PetscCall(PetscBLASIntCast(numRows, &N)); 7902 PetscCall(PetscBLASIntCast(numIndices, &K)); 7903 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7904 // row-major to column-major conversion, right multiplication becomes left multiplication 7905 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7906 numCols = newNumIndices; 7907 newValues = newNewValues; 7908 } 7909 7910 if (multiplyLeft) { 7911 PetscScalar *newNewValues = NULL; 7912 PetscBLASInt M, N, K; 7913 PetscScalar a = 1.0, b = 0.0; 7914 7915 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); 7916 7917 PetscCall(PetscBLASIntCast(numCols, &M)); 7918 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7919 PetscCall(PetscBLASIntCast(numIndices, &K)); 7920 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7921 // row-major to column-major conversion, left multiplication becomes right multiplication 7922 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7923 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7924 newValues = newNewValues; 7925 } 7926 *outValues = (PetscScalar *)newValues; 7927 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7928 } 7929 PetscFunctionReturn(PETSC_SUCCESS); 7930 } 7931 7932 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) 7933 { 7934 PetscFunctionBegin; 7935 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7936 PetscFunctionReturn(PETSC_SUCCESS); 7937 } 7938 7939 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7940 { 7941 /* Closure ordering */ 7942 PetscSection clSection; 7943 IS clPoints; 7944 const PetscInt *clp; 7945 PetscInt *points; 7946 PetscInt Ncl, Ni = 0; 7947 7948 PetscFunctionBeginHot; 7949 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7950 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7951 PetscInt dof; 7952 7953 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7954 Ni += dof; 7955 } 7956 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7957 *closureSize = Ni; 7958 PetscFunctionReturn(PETSC_SUCCESS); 7959 } 7960 7961 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) 7962 { 7963 /* Closure ordering */ 7964 PetscSection clSection; 7965 IS clPoints; 7966 const PetscInt *clp; 7967 PetscInt *points; 7968 const PetscInt *clperm = NULL; 7969 /* Dof permutation and sign flips */ 7970 const PetscInt **perms[32] = {NULL}; 7971 const PetscScalar **flips[32] = {NULL}; 7972 PetscScalar *valCopy = NULL; 7973 /* Hanging node constraints */ 7974 PetscInt *pointsC = NULL; 7975 PetscScalar *valuesC = NULL; 7976 PetscInt NclC, NiC; 7977 7978 PetscInt *idx; 7979 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7980 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7981 PetscInt idxStart, idxEnd; 7982 PetscInt nRows, nCols; 7983 7984 PetscFunctionBeginHot; 7985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7986 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7987 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7988 PetscAssertPointer(numRows, 6); 7989 PetscAssertPointer(numCols, 7); 7990 if (indices) PetscAssertPointer(indices, 8); 7991 if (outOffsets) PetscAssertPointer(outOffsets, 9); 7992 if (values) PetscAssertPointer(values, 10); 7993 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7994 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7995 PetscCall(PetscArrayzero(offsets, 32)); 7996 /* 1) Get points in closure */ 7997 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7998 if (useClPerm) { 7999 PetscInt depth, clsize; 8000 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8001 for (clsize = 0, p = 0; p < Ncl; p++) { 8002 PetscInt dof; 8003 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8004 clsize += dof; 8005 } 8006 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8007 } 8008 /* 2) Get number of indices on these points and field offsets from section */ 8009 for (p = 0; p < Ncl * 2; p += 2) { 8010 PetscInt dof, fdof; 8011 8012 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8013 for (f = 0; f < Nf; ++f) { 8014 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8015 offsets[f + 1] += fdof; 8016 } 8017 Ni += dof; 8018 } 8019 if (*numRows == -1) *numRows = Ni; 8020 if (*numCols == -1) *numCols = Ni; 8021 nRows = *numRows; 8022 nCols = *numCols; 8023 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8024 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8025 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8026 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8027 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8028 for (f = 0; f < PetscMax(1, Nf); ++f) { 8029 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8030 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8031 /* may need to apply sign changes to the element matrix */ 8032 if (values && flips[f]) { 8033 PetscInt foffset = offsets[f]; 8034 8035 for (p = 0; p < Ncl; ++p) { 8036 PetscInt pnt = points[2 * p], fdof; 8037 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8038 8039 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8040 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8041 if (flip) { 8042 PetscInt i, j, k; 8043 8044 if (!valCopy) { 8045 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8046 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8047 *values = valCopy; 8048 } 8049 for (i = 0; i < fdof; ++i) { 8050 PetscScalar fval = flip[i]; 8051 8052 if (multiplyRight) { 8053 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8054 } 8055 if (multiplyLeft) { 8056 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8057 } 8058 } 8059 } 8060 foffset += fdof; 8061 } 8062 } 8063 } 8064 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8065 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8066 if (NclC) { 8067 if (multiplyRight) *numCols = NiC; 8068 if (multiplyLeft) *numRows = NiC; 8069 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8070 for (f = 0; f < PetscMax(1, Nf); ++f) { 8071 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8072 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8073 } 8074 for (f = 0; f < PetscMax(1, Nf); ++f) { 8075 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8076 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8077 } 8078 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8079 Ncl = NclC; 8080 Ni = NiC; 8081 points = pointsC; 8082 if (values) *values = valuesC; 8083 } 8084 /* 5) Calculate indices */ 8085 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8086 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8087 if (Nf) { 8088 PetscInt idxOff; 8089 PetscBool useFieldOffsets; 8090 8091 if (outOffsets) { 8092 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8093 } 8094 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8095 if (useFieldOffsets) { 8096 for (p = 0; p < Ncl; ++p) { 8097 const PetscInt pnt = points[p * 2]; 8098 8099 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8100 } 8101 } else { 8102 for (p = 0; p < Ncl; ++p) { 8103 const PetscInt pnt = points[p * 2]; 8104 8105 if (pnt < idxStart || pnt >= idxEnd) continue; 8106 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8107 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8108 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8109 * global section. */ 8110 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8111 } 8112 } 8113 } else { 8114 PetscInt off = 0, idxOff; 8115 8116 for (p = 0; p < Ncl; ++p) { 8117 const PetscInt pnt = points[p * 2]; 8118 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8119 8120 if (pnt < idxStart || pnt >= idxEnd) continue; 8121 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8122 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8123 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8124 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8125 } 8126 } 8127 /* 6) Cleanup */ 8128 for (f = 0; f < PetscMax(1, Nf); ++f) { 8129 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8130 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8131 } 8132 if (NclC) { 8133 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8134 } else { 8135 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8136 } 8137 8138 if (indices) *indices = idx; 8139 PetscFunctionReturn(PETSC_SUCCESS); 8140 } 8141 8142 /*@C 8143 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8144 8145 Not collective 8146 8147 Input Parameters: 8148 + dm - The `DM` 8149 . section - The `PetscSection` describing the points (a local section) 8150 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8151 . point - The point defining the closure 8152 - useClPerm - Use the closure point permutation if available 8153 8154 Output Parameters: 8155 + numIndices - The number of dof indices in the closure of point with the input sections 8156 . indices - The dof indices 8157 . outOffsets - Array to write the field offsets into, or `NULL` 8158 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8159 8160 Level: advanced 8161 8162 Notes: 8163 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8164 8165 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8166 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8167 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8168 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8169 indices (with the above semantics) are implied. 8170 8171 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8172 `PetscSection`, `DMGetGlobalSection()` 8173 @*/ 8174 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8175 { 8176 PetscInt numRows = -1, numCols = -1; 8177 8178 PetscFunctionBeginHot; 8179 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8180 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8181 *numIndices = numRows; 8182 PetscFunctionReturn(PETSC_SUCCESS); 8183 } 8184 8185 /*@C 8186 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8187 8188 Not collective 8189 8190 Input Parameters: 8191 + dm - The `DM` 8192 . section - The `PetscSection` describing the points (a local section) 8193 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8194 . point - The point defining the closure 8195 - useClPerm - Use the closure point permutation if available 8196 8197 Output Parameters: 8198 + numIndices - The number of dof indices in the closure of point with the input sections 8199 . indices - The dof indices 8200 . outOffsets - Array to write the field offsets into, or `NULL` 8201 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8202 8203 Level: advanced 8204 8205 Notes: 8206 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8207 8208 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8209 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8210 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8211 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8212 indices (with the above semantics) are implied. 8213 8214 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8215 @*/ 8216 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8217 { 8218 PetscFunctionBegin; 8219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8220 PetscAssertPointer(indices, 7); 8221 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8222 PetscFunctionReturn(PETSC_SUCCESS); 8223 } 8224 8225 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8226 { 8227 DM_Plex *mesh = (DM_Plex *)dm->data; 8228 PetscInt *indices; 8229 PetscInt numIndices; 8230 const PetscScalar *valuesOrig = values; 8231 PetscErrorCode ierr; 8232 8233 PetscFunctionBegin; 8234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8235 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8236 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8237 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8238 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8239 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8240 8241 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8242 8243 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8244 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8245 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8246 if (ierr) { 8247 PetscMPIInt rank; 8248 8249 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8250 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8251 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8252 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8253 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8254 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8255 } 8256 if (mesh->printFEM > 1) { 8257 PetscInt i; 8258 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8259 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8260 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8261 } 8262 8263 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8264 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8265 PetscFunctionReturn(PETSC_SUCCESS); 8266 } 8267 8268 /*@C 8269 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8270 8271 Not collective 8272 8273 Input Parameters: 8274 + dm - The `DM` 8275 . section - The section describing the layout in `v`, or `NULL` to use the default section 8276 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8277 . A - The matrix 8278 . point - The point in the `DM` 8279 . values - The array of values 8280 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8281 8282 Level: intermediate 8283 8284 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8285 @*/ 8286 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8287 { 8288 PetscFunctionBegin; 8289 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8290 PetscFunctionReturn(PETSC_SUCCESS); 8291 } 8292 8293 /*@C 8294 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8295 8296 Not collective 8297 8298 Input Parameters: 8299 + dmRow - The `DM` for the row fields 8300 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8301 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8302 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8303 . dmCol - The `DM` for the column fields 8304 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8305 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8306 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8307 . A - The matrix 8308 . point - The point in the `DM` 8309 . values - The array of values 8310 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8311 8312 Level: intermediate 8313 8314 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8315 @*/ 8316 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) 8317 { 8318 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8319 PetscInt *indicesRow, *indicesCol; 8320 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8321 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8322 8323 PetscErrorCode ierr; 8324 8325 PetscFunctionBegin; 8326 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8327 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8328 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8329 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8330 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8331 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8332 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8333 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8334 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8335 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8336 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8337 8338 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8339 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8340 valuesV1 = valuesV0; 8341 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8342 valuesV2 = valuesV1; 8343 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8344 8345 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8346 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8347 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8348 if (ierr) { 8349 PetscMPIInt rank; 8350 8351 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8352 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8353 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8354 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8355 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8356 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8357 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8358 } 8359 8360 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8361 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8362 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8363 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8364 PetscFunctionReturn(PETSC_SUCCESS); 8365 } 8366 8367 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8368 { 8369 DM_Plex *mesh = (DM_Plex *)dmf->data; 8370 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8371 PetscInt *cpoints = NULL; 8372 PetscInt *findices, *cindices; 8373 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8374 PetscInt foffsets[32], coffsets[32]; 8375 DMPolytopeType ct; 8376 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8377 PetscErrorCode ierr; 8378 8379 PetscFunctionBegin; 8380 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8381 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8382 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8383 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8384 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8385 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8386 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8387 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8388 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8389 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8390 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8391 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8392 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8393 PetscCall(PetscArrayzero(foffsets, 32)); 8394 PetscCall(PetscArrayzero(coffsets, 32)); 8395 /* Column indices */ 8396 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8397 maxFPoints = numCPoints; 8398 /* Compress out points not in the section */ 8399 /* TODO: Squeeze out points with 0 dof as well */ 8400 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8401 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8402 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8403 cpoints[q * 2] = cpoints[p]; 8404 cpoints[q * 2 + 1] = cpoints[p + 1]; 8405 ++q; 8406 } 8407 } 8408 numCPoints = q; 8409 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8410 PetscInt fdof; 8411 8412 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8413 if (!dof) continue; 8414 for (f = 0; f < numFields; ++f) { 8415 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8416 coffsets[f + 1] += fdof; 8417 } 8418 numCIndices += dof; 8419 } 8420 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8421 /* Row indices */ 8422 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8423 { 8424 DMPlexTransform tr; 8425 DMPolytopeType *rct; 8426 PetscInt *rsize, *rcone, *rornt, Nt; 8427 8428 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8429 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8430 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8431 numSubcells = rsize[Nt - 1]; 8432 PetscCall(DMPlexTransformDestroy(&tr)); 8433 } 8434 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8435 for (r = 0, q = 0; r < numSubcells; ++r) { 8436 /* TODO Map from coarse to fine cells */ 8437 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8438 /* Compress out points not in the section */ 8439 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8440 for (p = 0; p < numFPoints * 2; p += 2) { 8441 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8442 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8443 if (!dof) continue; 8444 for (s = 0; s < q; ++s) 8445 if (fpoints[p] == ftotpoints[s * 2]) break; 8446 if (s < q) continue; 8447 ftotpoints[q * 2] = fpoints[p]; 8448 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8449 ++q; 8450 } 8451 } 8452 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8453 } 8454 numFPoints = q; 8455 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8456 PetscInt fdof; 8457 8458 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8459 if (!dof) continue; 8460 for (f = 0; f < numFields; ++f) { 8461 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8462 foffsets[f + 1] += fdof; 8463 } 8464 numFIndices += dof; 8465 } 8466 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8467 8468 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8469 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8470 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8471 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8472 if (numFields) { 8473 const PetscInt **permsF[32] = {NULL}; 8474 const PetscInt **permsC[32] = {NULL}; 8475 8476 for (f = 0; f < numFields; f++) { 8477 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8478 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8479 } 8480 for (p = 0; p < numFPoints; p++) { 8481 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8482 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8483 } 8484 for (p = 0; p < numCPoints; p++) { 8485 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8486 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8487 } 8488 for (f = 0; f < numFields; f++) { 8489 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8490 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8491 } 8492 } else { 8493 const PetscInt **permsF = NULL; 8494 const PetscInt **permsC = NULL; 8495 8496 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8497 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8498 for (p = 0, off = 0; p < numFPoints; p++) { 8499 const PetscInt *perm = permsF ? permsF[p] : NULL; 8500 8501 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8502 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8503 } 8504 for (p = 0, off = 0; p < numCPoints; p++) { 8505 const PetscInt *perm = permsC ? permsC[p] : NULL; 8506 8507 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8508 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8509 } 8510 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8511 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8512 } 8513 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8514 /* TODO: flips */ 8515 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8516 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8517 if (ierr) { 8518 PetscMPIInt rank; 8519 8520 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8521 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8522 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8523 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8524 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8525 } 8526 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8527 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8528 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8529 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8530 PetscFunctionReturn(PETSC_SUCCESS); 8531 } 8532 8533 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8534 { 8535 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8536 PetscInt *cpoints = NULL; 8537 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8538 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8539 DMPolytopeType ct; 8540 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8541 8542 PetscFunctionBegin; 8543 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8544 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8545 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8546 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8547 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8548 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8549 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8550 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8551 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8552 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8553 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8554 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8555 /* Column indices */ 8556 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8557 maxFPoints = numCPoints; 8558 /* Compress out points not in the section */ 8559 /* TODO: Squeeze out points with 0 dof as well */ 8560 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8561 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8562 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8563 cpoints[q * 2] = cpoints[p]; 8564 cpoints[q * 2 + 1] = cpoints[p + 1]; 8565 ++q; 8566 } 8567 } 8568 numCPoints = q; 8569 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8570 PetscInt fdof; 8571 8572 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8573 if (!dof) continue; 8574 for (f = 0; f < numFields; ++f) { 8575 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8576 coffsets[f + 1] += fdof; 8577 } 8578 numCIndices += dof; 8579 } 8580 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8581 /* Row indices */ 8582 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8583 { 8584 DMPlexTransform tr; 8585 DMPolytopeType *rct; 8586 PetscInt *rsize, *rcone, *rornt, Nt; 8587 8588 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8589 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8590 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8591 numSubcells = rsize[Nt - 1]; 8592 PetscCall(DMPlexTransformDestroy(&tr)); 8593 } 8594 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8595 for (r = 0, q = 0; r < numSubcells; ++r) { 8596 /* TODO Map from coarse to fine cells */ 8597 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8598 /* Compress out points not in the section */ 8599 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8600 for (p = 0; p < numFPoints * 2; p += 2) { 8601 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8602 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8603 if (!dof) continue; 8604 for (s = 0; s < q; ++s) 8605 if (fpoints[p] == ftotpoints[s * 2]) break; 8606 if (s < q) continue; 8607 ftotpoints[q * 2] = fpoints[p]; 8608 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8609 ++q; 8610 } 8611 } 8612 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8613 } 8614 numFPoints = q; 8615 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8616 PetscInt fdof; 8617 8618 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8619 if (!dof) continue; 8620 for (f = 0; f < numFields; ++f) { 8621 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8622 foffsets[f + 1] += fdof; 8623 } 8624 numFIndices += dof; 8625 } 8626 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8627 8628 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8629 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8630 if (numFields) { 8631 const PetscInt **permsF[32] = {NULL}; 8632 const PetscInt **permsC[32] = {NULL}; 8633 8634 for (f = 0; f < numFields; f++) { 8635 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8636 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8637 } 8638 for (p = 0; p < numFPoints; p++) { 8639 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8640 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8641 } 8642 for (p = 0; p < numCPoints; p++) { 8643 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8644 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8645 } 8646 for (f = 0; f < numFields; f++) { 8647 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8648 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8649 } 8650 } else { 8651 const PetscInt **permsF = NULL; 8652 const PetscInt **permsC = NULL; 8653 8654 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8655 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8656 for (p = 0, off = 0; p < numFPoints; p++) { 8657 const PetscInt *perm = permsF ? permsF[p] : NULL; 8658 8659 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8660 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8661 } 8662 for (p = 0, off = 0; p < numCPoints; p++) { 8663 const PetscInt *perm = permsC ? permsC[p] : NULL; 8664 8665 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8666 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8667 } 8668 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8669 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8670 } 8671 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8672 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8673 PetscFunctionReturn(PETSC_SUCCESS); 8674 } 8675 8676 /*@ 8677 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8678 8679 Input Parameter: 8680 . dm - The `DMPLEX` object 8681 8682 Output Parameter: 8683 . cellHeight - The height of a cell 8684 8685 Level: developer 8686 8687 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8688 @*/ 8689 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8690 { 8691 DM_Plex *mesh = (DM_Plex *)dm->data; 8692 8693 PetscFunctionBegin; 8694 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8695 PetscAssertPointer(cellHeight, 2); 8696 *cellHeight = mesh->vtkCellHeight; 8697 PetscFunctionReturn(PETSC_SUCCESS); 8698 } 8699 8700 /*@ 8701 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8702 8703 Input Parameters: 8704 + dm - The `DMPLEX` object 8705 - cellHeight - The height of a cell 8706 8707 Level: developer 8708 8709 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8710 @*/ 8711 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8712 { 8713 DM_Plex *mesh = (DM_Plex *)dm->data; 8714 8715 PetscFunctionBegin; 8716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8717 mesh->vtkCellHeight = cellHeight; 8718 PetscFunctionReturn(PETSC_SUCCESS); 8719 } 8720 8721 /*@ 8722 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8723 8724 Input Parameters: 8725 + dm - The `DMPLEX` object 8726 - ct - The `DMPolytopeType` of the cell 8727 8728 Output Parameters: 8729 + start - The first cell of this type, or `NULL` 8730 - end - The upper bound on this celltype, or `NULL` 8731 8732 Level: advanced 8733 8734 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8735 @*/ 8736 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8737 { 8738 DM_Plex *mesh = (DM_Plex *)dm->data; 8739 DMLabel label; 8740 PetscInt pStart, pEnd; 8741 8742 PetscFunctionBegin; 8743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8744 if (start) { 8745 PetscAssertPointer(start, 3); 8746 *start = 0; 8747 } 8748 if (end) { 8749 PetscAssertPointer(end, 4); 8750 *end = 0; 8751 } 8752 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8753 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8754 if (mesh->tr) { 8755 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8756 } else { 8757 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8758 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8759 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8760 } 8761 PetscFunctionReturn(PETSC_SUCCESS); 8762 } 8763 8764 /*@ 8765 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8766 8767 Input Parameters: 8768 + dm - The `DMPLEX` object 8769 - depth - The depth for the given point stratum 8770 8771 Output Parameter: 8772 . gsize - The global number of points in the stratum 8773 8774 Level: advanced 8775 8776 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8777 @*/ 8778 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8779 { 8780 PetscSF sf; 8781 const PetscInt *leaves; 8782 PetscInt Nl, loc, start, end, lsize = 0; 8783 8784 PetscFunctionBegin; 8785 PetscCall(DMGetPointSF(dm, &sf)); 8786 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8787 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8788 for (PetscInt p = start; p < end; ++p) { 8789 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8790 if (loc < 0) ++lsize; 8791 } 8792 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8793 PetscFunctionReturn(PETSC_SUCCESS); 8794 } 8795 8796 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8797 { 8798 PetscSection section, globalSection; 8799 PetscInt *numbers, p; 8800 8801 PetscFunctionBegin; 8802 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8803 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8804 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8805 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8806 PetscCall(PetscSectionSetUp(section)); 8807 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8808 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8809 for (p = pStart; p < pEnd; ++p) { 8810 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8811 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8812 else numbers[p - pStart] += shift; 8813 } 8814 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8815 if (globalSize) { 8816 PetscLayout layout; 8817 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8818 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8819 PetscCall(PetscLayoutDestroy(&layout)); 8820 } 8821 PetscCall(PetscSectionDestroy(§ion)); 8822 PetscCall(PetscSectionDestroy(&globalSection)); 8823 PetscFunctionReturn(PETSC_SUCCESS); 8824 } 8825 8826 /*@ 8827 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8828 8829 Input Parameters: 8830 + dm - The `DMPLEX` object 8831 - includeAll - Whether to include all cells, or just the simplex and box cells 8832 8833 Output Parameter: 8834 . globalCellNumbers - Global cell numbers for all cells on this process 8835 8836 Level: developer 8837 8838 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8839 @*/ 8840 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8841 { 8842 PetscInt cellHeight, cStart, cEnd; 8843 8844 PetscFunctionBegin; 8845 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8846 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8847 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8848 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8849 PetscFunctionReturn(PETSC_SUCCESS); 8850 } 8851 8852 /*@ 8853 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8854 8855 Input Parameter: 8856 . dm - The `DMPLEX` object 8857 8858 Output Parameter: 8859 . globalCellNumbers - Global cell numbers for all cells on this process 8860 8861 Level: developer 8862 8863 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8864 @*/ 8865 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8866 { 8867 DM_Plex *mesh = (DM_Plex *)dm->data; 8868 8869 PetscFunctionBegin; 8870 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8871 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8872 *globalCellNumbers = mesh->globalCellNumbers; 8873 PetscFunctionReturn(PETSC_SUCCESS); 8874 } 8875 8876 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8877 { 8878 PetscInt vStart, vEnd; 8879 8880 PetscFunctionBegin; 8881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8882 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8883 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8884 PetscFunctionReturn(PETSC_SUCCESS); 8885 } 8886 8887 /*@ 8888 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8889 8890 Input Parameter: 8891 . dm - The `DMPLEX` object 8892 8893 Output Parameter: 8894 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8895 8896 Level: developer 8897 8898 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8899 @*/ 8900 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8901 { 8902 DM_Plex *mesh = (DM_Plex *)dm->data; 8903 8904 PetscFunctionBegin; 8905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8906 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8907 *globalVertexNumbers = mesh->globalVertexNumbers; 8908 PetscFunctionReturn(PETSC_SUCCESS); 8909 } 8910 8911 /*@ 8912 DMPlexCreatePointNumbering - Create a global numbering for all points. 8913 8914 Collective 8915 8916 Input Parameter: 8917 . dm - The `DMPLEX` object 8918 8919 Output Parameter: 8920 . globalPointNumbers - Global numbers for all points on this process 8921 8922 Level: developer 8923 8924 Notes: 8925 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8926 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8927 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8928 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8929 8930 The partitioned mesh is 8931 ``` 8932 (2)--0--(3)--1--(4) (1)--0--(2) 8933 ``` 8934 and its global numbering is 8935 ``` 8936 (3)--0--(4)--1--(5)--2--(6) 8937 ``` 8938 Then the global numbering is provided as 8939 ``` 8940 [0] Number of indices in set 5 8941 [0] 0 0 8942 [0] 1 1 8943 [0] 2 3 8944 [0] 3 4 8945 [0] 4 -6 8946 [1] Number of indices in set 3 8947 [1] 0 2 8948 [1] 1 5 8949 [1] 2 6 8950 ``` 8951 8952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8953 @*/ 8954 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8955 { 8956 IS nums[4]; 8957 PetscInt depths[4], gdepths[4], starts[4]; 8958 PetscInt depth, d, shift = 0; 8959 PetscBool empty = PETSC_FALSE; 8960 PetscMPIInt idepth; 8961 8962 PetscFunctionBegin; 8963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8964 PetscCall(DMPlexGetDepth(dm, &depth)); 8965 // For unstratified meshes use dim instead of depth 8966 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8967 // If any stratum is empty, we must mark all empty 8968 for (d = 0; d <= depth; ++d) { 8969 PetscInt end; 8970 8971 depths[d] = depth - d; 8972 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8973 if (!(starts[d] - end)) empty = PETSC_TRUE; 8974 } 8975 if (empty) 8976 for (d = 0; d <= depth; ++d) { 8977 depths[d] = -1; 8978 starts[d] = -1; 8979 } 8980 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8981 PetscCall(PetscMPIIntCast(depth + 1, &idepth)); 8982 PetscCallMPI(MPIU_Allreduce(depths, gdepths, idepth, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8983 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]); 8984 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8985 for (d = 0; d <= depth; ++d) { 8986 PetscInt pStart, pEnd, gsize; 8987 8988 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8989 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8990 shift += gsize; 8991 } 8992 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8993 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8994 PetscFunctionReturn(PETSC_SUCCESS); 8995 } 8996 8997 /*@ 8998 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 8999 9000 Collective 9001 9002 Input Parameter: 9003 . dm - The `DMPLEX` object 9004 9005 Output Parameter: 9006 . globalEdgeNumbers - Global numbers for all edges on this process 9007 9008 Level: developer 9009 9010 Notes: 9011 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). 9012 9013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9014 @*/ 9015 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9016 { 9017 PetscSF sf; 9018 PetscInt eStart, eEnd; 9019 9020 PetscFunctionBegin; 9021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9022 PetscCall(DMGetPointSF(dm, &sf)); 9023 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9024 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9025 PetscFunctionReturn(PETSC_SUCCESS); 9026 } 9027 9028 /*@ 9029 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9030 9031 Input Parameter: 9032 . dm - The `DMPLEX` object 9033 9034 Output Parameter: 9035 . ranks - The rank field 9036 9037 Options Database Key: 9038 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9039 9040 Level: intermediate 9041 9042 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9043 @*/ 9044 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9045 { 9046 DM rdm; 9047 PetscFE fe; 9048 PetscScalar *r; 9049 PetscMPIInt rank; 9050 DMPolytopeType ct; 9051 PetscInt dim, cStart, cEnd, c; 9052 PetscBool simplex; 9053 9054 PetscFunctionBeginUser; 9055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9056 PetscAssertPointer(ranks, 2); 9057 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9058 PetscCall(DMClone(dm, &rdm)); 9059 PetscCall(DMGetDimension(rdm, &dim)); 9060 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9061 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9062 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9063 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9064 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9065 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9066 PetscCall(PetscFEDestroy(&fe)); 9067 PetscCall(DMCreateDS(rdm)); 9068 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9069 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9070 PetscCall(VecGetArray(*ranks, &r)); 9071 for (c = cStart; c < cEnd; ++c) { 9072 PetscScalar *lr; 9073 9074 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9075 if (lr) *lr = rank; 9076 } 9077 PetscCall(VecRestoreArray(*ranks, &r)); 9078 PetscCall(DMDestroy(&rdm)); 9079 PetscFunctionReturn(PETSC_SUCCESS); 9080 } 9081 9082 /*@ 9083 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9084 9085 Input Parameters: 9086 + dm - The `DMPLEX` 9087 - label - The `DMLabel` 9088 9089 Output Parameter: 9090 . val - The label value field 9091 9092 Options Database Key: 9093 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9094 9095 Level: intermediate 9096 9097 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9098 @*/ 9099 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9100 { 9101 DM rdm, plex; 9102 Vec lval; 9103 PetscSection section; 9104 PetscFE fe; 9105 PetscScalar *v; 9106 PetscInt dim, pStart, pEnd, p, cStart; 9107 DMPolytopeType ct; 9108 char name[PETSC_MAX_PATH_LEN]; 9109 const char *lname, *prefix; 9110 9111 PetscFunctionBeginUser; 9112 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9113 PetscAssertPointer(label, 2); 9114 PetscAssertPointer(val, 3); 9115 PetscCall(DMClone(dm, &rdm)); 9116 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9117 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9118 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9119 PetscCall(DMDestroy(&plex)); 9120 PetscCall(DMGetDimension(rdm, &dim)); 9121 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9122 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9123 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9124 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9125 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9126 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9127 PetscCall(PetscFEDestroy(&fe)); 9128 PetscCall(DMCreateDS(rdm)); 9129 PetscCall(DMCreateGlobalVector(rdm, val)); 9130 PetscCall(DMCreateLocalVector(rdm, &lval)); 9131 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9132 PetscCall(DMGetLocalSection(rdm, §ion)); 9133 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9134 PetscCall(VecGetArray(lval, &v)); 9135 for (p = pStart; p < pEnd; ++p) { 9136 PetscInt cval, dof, off; 9137 9138 PetscCall(PetscSectionGetDof(section, p, &dof)); 9139 if (!dof) continue; 9140 PetscCall(DMLabelGetValue(label, p, &cval)); 9141 PetscCall(PetscSectionGetOffset(section, p, &off)); 9142 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9143 } 9144 PetscCall(VecRestoreArray(lval, &v)); 9145 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9146 PetscCall(VecDestroy(&lval)); 9147 PetscCall(DMDestroy(&rdm)); 9148 PetscFunctionReturn(PETSC_SUCCESS); 9149 } 9150 9151 /*@ 9152 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9153 9154 Input Parameter: 9155 . dm - The `DMPLEX` object 9156 9157 Level: developer 9158 9159 Notes: 9160 This is a useful diagnostic when creating meshes programmatically. 9161 9162 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9163 9164 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9165 @*/ 9166 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9167 { 9168 PetscSection coneSection, supportSection; 9169 const PetscInt *cone, *support; 9170 PetscInt coneSize, c, supportSize, s; 9171 PetscInt pStart, pEnd, p, pp, csize, ssize; 9172 PetscBool storagecheck = PETSC_TRUE; 9173 9174 PetscFunctionBegin; 9175 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9176 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9177 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9178 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9179 /* Check that point p is found in the support of its cone points, and vice versa */ 9180 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9181 for (p = pStart; p < pEnd; ++p) { 9182 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9183 PetscCall(DMPlexGetCone(dm, p, &cone)); 9184 for (c = 0; c < coneSize; ++c) { 9185 PetscBool dup = PETSC_FALSE; 9186 PetscInt d; 9187 for (d = c - 1; d >= 0; --d) { 9188 if (cone[c] == cone[d]) { 9189 dup = PETSC_TRUE; 9190 break; 9191 } 9192 } 9193 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9194 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9195 for (s = 0; s < supportSize; ++s) { 9196 if (support[s] == p) break; 9197 } 9198 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9199 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9200 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9201 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9202 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9203 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9204 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9205 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]); 9206 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9207 } 9208 } 9209 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9210 if (p != pp) { 9211 storagecheck = PETSC_FALSE; 9212 continue; 9213 } 9214 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9215 PetscCall(DMPlexGetSupport(dm, p, &support)); 9216 for (s = 0; s < supportSize; ++s) { 9217 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9218 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9219 for (c = 0; c < coneSize; ++c) { 9220 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9221 if (cone[c] != pp) { 9222 c = 0; 9223 break; 9224 } 9225 if (cone[c] == p) break; 9226 } 9227 if (c >= coneSize) { 9228 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9229 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9230 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9231 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9232 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9233 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9234 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9235 } 9236 } 9237 } 9238 if (storagecheck) { 9239 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9240 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9241 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9242 } 9243 PetscFunctionReturn(PETSC_SUCCESS); 9244 } 9245 9246 /* 9247 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. 9248 */ 9249 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9250 { 9251 DMPolytopeType cct; 9252 PetscInt ptpoints[4]; 9253 const PetscInt *cone, *ccone, *ptcone; 9254 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9255 9256 PetscFunctionBegin; 9257 *unsplit = 0; 9258 switch (ct) { 9259 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9260 ptpoints[npt++] = c; 9261 break; 9262 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9263 PetscCall(DMPlexGetCone(dm, c, &cone)); 9264 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9265 for (cp = 0; cp < coneSize; ++cp) { 9266 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9267 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9268 } 9269 break; 9270 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9271 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9272 PetscCall(DMPlexGetCone(dm, c, &cone)); 9273 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9274 for (cp = 0; cp < coneSize; ++cp) { 9275 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9276 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9277 for (ccp = 0; ccp < cconeSize; ++ccp) { 9278 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9279 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9280 PetscInt p; 9281 for (p = 0; p < npt; ++p) 9282 if (ptpoints[p] == ccone[ccp]) break; 9283 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9284 } 9285 } 9286 } 9287 break; 9288 default: 9289 break; 9290 } 9291 for (pt = 0; pt < npt; ++pt) { 9292 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9293 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9294 } 9295 PetscFunctionReturn(PETSC_SUCCESS); 9296 } 9297 9298 /*@ 9299 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9300 9301 Input Parameters: 9302 + dm - The `DMPLEX` object 9303 - cellHeight - Normally 0 9304 9305 Level: developer 9306 9307 Notes: 9308 This is a useful diagnostic when creating meshes programmatically. 9309 Currently applicable only to homogeneous simplex or tensor meshes. 9310 9311 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9312 9313 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9314 @*/ 9315 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9316 { 9317 DMPlexInterpolatedFlag interp; 9318 DMPolytopeType ct; 9319 PetscInt vStart, vEnd, cStart, cEnd, c; 9320 9321 PetscFunctionBegin; 9322 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9323 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9324 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9325 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9326 for (c = cStart; c < cEnd; ++c) { 9327 PetscInt *closure = NULL; 9328 PetscInt coneSize, closureSize, cl, Nv = 0; 9329 9330 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9331 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9332 if (interp == DMPLEX_INTERPOLATED_FULL) { 9333 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9334 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)); 9335 } 9336 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9337 for (cl = 0; cl < closureSize * 2; cl += 2) { 9338 const PetscInt p = closure[cl]; 9339 if ((p >= vStart) && (p < vEnd)) ++Nv; 9340 } 9341 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9342 /* Special Case: Tensor faces with identified vertices */ 9343 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9344 PetscInt unsplit; 9345 9346 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9347 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9348 } 9349 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)); 9350 } 9351 PetscFunctionReturn(PETSC_SUCCESS); 9352 } 9353 9354 /*@ 9355 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9356 9357 Collective 9358 9359 Input Parameters: 9360 + dm - The `DMPLEX` object 9361 - cellHeight - Normally 0 9362 9363 Level: developer 9364 9365 Notes: 9366 This is a useful diagnostic when creating meshes programmatically. 9367 This routine is only relevant for meshes that are fully interpolated across all ranks. 9368 It will error out if a partially interpolated mesh is given on some rank. 9369 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9370 9371 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9372 9373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9374 @*/ 9375 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9376 { 9377 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9378 DMPlexInterpolatedFlag interpEnum; 9379 9380 PetscFunctionBegin; 9381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9382 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9383 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9384 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9385 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9386 PetscFunctionReturn(PETSC_SUCCESS); 9387 } 9388 9389 PetscCall(DMGetDimension(dm, &dim)); 9390 PetscCall(DMPlexGetDepth(dm, &depth)); 9391 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9392 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9393 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9394 for (c = cStart; c < cEnd; ++c) { 9395 const PetscInt *cone, *ornt, *faceSizes, *faces; 9396 const DMPolytopeType *faceTypes; 9397 DMPolytopeType ct; 9398 PetscInt numFaces, coneSize, f; 9399 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9400 9401 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9402 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9403 if (unsplit) continue; 9404 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9405 PetscCall(DMPlexGetCone(dm, c, &cone)); 9406 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9407 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9408 for (cl = 0; cl < closureSize * 2; cl += 2) { 9409 const PetscInt p = closure[cl]; 9410 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9411 } 9412 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9413 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); 9414 for (f = 0; f < numFaces; ++f) { 9415 DMPolytopeType fct; 9416 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9417 9418 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9419 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9420 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9421 const PetscInt p = fclosure[cl]; 9422 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9423 } 9424 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]); 9425 for (v = 0; v < fnumCorners; ++v) { 9426 if (fclosure[v] != faces[fOff + v]) { 9427 PetscInt v1; 9428 9429 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9430 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9431 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9432 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9433 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9434 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]); 9435 } 9436 } 9437 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9438 fOff += faceSizes[f]; 9439 } 9440 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9441 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9442 } 9443 } 9444 PetscFunctionReturn(PETSC_SUCCESS); 9445 } 9446 9447 /*@ 9448 DMPlexCheckGeometry - Check the geometry of mesh cells 9449 9450 Input Parameter: 9451 . dm - The `DMPLEX` object 9452 9453 Level: developer 9454 9455 Notes: 9456 This is a useful diagnostic when creating meshes programmatically. 9457 9458 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9459 9460 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9461 @*/ 9462 PetscErrorCode DMPlexCheckGeometry(DM dm) 9463 { 9464 Vec coordinates; 9465 PetscReal detJ, J[9], refVol = 1.0; 9466 PetscReal vol; 9467 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9468 9469 PetscFunctionBegin; 9470 PetscCall(DMGetDimension(dm, &dim)); 9471 PetscCall(DMGetCoordinateDim(dm, &dE)); 9472 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9473 PetscCall(DMPlexGetDepth(dm, &depth)); 9474 for (d = 0; d < dim; ++d) refVol *= 2.0; 9475 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9476 /* Make sure local coordinates are created, because that step is collective */ 9477 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9478 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9479 for (c = cStart; c < cEnd; ++c) { 9480 DMPolytopeType ct; 9481 PetscInt unsplit; 9482 PetscBool ignoreZeroVol = PETSC_FALSE; 9483 9484 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9485 switch (ct) { 9486 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9487 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9488 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9489 ignoreZeroVol = PETSC_TRUE; 9490 break; 9491 default: 9492 break; 9493 } 9494 switch (ct) { 9495 case DM_POLYTOPE_TRI_PRISM: 9496 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9497 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9498 case DM_POLYTOPE_PYRAMID: 9499 continue; 9500 default: 9501 break; 9502 } 9503 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9504 if (unsplit) continue; 9505 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9506 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); 9507 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9508 /* This should work with periodicity since DG coordinates should be used */ 9509 if (depth > 1) { 9510 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9511 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); 9512 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9513 } 9514 } 9515 PetscFunctionReturn(PETSC_SUCCESS); 9516 } 9517 9518 /*@ 9519 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9520 9521 Collective 9522 9523 Input Parameters: 9524 + dm - The `DMPLEX` object 9525 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9526 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9527 9528 Level: developer 9529 9530 Notes: 9531 This is mainly intended for debugging/testing purposes. 9532 9533 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9534 9535 Extra roots can come from periodic cuts, where additional points appear on the boundary 9536 9537 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9538 @*/ 9539 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9540 { 9541 PetscInt l, nleaves, nroots, overlap; 9542 const PetscInt *locals; 9543 const PetscSFNode *remotes; 9544 PetscBool distributed; 9545 MPI_Comm comm; 9546 PetscMPIInt rank; 9547 9548 PetscFunctionBegin; 9549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9550 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9551 else pointSF = dm->sf; 9552 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9553 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9554 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9555 { 9556 PetscMPIInt mpiFlag; 9557 9558 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9559 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9560 } 9561 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9562 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9563 if (!distributed) { 9564 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); 9565 PetscFunctionReturn(PETSC_SUCCESS); 9566 } 9567 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); 9568 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9569 9570 /* Check SF graph is compatible with DMPlex chart */ 9571 { 9572 PetscInt pStart, pEnd, maxLeaf; 9573 9574 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9575 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9576 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9577 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9578 } 9579 9580 /* Check Point SF has no local points referenced */ 9581 for (l = 0; l < nleaves; l++) { 9582 PetscMPIInt irank; 9583 9584 PetscCall(PetscMPIIntCast(remotes[l].rank, &irank)); 9585 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); 9586 } 9587 9588 /* Check there are no cells in interface */ 9589 if (!overlap) { 9590 PetscInt cellHeight, cStart, cEnd; 9591 9592 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9593 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9594 for (l = 0; l < nleaves; ++l) { 9595 const PetscInt point = locals ? locals[l] : l; 9596 9597 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9598 } 9599 } 9600 9601 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9602 { 9603 const PetscInt *rootdegree; 9604 9605 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9606 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9607 for (l = 0; l < nleaves; ++l) { 9608 const PetscInt point = locals ? locals[l] : l; 9609 const PetscInt *cone; 9610 PetscInt coneSize, c, idx; 9611 9612 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9613 PetscCall(DMPlexGetCone(dm, point, &cone)); 9614 for (c = 0; c < coneSize; ++c) { 9615 if (!rootdegree[cone[c]]) { 9616 if (locals) { 9617 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9618 } else { 9619 idx = (cone[c] < nleaves) ? cone[c] : -1; 9620 } 9621 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9622 } 9623 } 9624 } 9625 } 9626 PetscFunctionReturn(PETSC_SUCCESS); 9627 } 9628 9629 /*@ 9630 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9631 9632 Collective 9633 9634 Input Parameter: 9635 . dm - The `DMPLEX` object 9636 9637 Level: developer 9638 9639 Notes: 9640 This is mainly intended for debugging/testing purposes. 9641 9642 Other cell types which are disconnected would be caught by the symmetry and face checks. 9643 9644 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9645 9646 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9647 @*/ 9648 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9649 { 9650 PetscInt pStart, pEnd, vStart, vEnd; 9651 9652 PetscFunctionBegin; 9653 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9654 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9655 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9656 for (PetscInt v = vStart; v < vEnd; ++v) { 9657 PetscInt suppSize; 9658 9659 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9660 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9661 } 9662 PetscFunctionReturn(PETSC_SUCCESS); 9663 } 9664 9665 /*@ 9666 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9667 9668 Input Parameter: 9669 . dm - The `DMPLEX` object 9670 9671 Level: developer 9672 9673 Notes: 9674 This is a useful diagnostic when creating meshes programmatically. 9675 9676 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9677 9678 Currently does not include `DMPlexCheckCellShape()`. 9679 9680 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9681 @*/ 9682 PetscErrorCode DMPlexCheck(DM dm) 9683 { 9684 PetscInt cellHeight; 9685 9686 PetscFunctionBegin; 9687 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9688 PetscCall(DMPlexCheckSymmetry(dm)); 9689 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9690 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9691 PetscCall(DMPlexCheckGeometry(dm)); 9692 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9693 PetscCall(DMPlexCheckInterfaceCones(dm)); 9694 PetscCall(DMPlexCheckOrphanVertices(dm)); 9695 PetscFunctionReturn(PETSC_SUCCESS); 9696 } 9697 9698 typedef struct cell_stats { 9699 PetscReal min, max, sum, squaresum; 9700 PetscInt count; 9701 } cell_stats_t; 9702 9703 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9704 { 9705 PetscInt i, N = *len; 9706 9707 for (i = 0; i < N; i++) { 9708 cell_stats_t *A = (cell_stats_t *)a; 9709 cell_stats_t *B = (cell_stats_t *)b; 9710 9711 B->min = PetscMin(A->min, B->min); 9712 B->max = PetscMax(A->max, B->max); 9713 B->sum += A->sum; 9714 B->squaresum += A->squaresum; 9715 B->count += A->count; 9716 } 9717 } 9718 9719 /*@ 9720 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9721 9722 Collective 9723 9724 Input Parameters: 9725 + dm - The `DMPLEX` object 9726 . output - If true, statistics will be displayed on `stdout` 9727 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9728 9729 Level: developer 9730 9731 Notes: 9732 This is mainly intended for debugging/testing purposes. 9733 9734 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9735 9736 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9737 @*/ 9738 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9739 { 9740 DM dmCoarse; 9741 cell_stats_t stats, globalStats; 9742 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9743 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9744 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9745 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9746 PetscMPIInt rank, size; 9747 9748 PetscFunctionBegin; 9749 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9750 stats.min = PETSC_MAX_REAL; 9751 stats.max = PETSC_MIN_REAL; 9752 stats.sum = stats.squaresum = 0.; 9753 stats.count = 0; 9754 9755 PetscCallMPI(MPI_Comm_size(comm, &size)); 9756 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9757 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9758 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9759 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9760 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9761 for (c = cStart; c < cEnd; c++) { 9762 PetscInt i; 9763 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9764 9765 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9766 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9767 for (i = 0; i < PetscSqr(cdim); ++i) { 9768 frobJ += J[i] * J[i]; 9769 frobInvJ += invJ[i] * invJ[i]; 9770 } 9771 cond2 = frobJ * frobInvJ; 9772 cond = PetscSqrtReal(cond2); 9773 9774 stats.min = PetscMin(stats.min, cond); 9775 stats.max = PetscMax(stats.max, cond); 9776 stats.sum += cond; 9777 stats.squaresum += cond2; 9778 stats.count++; 9779 if (output && cond > limit) { 9780 PetscSection coordSection; 9781 Vec coordsLocal; 9782 PetscScalar *coords = NULL; 9783 PetscInt Nv, d, clSize, cl, *closure = NULL; 9784 9785 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9786 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9787 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9788 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9789 for (i = 0; i < Nv / cdim; ++i) { 9790 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9791 for (d = 0; d < cdim; ++d) { 9792 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9793 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9794 } 9795 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9796 } 9797 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9798 for (cl = 0; cl < clSize * 2; cl += 2) { 9799 const PetscInt edge = closure[cl]; 9800 9801 if ((edge >= eStart) && (edge < eEnd)) { 9802 PetscReal len; 9803 9804 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9805 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9806 } 9807 } 9808 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9809 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9810 } 9811 } 9812 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9813 9814 if (size > 1) { 9815 PetscMPIInt blockLengths[2] = {4, 1}; 9816 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9817 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9818 MPI_Op statReduce; 9819 9820 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9821 PetscCallMPI(MPI_Type_commit(&statType)); 9822 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9823 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9824 PetscCallMPI(MPI_Op_free(&statReduce)); 9825 PetscCallMPI(MPI_Type_free(&statType)); 9826 } else { 9827 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9828 } 9829 if (rank == 0) { 9830 count = globalStats.count; 9831 min = globalStats.min; 9832 max = globalStats.max; 9833 mean = globalStats.sum / globalStats.count; 9834 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9835 } 9836 9837 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)); 9838 PetscCall(PetscFree2(J, invJ)); 9839 9840 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9841 if (dmCoarse) { 9842 PetscBool isplex; 9843 9844 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9845 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9846 } 9847 PetscFunctionReturn(PETSC_SUCCESS); 9848 } 9849 9850 /*@ 9851 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9852 orthogonal quality below given tolerance. 9853 9854 Collective 9855 9856 Input Parameters: 9857 + dm - The `DMPLEX` object 9858 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9859 - atol - [0, 1] Absolute tolerance for tagging cells. 9860 9861 Output Parameters: 9862 + OrthQual - `Vec` containing orthogonal quality per cell 9863 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9864 9865 Options Database Keys: 9866 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9867 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9868 9869 Level: intermediate 9870 9871 Notes: 9872 Orthogonal quality is given by the following formula\: 9873 9874 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9875 9876 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 9877 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9878 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9879 calculating the cosine of the angle between these vectors. 9880 9881 Orthogonal quality ranges from 1 (best) to 0 (worst). 9882 9883 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9884 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9885 9886 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9887 9888 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9889 @*/ 9890 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9891 { 9892 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9893 PetscInt *idx; 9894 PetscScalar *oqVals; 9895 const PetscScalar *cellGeomArr, *faceGeomArr; 9896 PetscReal *ci, *fi, *Ai; 9897 MPI_Comm comm; 9898 Vec cellgeom, facegeom; 9899 DM dmFace, dmCell; 9900 IS glob; 9901 ISLocalToGlobalMapping ltog; 9902 PetscViewer vwr; 9903 9904 PetscFunctionBegin; 9905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9906 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9907 PetscAssertPointer(OrthQual, 4); 9908 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9909 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9910 PetscCall(DMGetDimension(dm, &nc)); 9911 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9912 { 9913 DMPlexInterpolatedFlag interpFlag; 9914 9915 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9916 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9917 PetscMPIInt rank; 9918 9919 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9920 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9921 } 9922 } 9923 if (OrthQualLabel) { 9924 PetscAssertPointer(OrthQualLabel, 5); 9925 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9926 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9927 } else { 9928 *OrthQualLabel = NULL; 9929 } 9930 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9931 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9932 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9933 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9934 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9935 PetscCall(VecCreate(comm, OrthQual)); 9936 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9937 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9938 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9939 PetscCall(VecSetUp(*OrthQual)); 9940 PetscCall(ISDestroy(&glob)); 9941 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9942 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9943 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9944 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9945 PetscCall(VecGetDM(cellgeom, &dmCell)); 9946 PetscCall(VecGetDM(facegeom, &dmFace)); 9947 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9948 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9949 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9950 PetscInt cellarr[2], *adj = NULL; 9951 PetscScalar *cArr, *fArr; 9952 PetscReal minvalc = 1.0, minvalf = 1.0; 9953 PetscFVCellGeom *cg; 9954 9955 idx[cellIter] = cell - cStart; 9956 cellarr[0] = cell; 9957 /* Make indexing into cellGeom easier */ 9958 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9959 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9960 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9961 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9962 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9963 PetscInt i; 9964 const PetscInt neigh = adj[cellneigh]; 9965 PetscReal normci = 0, normfi = 0, normai = 0; 9966 PetscFVCellGeom *cgneigh; 9967 PetscFVFaceGeom *fg; 9968 9969 /* Don't count ourselves in the neighbor list */ 9970 if (neigh == cell) continue; 9971 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9972 cellarr[1] = neigh; 9973 { 9974 PetscInt numcovpts; 9975 const PetscInt *covpts; 9976 9977 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9978 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9979 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9980 } 9981 9982 /* Compute c_i, f_i and their norms */ 9983 for (i = 0; i < nc; i++) { 9984 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9985 fi[i] = fg->centroid[i] - cg->centroid[i]; 9986 Ai[i] = fg->normal[i]; 9987 normci += PetscPowReal(ci[i], 2); 9988 normfi += PetscPowReal(fi[i], 2); 9989 normai += PetscPowReal(Ai[i], 2); 9990 } 9991 normci = PetscSqrtReal(normci); 9992 normfi = PetscSqrtReal(normfi); 9993 normai = PetscSqrtReal(normai); 9994 9995 /* Normalize and compute for each face-cell-normal pair */ 9996 for (i = 0; i < nc; i++) { 9997 ci[i] = ci[i] / normci; 9998 fi[i] = fi[i] / normfi; 9999 Ai[i] = Ai[i] / normai; 10000 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10001 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10002 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10003 } 10004 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10005 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10006 } 10007 PetscCall(PetscFree(adj)); 10008 PetscCall(PetscFree2(cArr, fArr)); 10009 /* Defer to cell if they're equal */ 10010 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10011 if (OrthQualLabel) { 10012 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10013 } 10014 } 10015 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10016 PetscCall(VecAssemblyBegin(*OrthQual)); 10017 PetscCall(VecAssemblyEnd(*OrthQual)); 10018 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10019 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10020 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10021 if (OrthQualLabel) { 10022 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10023 } 10024 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10025 PetscCall(PetscViewerDestroy(&vwr)); 10026 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10027 PetscFunctionReturn(PETSC_SUCCESS); 10028 } 10029 10030 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10031 * interpolator construction */ 10032 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10033 { 10034 PetscSection section, newSection, gsection; 10035 PetscSF sf; 10036 PetscBool hasConstraints, ghasConstraints; 10037 10038 PetscFunctionBegin; 10039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10040 PetscAssertPointer(odm, 2); 10041 PetscCall(DMGetLocalSection(dm, §ion)); 10042 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10043 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10044 if (!ghasConstraints) { 10045 PetscCall(PetscObjectReference((PetscObject)dm)); 10046 *odm = dm; 10047 PetscFunctionReturn(PETSC_SUCCESS); 10048 } 10049 PetscCall(DMClone(dm, odm)); 10050 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10051 PetscCall(DMGetLocalSection(*odm, &newSection)); 10052 PetscCall(DMGetPointSF(*odm, &sf)); 10053 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10054 PetscCall(DMSetGlobalSection(*odm, gsection)); 10055 PetscCall(PetscSectionDestroy(&gsection)); 10056 PetscFunctionReturn(PETSC_SUCCESS); 10057 } 10058 10059 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10060 { 10061 DM dmco, dmfo; 10062 Mat interpo; 10063 Vec rscale; 10064 Vec cglobalo, clocal; 10065 Vec fglobal, fglobalo, flocal; 10066 PetscBool regular; 10067 10068 PetscFunctionBegin; 10069 PetscCall(DMGetFullDM(dmc, &dmco)); 10070 PetscCall(DMGetFullDM(dmf, &dmfo)); 10071 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10072 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10073 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10074 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10075 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10076 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10077 PetscCall(VecSet(cglobalo, 0.)); 10078 PetscCall(VecSet(clocal, 0.)); 10079 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10080 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10081 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10082 PetscCall(VecSet(fglobal, 0.)); 10083 PetscCall(VecSet(fglobalo, 0.)); 10084 PetscCall(VecSet(flocal, 0.)); 10085 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10086 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10087 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10088 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10089 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10090 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10091 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10092 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10093 *shift = fglobal; 10094 PetscCall(VecDestroy(&flocal)); 10095 PetscCall(VecDestroy(&fglobalo)); 10096 PetscCall(VecDestroy(&clocal)); 10097 PetscCall(VecDestroy(&cglobalo)); 10098 PetscCall(VecDestroy(&rscale)); 10099 PetscCall(MatDestroy(&interpo)); 10100 PetscCall(DMDestroy(&dmfo)); 10101 PetscCall(DMDestroy(&dmco)); 10102 PetscFunctionReturn(PETSC_SUCCESS); 10103 } 10104 10105 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10106 { 10107 PetscObject shifto; 10108 Vec shift; 10109 10110 PetscFunctionBegin; 10111 if (!interp) { 10112 Vec rscale; 10113 10114 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10115 PetscCall(VecDestroy(&rscale)); 10116 } else { 10117 PetscCall(PetscObjectReference((PetscObject)interp)); 10118 } 10119 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10120 if (!shifto) { 10121 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10122 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10123 shifto = (PetscObject)shift; 10124 PetscCall(VecDestroy(&shift)); 10125 } 10126 shift = (Vec)shifto; 10127 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10128 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10129 PetscCall(MatDestroy(&interp)); 10130 PetscFunctionReturn(PETSC_SUCCESS); 10131 } 10132 10133 /* Pointwise interpolation 10134 Just code FEM for now 10135 u^f = I u^c 10136 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10137 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10138 I_{ij} = psi^f_i phi^c_j 10139 */ 10140 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10141 { 10142 PetscSection gsc, gsf; 10143 PetscInt m, n; 10144 void *ctx; 10145 DM cdm; 10146 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10147 10148 PetscFunctionBegin; 10149 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10150 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10151 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10152 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10153 10154 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10155 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10156 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10157 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10158 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10159 10160 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10161 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10162 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10163 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10164 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10165 if (scaling) { 10166 /* Use naive scaling */ 10167 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10168 } 10169 PetscFunctionReturn(PETSC_SUCCESS); 10170 } 10171 10172 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10173 { 10174 VecScatter ctx; 10175 10176 PetscFunctionBegin; 10177 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10178 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10179 PetscCall(VecScatterDestroy(&ctx)); 10180 PetscFunctionReturn(PETSC_SUCCESS); 10181 } 10182 10183 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[]) 10184 { 10185 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10186 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10187 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10188 } 10189 10190 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10191 { 10192 DM dmc; 10193 PetscDS ds; 10194 Vec ones, locmass; 10195 IS cellIS; 10196 PetscFormKey key; 10197 PetscInt depth; 10198 10199 PetscFunctionBegin; 10200 PetscCall(DMClone(dm, &dmc)); 10201 PetscCall(DMCopyDisc(dm, dmc)); 10202 PetscCall(DMGetDS(dmc, &ds)); 10203 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10204 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10205 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10206 else PetscCall(DMGetLocalVector(dm, &locmass)); 10207 PetscCall(DMGetLocalVector(dm, &ones)); 10208 PetscCall(DMPlexGetDepth(dm, &depth)); 10209 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10210 PetscCall(VecSet(locmass, 0.0)); 10211 PetscCall(VecSet(ones, 1.0)); 10212 key.label = NULL; 10213 key.value = 0; 10214 key.field = 0; 10215 key.part = 0; 10216 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10217 PetscCall(ISDestroy(&cellIS)); 10218 if (mass) { 10219 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10220 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10221 } 10222 PetscCall(DMRestoreLocalVector(dm, &ones)); 10223 if (lmass) *lmass = locmass; 10224 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10225 PetscCall(DMDestroy(&dmc)); 10226 PetscFunctionReturn(PETSC_SUCCESS); 10227 } 10228 10229 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10230 { 10231 PetscSection gsc, gsf; 10232 PetscInt m, n; 10233 void *ctx; 10234 DM cdm; 10235 PetscBool regular; 10236 10237 PetscFunctionBegin; 10238 if (dmFine == dmCoarse) { 10239 DM dmc; 10240 PetscDS ds; 10241 PetscWeakForm wf; 10242 Vec u; 10243 IS cellIS; 10244 PetscFormKey key; 10245 PetscInt depth; 10246 10247 PetscCall(DMClone(dmFine, &dmc)); 10248 PetscCall(DMCopyDisc(dmFine, dmc)); 10249 PetscCall(DMGetDS(dmc, &ds)); 10250 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10251 PetscCall(PetscWeakFormClear(wf)); 10252 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10253 PetscCall(DMCreateMatrix(dmc, mass)); 10254 PetscCall(DMGetLocalVector(dmc, &u)); 10255 PetscCall(DMPlexGetDepth(dmc, &depth)); 10256 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10257 PetscCall(MatZeroEntries(*mass)); 10258 key.label = NULL; 10259 key.value = 0; 10260 key.field = 0; 10261 key.part = 0; 10262 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10263 PetscCall(ISDestroy(&cellIS)); 10264 PetscCall(DMRestoreLocalVector(dmc, &u)); 10265 PetscCall(DMDestroy(&dmc)); 10266 } else { 10267 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10268 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10269 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10270 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10271 10272 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10273 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10274 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10275 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10276 10277 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10278 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10279 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10280 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10281 } 10282 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10283 PetscFunctionReturn(PETSC_SUCCESS); 10284 } 10285 10286 /*@ 10287 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10288 10289 Input Parameter: 10290 . dm - The `DMPLEX` object 10291 10292 Output Parameter: 10293 . regular - The flag 10294 10295 Level: intermediate 10296 10297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10298 @*/ 10299 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10300 { 10301 PetscFunctionBegin; 10302 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10303 PetscAssertPointer(regular, 2); 10304 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10305 PetscFunctionReturn(PETSC_SUCCESS); 10306 } 10307 10308 /*@ 10309 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10310 10311 Input Parameters: 10312 + dm - The `DMPLEX` object 10313 - regular - The flag 10314 10315 Level: intermediate 10316 10317 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10318 @*/ 10319 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10320 { 10321 PetscFunctionBegin; 10322 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10323 ((DM_Plex *)dm->data)->regularRefinement = regular; 10324 PetscFunctionReturn(PETSC_SUCCESS); 10325 } 10326 10327 /*@ 10328 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10329 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10330 10331 Not Collective 10332 10333 Input Parameter: 10334 . dm - The `DMPLEX` object 10335 10336 Output Parameters: 10337 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10338 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10339 10340 Level: intermediate 10341 10342 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10343 @*/ 10344 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10345 { 10346 DM_Plex *plex = (DM_Plex *)dm->data; 10347 10348 PetscFunctionBegin; 10349 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10350 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10351 if (anchorSection) *anchorSection = plex->anchorSection; 10352 if (anchorIS) *anchorIS = plex->anchorIS; 10353 PetscFunctionReturn(PETSC_SUCCESS); 10354 } 10355 10356 /*@ 10357 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10358 10359 Collective 10360 10361 Input Parameters: 10362 + dm - The `DMPLEX` object 10363 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10364 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10365 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10366 10367 Level: intermediate 10368 10369 Notes: 10370 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10371 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10372 combination of other points' degrees of freedom. 10373 10374 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10375 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10376 10377 The reference counts of `anchorSection` and `anchorIS` are incremented. 10378 10379 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10380 @*/ 10381 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10382 { 10383 DM_Plex *plex = (DM_Plex *)dm->data; 10384 PetscMPIInt result; 10385 10386 PetscFunctionBegin; 10387 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10388 if (anchorSection) { 10389 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10390 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10391 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10392 } 10393 if (anchorIS) { 10394 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10395 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10396 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10397 } 10398 10399 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10400 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10401 plex->anchorSection = anchorSection; 10402 10403 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10404 PetscCall(ISDestroy(&plex->anchorIS)); 10405 plex->anchorIS = anchorIS; 10406 10407 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10408 PetscInt size, a, pStart, pEnd; 10409 const PetscInt *anchors; 10410 10411 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10412 PetscCall(ISGetLocalSize(anchorIS, &size)); 10413 PetscCall(ISGetIndices(anchorIS, &anchors)); 10414 for (a = 0; a < size; a++) { 10415 PetscInt p; 10416 10417 p = anchors[a]; 10418 if (p >= pStart && p < pEnd) { 10419 PetscInt dof; 10420 10421 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10422 if (dof) { 10423 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10424 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10425 } 10426 } 10427 } 10428 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10429 } 10430 /* reset the generic constraints */ 10431 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10432 PetscFunctionReturn(PETSC_SUCCESS); 10433 } 10434 10435 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10436 { 10437 PetscSection anchorSection; 10438 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10439 10440 PetscFunctionBegin; 10441 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10442 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10443 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10444 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10445 if (numFields) { 10446 PetscInt f; 10447 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10448 10449 for (f = 0; f < numFields; f++) { 10450 PetscInt numComp; 10451 10452 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10453 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10454 } 10455 } 10456 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10457 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10458 pStart = PetscMax(pStart, sStart); 10459 pEnd = PetscMin(pEnd, sEnd); 10460 pEnd = PetscMax(pStart, pEnd); 10461 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10462 for (p = pStart; p < pEnd; p++) { 10463 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10464 if (dof) { 10465 PetscCall(PetscSectionGetDof(section, p, &dof)); 10466 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10467 for (f = 0; f < numFields; f++) { 10468 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10469 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10470 } 10471 } 10472 } 10473 PetscCall(PetscSectionSetUp(*cSec)); 10474 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10475 PetscFunctionReturn(PETSC_SUCCESS); 10476 } 10477 10478 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10479 { 10480 PetscSection aSec; 10481 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10482 const PetscInt *anchors; 10483 PetscInt numFields, f; 10484 IS aIS; 10485 MatType mtype; 10486 PetscBool iscuda, iskokkos; 10487 10488 PetscFunctionBegin; 10489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10490 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10491 PetscCall(PetscSectionGetStorageSize(section, &n)); 10492 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10493 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10494 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10495 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10496 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10497 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10498 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10499 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10500 else mtype = MATSEQAIJ; 10501 PetscCall(MatSetType(*cMat, mtype)); 10502 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10503 PetscCall(ISGetIndices(aIS, &anchors)); 10504 /* cSec will be a subset of aSec and section */ 10505 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10506 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10507 PetscCall(PetscMalloc1(m + 1, &i)); 10508 i[0] = 0; 10509 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10510 for (p = pStart; p < pEnd; p++) { 10511 PetscInt rDof, rOff, r; 10512 10513 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10514 if (!rDof) continue; 10515 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10516 if (numFields) { 10517 for (f = 0; f < numFields; f++) { 10518 annz = 0; 10519 for (r = 0; r < rDof; r++) { 10520 a = anchors[rOff + r]; 10521 if (a < sStart || a >= sEnd) continue; 10522 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10523 annz += aDof; 10524 } 10525 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10526 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10527 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10528 } 10529 } else { 10530 annz = 0; 10531 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10532 for (q = 0; q < dof; q++) { 10533 a = anchors[rOff + q]; 10534 if (a < sStart || a >= sEnd) continue; 10535 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10536 annz += aDof; 10537 } 10538 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10539 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10540 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10541 } 10542 } 10543 nnz = i[m]; 10544 PetscCall(PetscMalloc1(nnz, &j)); 10545 offset = 0; 10546 for (p = pStart; p < pEnd; p++) { 10547 if (numFields) { 10548 for (f = 0; f < numFields; f++) { 10549 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10550 for (q = 0; q < dof; q++) { 10551 PetscInt rDof, rOff, r; 10552 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10553 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10554 for (r = 0; r < rDof; r++) { 10555 PetscInt s; 10556 10557 a = anchors[rOff + r]; 10558 if (a < sStart || a >= sEnd) continue; 10559 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10560 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10561 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10562 } 10563 } 10564 } 10565 } else { 10566 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10567 for (q = 0; q < dof; q++) { 10568 PetscInt rDof, rOff, r; 10569 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10570 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10571 for (r = 0; r < rDof; r++) { 10572 PetscInt s; 10573 10574 a = anchors[rOff + r]; 10575 if (a < sStart || a >= sEnd) continue; 10576 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10577 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10578 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10579 } 10580 } 10581 } 10582 } 10583 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10584 PetscCall(PetscFree(i)); 10585 PetscCall(PetscFree(j)); 10586 PetscCall(ISRestoreIndices(aIS, &anchors)); 10587 PetscFunctionReturn(PETSC_SUCCESS); 10588 } 10589 10590 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10591 { 10592 DM_Plex *plex = (DM_Plex *)dm->data; 10593 PetscSection anchorSection, section, cSec; 10594 Mat cMat; 10595 10596 PetscFunctionBegin; 10597 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10598 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10599 if (anchorSection) { 10600 PetscInt Nf; 10601 10602 PetscCall(DMGetLocalSection(dm, §ion)); 10603 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10604 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10605 PetscCall(DMGetNumFields(dm, &Nf)); 10606 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10607 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10608 PetscCall(PetscSectionDestroy(&cSec)); 10609 PetscCall(MatDestroy(&cMat)); 10610 } 10611 PetscFunctionReturn(PETSC_SUCCESS); 10612 } 10613 10614 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10615 { 10616 IS subis; 10617 PetscSection section, subsection; 10618 10619 PetscFunctionBegin; 10620 PetscCall(DMGetLocalSection(dm, §ion)); 10621 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10622 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10623 /* Create subdomain */ 10624 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10625 /* Create submodel */ 10626 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10627 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10628 PetscCall(DMSetLocalSection(*subdm, subsection)); 10629 PetscCall(PetscSectionDestroy(&subsection)); 10630 PetscCall(DMCopyDisc(dm, *subdm)); 10631 /* Create map from submodel to global model */ 10632 if (is) { 10633 PetscSection sectionGlobal, subsectionGlobal; 10634 IS spIS; 10635 const PetscInt *spmap; 10636 PetscInt *subIndices; 10637 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10638 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10639 10640 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10641 PetscCall(ISGetIndices(spIS, &spmap)); 10642 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10643 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10644 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10645 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10646 for (p = pStart; p < pEnd; ++p) { 10647 PetscInt gdof, pSubSize = 0; 10648 10649 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10650 if (gdof > 0) { 10651 for (f = 0; f < Nf; ++f) { 10652 PetscInt fdof, fcdof; 10653 10654 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10655 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10656 pSubSize += fdof - fcdof; 10657 } 10658 subSize += pSubSize; 10659 if (pSubSize) { 10660 if (bs < 0) { 10661 bs = pSubSize; 10662 } else if (bs != pSubSize) { 10663 /* Layout does not admit a pointwise block size */ 10664 bs = 1; 10665 } 10666 } 10667 } 10668 } 10669 /* Must have same blocksize on all procs (some might have no points) */ 10670 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10671 bsLocal[1] = bs; 10672 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10673 if (bsMinMax[0] != bsMinMax[1]) { 10674 bs = 1; 10675 } else { 10676 bs = bsMinMax[0]; 10677 } 10678 PetscCall(PetscMalloc1(subSize, &subIndices)); 10679 for (p = pStart; p < pEnd; ++p) { 10680 PetscInt gdof, goff; 10681 10682 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10683 if (gdof > 0) { 10684 const PetscInt point = spmap[p]; 10685 10686 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10687 for (f = 0; f < Nf; ++f) { 10688 PetscInt fdof, fcdof, fc, f2, poff = 0; 10689 10690 /* Can get rid of this loop by storing field information in the global section */ 10691 for (f2 = 0; f2 < f; ++f2) { 10692 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10693 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10694 poff += fdof - fcdof; 10695 } 10696 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10697 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10698 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10699 } 10700 } 10701 } 10702 PetscCall(ISRestoreIndices(spIS, &spmap)); 10703 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10704 if (bs > 1) { 10705 /* We need to check that the block size does not come from non-contiguous fields */ 10706 PetscInt i, j, set = 1; 10707 for (i = 0; i < subSize; i += bs) { 10708 for (j = 0; j < bs; ++j) { 10709 if (subIndices[i + j] != subIndices[i] + j) { 10710 set = 0; 10711 break; 10712 } 10713 } 10714 } 10715 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10716 } 10717 /* Attach nullspace */ 10718 for (f = 0; f < Nf; ++f) { 10719 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10720 if ((*subdm)->nullspaceConstructors[f]) break; 10721 } 10722 if (f < Nf) { 10723 MatNullSpace nullSpace; 10724 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10725 10726 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10727 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10728 } 10729 } 10730 PetscFunctionReturn(PETSC_SUCCESS); 10731 } 10732 10733 /*@ 10734 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10735 10736 Input Parameters: 10737 + dm - The `DM` 10738 - dummy - unused argument 10739 10740 Options Database Key: 10741 . -dm_plex_monitor_throughput - Activate the monitor 10742 10743 Level: developer 10744 10745 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10746 @*/ 10747 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10748 { 10749 PetscLogHandler default_handler; 10750 10751 PetscFunctionBegin; 10752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10753 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10754 if (default_handler) { 10755 PetscLogEvent event; 10756 PetscEventPerfInfo eventInfo; 10757 PetscLogDouble cellRate, flopRate; 10758 PetscInt cStart, cEnd, Nf, N; 10759 const char *name; 10760 10761 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10762 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10763 PetscCall(DMGetNumFields(dm, &Nf)); 10764 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10765 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10766 N = (cEnd - cStart) * Nf * eventInfo.count; 10767 flopRate = eventInfo.flops / eventInfo.time; 10768 cellRate = N / eventInfo.time; 10769 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)); 10770 } else { 10771 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."); 10772 } 10773 PetscFunctionReturn(PETSC_SUCCESS); 10774 } 10775