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 DM cdm; 277 PetscDS ds; 278 PetscDraw draw = NULL; 279 PetscDrawLG lg; 280 Vec coordinates; 281 const PetscScalar *coords, **sol; 282 PetscReal *vals; 283 PetscInt *Nc; 284 PetscInt Nf, Nl, vStart, vEnd, eStart, eEnd; 285 char **names; 286 287 PetscFunctionBegin; 288 PetscCall(DMGetCoordinateDM(dm, &cdm)); 289 PetscCall(DMGetDS(dm, &ds)); 290 PetscCall(PetscDSGetNumFields(ds, &Nf)); 291 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 292 PetscCall(PetscDSGetComponents(ds, &Nc)); 293 294 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 295 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 296 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 297 298 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 299 for (PetscInt i = 0, l = 0; i < n; ++i) { 300 const char *vname; 301 302 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 303 for (PetscInt f = 0; f < Nf; ++f) { 304 PetscObject disc; 305 const char *fname; 306 char tmpname[PETSC_MAX_PATH_LEN]; 307 308 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 309 /* TODO Create names for components */ 310 for (PetscInt c = 0; c < Nc[f]; ++c, ++l) { 311 PetscCall(PetscObjectGetName(disc, &fname)); 312 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 313 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 314 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 315 PetscCall(PetscStrallocpy(tmpname, &names[l])); 316 } 317 } 318 } 319 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 320 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 321 PetscCall(VecGetArrayRead(coordinates, &coords)); 322 for (PetscInt i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 323 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 324 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 325 PetscSection s; 326 PetscInt dof; 327 328 PetscCall(DMGetLocalSection(dm, &s)); 329 PetscCall(PetscSectionGetDof(s, eStart, &dof)); 330 if (dof) { 331 // P_2 332 PetscInt vFirst = -1; 333 334 for (PetscInt e = eStart; e < eEnd; ++e) { 335 PetscScalar *xa, *xb, *svals; 336 const PetscInt *cone; 337 338 PetscCall(DMPlexGetCone(dm, e, &cone)); 339 PetscCall(DMPlexPointLocalRead(cdm, cone[0], coords, &xa)); 340 PetscCall(DMPlexPointLocalRead(cdm, cone[1], coords, &xb)); 341 if (e == eStart) vFirst = cone[0]; 342 for (PetscInt i = 0; i < n; ++i) { 343 PetscCall(DMPlexPointLocalRead(dm, cone[0], sol[i], &svals)); 344 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 345 } 346 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xa[0]), vals)); 347 if (e == eEnd - 1 && cone[1] != vFirst) { 348 for (PetscInt i = 0; i < n; ++i) { 349 PetscCall(DMPlexPointLocalRead(dm, e, sol[i], &svals)); 350 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 351 } 352 PetscCall(PetscDrawLGAddCommonPoint(lg, 0.5 * (PetscRealPart(xa[0]) + PetscRealPart(xb[0])), vals)); 353 for (PetscInt i = 0; i < n; ++i) { 354 PetscCall(DMPlexPointLocalRead(dm, cone[1], sol[i], &svals)); 355 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 356 } 357 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(xb[0]), vals)); 358 } 359 } 360 } else { 361 // P_1 362 for (PetscInt v = vStart; v < vEnd; ++v) { 363 PetscScalar *x, *svals; 364 365 PetscCall(DMPlexPointLocalRead(cdm, v, coords, &x)); 366 for (PetscInt i = 0; i < n; ++i) { 367 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 368 for (PetscInt l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 369 } 370 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 371 } 372 } 373 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 374 for (PetscInt i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 375 for (PetscInt l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 376 PetscCall(PetscFree3(sol, names, vals)); 377 378 PetscCall(PetscDrawLGDraw(lg)); 379 PetscCall(PetscDrawLGDestroy(&lg)); 380 PetscFunctionReturn(PETSC_SUCCESS); 381 } 382 383 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 384 { 385 DM dm; 386 387 PetscFunctionBegin; 388 PetscCall(VecGetDM(u, &dm)); 389 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 390 PetscFunctionReturn(PETSC_SUCCESS); 391 } 392 393 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 394 { 395 DM dm; 396 PetscSection s; 397 PetscDraw draw, popup; 398 DM cdm; 399 PetscSection coordSection; 400 Vec coordinates; 401 const PetscScalar *array; 402 PetscReal lbound[3], ubound[3]; 403 PetscReal vbound[2], time; 404 PetscBool flg; 405 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 406 const char *name; 407 char title[PETSC_MAX_PATH_LEN]; 408 409 PetscFunctionBegin; 410 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 411 PetscCall(VecGetDM(v, &dm)); 412 PetscCall(DMGetCoordinateDim(dm, &dim)); 413 PetscCall(DMGetLocalSection(dm, &s)); 414 PetscCall(PetscSectionGetNumFields(s, &Nf)); 415 PetscCall(DMGetCoarsenLevel(dm, &level)); 416 PetscCall(DMGetCoordinateDM(dm, &cdm)); 417 PetscCall(DMGetLocalSection(cdm, &coordSection)); 418 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 419 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 420 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 421 422 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 423 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 424 425 PetscCall(VecGetLocalSize(coordinates, &N)); 426 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 427 PetscCall(PetscDrawClear(draw)); 428 429 /* Could implement something like DMDASelectFields() */ 430 for (f = 0; f < Nf; ++f) { 431 DM fdm = dm; 432 Vec fv = v; 433 IS fis; 434 char prefix[PETSC_MAX_PATH_LEN]; 435 const char *fname; 436 437 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 438 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 439 440 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 441 else prefix[0] = '\0'; 442 if (Nf > 1) { 443 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 444 PetscCall(VecGetSubVector(v, fis, &fv)); 445 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 446 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 447 } 448 for (comp = 0; comp < Nc; ++comp, ++w) { 449 PetscInt nmax = 2; 450 451 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 452 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 453 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 454 PetscCall(PetscDrawSetTitle(draw, title)); 455 456 /* TODO Get max and min only for this component */ 457 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 458 if (!flg) { 459 PetscCall(VecMin(fv, NULL, &vbound[0])); 460 PetscCall(VecMax(fv, NULL, &vbound[1])); 461 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 462 } 463 464 PetscCall(PetscDrawGetPopup(draw, &popup)); 465 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 466 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 467 PetscCall(VecGetArrayRead(fv, &array)); 468 for (c = cStart; c < cEnd; ++c) { 469 DMPolytopeType ct; 470 PetscScalar *coords = NULL, *a = NULL; 471 const PetscScalar *coords_arr; 472 PetscBool isDG; 473 PetscInt numCoords; 474 int color[4] = {-1, -1, -1, -1}; 475 476 PetscCall(DMPlexGetCellType(dm, c, &ct)); 477 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 478 if (a) { 479 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 480 color[1] = color[2] = color[3] = color[0]; 481 } else { 482 PetscScalar *vals = NULL; 483 PetscInt numVals, va; 484 485 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 486 if (!numVals) { 487 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 488 continue; 489 } 490 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); 491 switch (numVals / Nc) { 492 case 1: /* P1 Clamped Segment Prism */ 493 case 2: /* P1 Segment Prism, P2 Clamped Segment Prism */ 494 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]); 495 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 496 break; 497 case 3: /* P1 Triangle */ 498 case 4: /* P1 Quadrangle */ 499 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]); 500 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 501 break; 502 case 6: /* P2 Triangle */ 503 case 8: /* P2 Quadrangle */ 504 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]); 505 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 506 break; 507 default: 508 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 509 } 510 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 511 } 512 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 513 switch (numCoords) { 514 case 6: 515 case 12: /* Localized triangle */ 516 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])); 517 break; 518 case 8: 519 case 16: /* Localized quadrilateral */ 520 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR) { 521 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscMax(color[0], color[1]))); 522 } else { 523 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])); 524 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])); 525 } 526 break; 527 default: 528 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 529 } 530 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 531 } 532 PetscCall(VecRestoreArrayRead(fv, &array)); 533 PetscCall(PetscDrawFlush(draw)); 534 PetscCall(PetscDrawPause(draw)); 535 PetscCall(PetscDrawSave(draw)); 536 } 537 if (Nf > 1) { 538 PetscCall(VecRestoreSubVector(v, fis, &fv)); 539 PetscCall(ISDestroy(&fis)); 540 PetscCall(DMDestroy(&fdm)); 541 } 542 } 543 PetscFunctionReturn(PETSC_SUCCESS); 544 } 545 546 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 547 { 548 DM dm; 549 PetscDraw draw; 550 PetscInt dim; 551 PetscBool isnull; 552 553 PetscFunctionBegin; 554 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 555 PetscCall(PetscDrawIsNull(draw, &isnull)); 556 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 557 558 PetscCall(VecGetDM(v, &dm)); 559 PetscCall(DMGetCoordinateDim(dm, &dim)); 560 switch (dim) { 561 case 1: 562 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 563 break; 564 case 2: 565 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 566 break; 567 default: 568 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 569 } 570 PetscFunctionReturn(PETSC_SUCCESS); 571 } 572 573 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 574 { 575 DM dm; 576 Vec locv; 577 const char *name; 578 PetscSection section; 579 PetscInt pStart, pEnd; 580 PetscInt numFields; 581 PetscViewerVTKFieldType ft; 582 583 PetscFunctionBegin; 584 PetscCall(VecGetDM(v, &dm)); 585 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 586 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 587 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 588 PetscCall(VecCopy(v, locv)); 589 PetscCall(DMGetLocalSection(dm, §ion)); 590 PetscCall(PetscSectionGetNumFields(section, &numFields)); 591 if (!numFields) { 592 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 593 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 594 } else { 595 PetscInt f; 596 597 for (f = 0; f < numFields; f++) { 598 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 599 if (ft == PETSC_VTK_INVALID) continue; 600 PetscCall(PetscObjectReference((PetscObject)locv)); 601 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 602 } 603 PetscCall(VecDestroy(&locv)); 604 } 605 PetscFunctionReturn(PETSC_SUCCESS); 606 } 607 608 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 609 { 610 DM dm; 611 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns, ispython; 612 613 PetscFunctionBegin; 614 PetscCall(VecGetDM(v, &dm)); 615 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 616 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 617 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 618 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 619 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 620 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 621 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 622 if (isvtk || ishdf5 || isdraw || isglvis || iscgns || ispython) { 623 PetscInt i, numFields; 624 PetscObject fe; 625 PetscBool fem = PETSC_FALSE; 626 Vec locv = v; 627 const char *name; 628 PetscInt step; 629 PetscReal time; 630 631 PetscCall(DMGetNumFields(dm, &numFields)); 632 for (i = 0; i < numFields; i++) { 633 PetscCall(DMGetField(dm, i, NULL, &fe)); 634 if (fe->classid == PETSCFE_CLASSID) { 635 fem = PETSC_TRUE; 636 break; 637 } 638 } 639 if (fem) { 640 PetscObject isZero; 641 642 PetscCall(DMGetLocalVector(dm, &locv)); 643 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 644 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 645 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 646 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 647 PetscCall(VecCopy(v, locv)); 648 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 649 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 650 } 651 if (isvtk) { 652 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 653 } else if (ishdf5) { 654 #if defined(PETSC_HAVE_HDF5) 655 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 656 #else 657 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 658 #endif 659 } else if (isdraw) { 660 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 661 } else if (ispython) { 662 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)locv)); 663 } else if (isglvis) { 664 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 665 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 666 PetscCall(VecView_GLVis(locv, viewer)); 667 } else if (iscgns) { 668 #if defined(PETSC_HAVE_CGNS) 669 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 670 #else 671 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 672 #endif 673 } 674 if (fem) { 675 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 676 PetscCall(DMRestoreLocalVector(dm, &locv)); 677 } 678 } else { 679 PetscBool isseq; 680 681 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 682 if (isseq) PetscCall(VecView_Seq(v, viewer)); 683 else PetscCall(VecView_MPI(v, viewer)); 684 } 685 PetscFunctionReturn(PETSC_SUCCESS); 686 } 687 688 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 689 { 690 DM dm; 691 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns, ispython; 692 693 PetscFunctionBegin; 694 PetscCall(VecGetDM(v, &dm)); 695 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 696 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 697 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 698 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 699 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 700 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 701 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 702 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 703 if (isvtk || isdraw || isglvis || iscgns || ispython) { 704 Vec locv; 705 PetscObject isZero; 706 const char *name; 707 708 PetscCall(DMGetLocalVector(dm, &locv)); 709 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 710 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 711 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 712 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 713 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 714 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 715 PetscCall(VecView_Plex_Local(locv, viewer)); 716 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 717 PetscCall(DMRestoreLocalVector(dm, &locv)); 718 } else if (ishdf5) { 719 #if defined(PETSC_HAVE_HDF5) 720 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 721 #else 722 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 723 #endif 724 } else if (isexodusii) { 725 #if defined(PETSC_HAVE_EXODUSII) 726 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 727 #else 728 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 729 #endif 730 } else { 731 PetscBool isseq; 732 733 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 734 if (isseq) PetscCall(VecView_Seq(v, viewer)); 735 else PetscCall(VecView_MPI(v, viewer)); 736 } 737 PetscFunctionReturn(PETSC_SUCCESS); 738 } 739 740 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 741 { 742 DM dm; 743 MPI_Comm comm; 744 PetscViewerFormat format; 745 Vec v; 746 PetscBool isvtk, ishdf5; 747 748 PetscFunctionBegin; 749 PetscCall(VecGetDM(originalv, &dm)); 750 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 751 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 752 PetscCall(PetscViewerGetFormat(viewer, &format)); 753 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 754 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 755 if (format == PETSC_VIEWER_NATIVE) { 756 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 757 /* this need a better fix */ 758 if (dm->useNatural) { 759 if (dm->sfNatural) { 760 const char *vecname; 761 PetscInt n, nroots; 762 763 PetscCall(VecGetLocalSize(originalv, &n)); 764 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 765 if (n == nroots) { 766 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 767 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 768 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 769 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 770 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 771 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 772 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 773 } else v = originalv; 774 } else v = originalv; 775 776 if (ishdf5) { 777 #if defined(PETSC_HAVE_HDF5) 778 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 779 #else 780 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 781 #endif 782 } else if (isvtk) { 783 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 784 } else { 785 PetscBool isseq; 786 787 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 788 if (isseq) PetscCall(VecView_Seq(v, viewer)); 789 else PetscCall(VecView_MPI(v, viewer)); 790 } 791 if (v != originalv) PetscCall(VecDestroy(&v)); 792 PetscFunctionReturn(PETSC_SUCCESS); 793 } 794 795 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 796 { 797 DM dm; 798 PetscBool ishdf5; 799 800 PetscFunctionBegin; 801 PetscCall(VecGetDM(v, &dm)); 802 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 803 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 804 if (ishdf5) { 805 DM dmBC; 806 Vec gv; 807 const char *name; 808 809 PetscCall(DMGetOutputDM(dm, &dmBC)); 810 PetscCall(DMGetGlobalVector(dmBC, &gv)); 811 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 812 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 813 PetscCall(VecLoad_Default(gv, viewer)); 814 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 815 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 816 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 817 } else PetscCall(VecLoad_Default(v, viewer)); 818 PetscFunctionReturn(PETSC_SUCCESS); 819 } 820 821 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 822 { 823 DM dm; 824 PetscBool ishdf5, isexodusii, iscgns; 825 826 PetscFunctionBegin; 827 PetscCall(VecGetDM(v, &dm)); 828 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 829 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 830 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 831 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 832 if (ishdf5) { 833 #if defined(PETSC_HAVE_HDF5) 834 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 835 #else 836 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 837 #endif 838 } else if (isexodusii) { 839 #if defined(PETSC_HAVE_EXODUSII) 840 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 841 #else 842 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 843 #endif 844 } else if (iscgns) { 845 #if defined(PETSC_HAVE_CGNS) 846 PetscCall(VecLoad_Plex_CGNS_Internal(v, viewer)); 847 #else 848 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 849 #endif 850 } else PetscCall(VecLoad_Default(v, viewer)); 851 PetscFunctionReturn(PETSC_SUCCESS); 852 } 853 854 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 855 { 856 DM dm; 857 PetscViewerFormat format; 858 PetscBool ishdf5; 859 860 PetscFunctionBegin; 861 PetscCall(VecGetDM(originalv, &dm)); 862 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 863 PetscCall(PetscViewerGetFormat(viewer, &format)); 864 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 865 if (format == PETSC_VIEWER_NATIVE) { 866 if (dm->useNatural) { 867 if (dm->sfNatural) { 868 if (ishdf5) { 869 #if defined(PETSC_HAVE_HDF5) 870 Vec v; 871 const char *vecname; 872 873 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 874 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 875 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 876 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 877 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 878 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 879 PetscCall(VecDestroy(&v)); 880 #else 881 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 882 #endif 883 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 884 } 885 } else PetscCall(VecLoad_Default(originalv, viewer)); 886 } 887 PetscFunctionReturn(PETSC_SUCCESS); 888 } 889 890 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 891 { 892 PetscSection coordSection; 893 Vec coordinates; 894 DMLabel depthLabel, celltypeLabel; 895 const char *name[4]; 896 const PetscScalar *a; 897 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 898 899 PetscFunctionBegin; 900 PetscCall(DMGetDimension(dm, &dim)); 901 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 902 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 903 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 904 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 905 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 906 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 907 PetscCall(VecGetArrayRead(coordinates, &a)); 908 name[0] = "vertex"; 909 name[1] = "edge"; 910 name[dim - 1] = "face"; 911 name[dim] = "cell"; 912 for (c = cStart; c < cEnd; ++c) { 913 PetscInt *closure = NULL; 914 PetscInt closureSize, cl, ct; 915 916 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 917 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 918 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 919 PetscCall(PetscViewerASCIIPushTab(viewer)); 920 for (cl = 0; cl < closureSize * 2; cl += 2) { 921 PetscInt point = closure[cl], depth, dof, off, d, p; 922 923 if ((point < pStart) || (point >= pEnd)) continue; 924 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 925 if (!dof) continue; 926 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 927 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 928 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 929 for (p = 0; p < dof / dim; ++p) { 930 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 931 for (d = 0; d < dim; ++d) { 932 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 933 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 934 } 935 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 936 } 937 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 938 } 939 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 940 PetscCall(PetscViewerASCIIPopTab(viewer)); 941 } 942 PetscCall(VecRestoreArrayRead(coordinates, &a)); 943 PetscFunctionReturn(PETSC_SUCCESS); 944 } 945 946 typedef enum { 947 CS_CARTESIAN, 948 CS_POLAR, 949 CS_CYLINDRICAL, 950 CS_SPHERICAL 951 } CoordSystem; 952 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 953 954 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 955 { 956 PetscInt i; 957 958 PetscFunctionBegin; 959 if (dim > 3) { 960 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 961 } else { 962 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 963 964 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 965 switch (cs) { 966 case CS_CARTESIAN: 967 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 968 break; 969 case CS_POLAR: 970 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 971 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 972 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 973 break; 974 case CS_CYLINDRICAL: 975 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 976 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 977 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 978 trcoords[2] = coords[2]; 979 break; 980 case CS_SPHERICAL: 981 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 982 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 983 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 984 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 985 break; 986 } 987 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 988 } 989 PetscFunctionReturn(PETSC_SUCCESS); 990 } 991 992 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 993 { 994 DM_Plex *mesh = (DM_Plex *)dm->data; 995 DM cdm, cdmCell; 996 PetscSection coordSection, coordSectionCell; 997 Vec coordinates, coordinatesCell; 998 PetscViewerFormat format; 999 1000 PetscFunctionBegin; 1001 PetscCall(PetscViewerGetFormat(viewer, &format)); 1002 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 1003 const char *name; 1004 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 1005 PetscInt pStart, pEnd, p, numLabels, l; 1006 PetscMPIInt rank, size; 1007 1008 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1009 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1010 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1011 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1012 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1013 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1014 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1015 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1016 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1017 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1018 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1019 PetscCall(DMGetDimension(dm, &dim)); 1020 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1021 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1022 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1023 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 1025 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1026 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 1027 for (p = pStart; p < pEnd; ++p) { 1028 PetscInt dof, off, s; 1029 1030 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 1031 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 1032 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 1033 } 1034 PetscCall(PetscViewerFlush(viewer)); 1035 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 1036 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 1037 for (p = pStart; p < pEnd; ++p) { 1038 PetscInt dof, off, c; 1039 1040 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 1041 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 1042 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])); 1043 } 1044 PetscCall(PetscViewerFlush(viewer)); 1045 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1046 if (coordSection && coordinates) { 1047 CoordSystem cs = CS_CARTESIAN; 1048 const PetscScalar *array, *arrayCell = NULL; 1049 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_INT_MAX, pcEnd = PETSC_INT_MIN, pStart, pEnd, p; 1050 PetscMPIInt rank; 1051 const char *name; 1052 1053 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 1054 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1055 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 1056 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 1057 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 1058 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 1059 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 1060 pStart = PetscMin(pvStart, pcStart); 1061 pEnd = PetscMax(pvEnd, pcEnd); 1062 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 1063 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 1064 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 1065 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 1066 1067 PetscCall(VecGetArrayRead(coordinates, &array)); 1068 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 1069 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1070 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1071 for (p = pStart; p < pEnd; ++p) { 1072 PetscInt dof, off; 1073 1074 if (p >= pvStart && p < pvEnd) { 1075 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1076 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1077 if (dof) { 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1079 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1080 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1081 } 1082 } 1083 if (cdmCell && p >= pcStart && p < pcEnd) { 1084 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1085 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1086 if (dof) { 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1088 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1089 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1090 } 1091 } 1092 } 1093 PetscCall(PetscViewerFlush(viewer)); 1094 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1095 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1096 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1097 } 1098 PetscCall(DMGetNumLabels(dm, &numLabels)); 1099 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1100 for (l = 0; l < numLabels; ++l) { 1101 DMLabel label; 1102 PetscBool isdepth; 1103 const char *name; 1104 1105 PetscCall(DMGetLabelName(dm, l, &name)); 1106 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1107 if (isdepth) continue; 1108 PetscCall(DMGetLabel(dm, name, &label)); 1109 PetscCall(DMLabelView(label, viewer)); 1110 } 1111 if (size > 1) { 1112 PetscSF sf; 1113 1114 PetscCall(DMGetPointSF(dm, &sf)); 1115 PetscCall(PetscSFView(sf, viewer)); 1116 } 1117 if (mesh->periodic.face_sfs) 1118 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFView(mesh->periodic.face_sfs[i], viewer)); 1119 PetscCall(PetscViewerFlush(viewer)); 1120 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1121 const char *name, *color; 1122 const char *defcolors[3] = {"gray", "orange", "green"}; 1123 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1124 char lname[PETSC_MAX_PATH_LEN]; 1125 PetscReal scale = 2.0; 1126 PetscReal tikzscale = 1.0; 1127 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1128 double tcoords[3]; 1129 PetscScalar *coords; 1130 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; 1131 PetscMPIInt rank, size; 1132 char **names, **colors, **lcolors; 1133 PetscBool flg, lflg; 1134 PetscBT wp = NULL; 1135 PetscInt pEnd, pStart; 1136 1137 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1138 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1139 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1140 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1141 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1142 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1143 PetscCall(DMGetDimension(dm, &dim)); 1144 PetscCall(DMPlexGetDepth(dm, &depth)); 1145 PetscCall(DMGetNumLabels(dm, &numLabels)); 1146 numLabels = PetscMax(numLabels, 10); 1147 numColors = 10; 1148 numLColors = 10; 1149 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1150 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1151 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1152 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1153 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1154 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1155 n = 4; 1156 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1157 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1158 n = 4; 1159 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1160 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1161 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1162 if (!useLabels) numLabels = 0; 1163 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1164 if (!useColors) { 1165 numColors = 3; 1166 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1167 } 1168 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1169 if (!useColors) { 1170 numLColors = 4; 1171 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1172 } 1173 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1174 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1175 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1176 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1177 if (depth < dim) plotEdges = PETSC_FALSE; 1178 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1179 1180 /* filter points with labelvalue != labeldefaultvalue */ 1181 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1182 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1183 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1184 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1185 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 1186 if (lflg) { 1187 DMLabel lbl; 1188 1189 PetscCall(DMGetLabel(dm, lname, &lbl)); 1190 if (lbl) { 1191 PetscInt val, defval; 1192 1193 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1194 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1195 for (c = pStart; c < pEnd; c++) { 1196 PetscInt *closure = NULL; 1197 PetscInt closureSize; 1198 1199 PetscCall(DMLabelGetValue(lbl, c, &val)); 1200 if (val == defval) continue; 1201 1202 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1203 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1204 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1205 } 1206 } 1207 } 1208 1209 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1210 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1211 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1212 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1213 \\documentclass[tikz]{standalone}\n\n\ 1214 \\usepackage{pgflibraryshapes}\n\ 1215 \\usetikzlibrary{backgrounds}\n\ 1216 \\usetikzlibrary{arrows}\n\ 1217 \\begin{document}\n")); 1218 if (size > 1) { 1219 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1220 for (p = 0; p < size; ++p) { 1221 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1223 } 1224 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1225 } 1226 if (drawHasse) { 1227 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, PetscMax(fEnd - fStart, cEnd - cStart))); 1228 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1233 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1234 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1235 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1236 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1237 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fStart}{%" PetscInt_FMT "}\n", fStart)); 1238 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fEnd}{%" PetscInt_FMT "}\n", fEnd - 1)); 1239 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\fShift}{%.2f}\n", 3 + (maxStratum - (fEnd - fStart)) / 2.)); 1240 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numFaces}{%" PetscInt_FMT "}\n", fEnd - fStart)); 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1242 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1243 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1244 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1245 } 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1247 1248 /* Plot vertices */ 1249 PetscCall(VecGetArray(coordinates, &coords)); 1250 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1251 for (v = vStart; v < vEnd; ++v) { 1252 PetscInt off, dof, d; 1253 PetscBool isLabeled = PETSC_FALSE; 1254 1255 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1256 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1257 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1258 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1259 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1260 for (d = 0; d < dof; ++d) { 1261 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1262 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1263 } 1264 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1265 if (dim == 3) { 1266 PetscReal tmp = tcoords[1]; 1267 tcoords[1] = tcoords[2]; 1268 tcoords[2] = -tmp; 1269 } 1270 for (d = 0; d < dof; ++d) { 1271 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1272 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1273 } 1274 if (drawHasse) color = colors[0 % numColors]; 1275 else color = colors[rank % numColors]; 1276 for (l = 0; l < numLabels; ++l) { 1277 PetscInt val; 1278 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1279 if (val >= 0) { 1280 color = lcolors[l % numLColors]; 1281 isLabeled = PETSC_TRUE; 1282 break; 1283 } 1284 } 1285 if (drawNumbers[0]) { 1286 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1287 } else if (drawColors[0]) { 1288 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1289 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1290 } 1291 PetscCall(VecRestoreArray(coordinates, &coords)); 1292 PetscCall(PetscViewerFlush(viewer)); 1293 /* Plot edges */ 1294 if (plotEdges) { 1295 PetscCall(VecGetArray(coordinates, &coords)); 1296 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1297 for (e = eStart; e < eEnd; ++e) { 1298 const PetscInt *cone; 1299 PetscInt coneSize, offA, offB, dof, d; 1300 1301 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1302 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1303 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1304 PetscCall(DMPlexGetCone(dm, e, &cone)); 1305 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1306 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1307 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1308 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1309 for (d = 0; d < dof; ++d) { 1310 tcoords[d] = (double)(scale * PetscRealPart(coords[offA + d] + coords[offB + d]) / 2); 1311 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1312 } 1313 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1314 if (dim == 3) { 1315 PetscReal tmp = tcoords[1]; 1316 tcoords[1] = tcoords[2]; 1317 tcoords[2] = -tmp; 1318 } 1319 for (d = 0; d < dof; ++d) { 1320 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1321 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d])); 1322 } 1323 if (drawHasse) color = colors[1 % numColors]; 1324 else color = colors[rank % numColors]; 1325 for (l = 0; l < numLabels; ++l) { 1326 PetscInt val; 1327 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1328 if (val >= 0) { 1329 color = lcolors[l % numLColors]; 1330 break; 1331 } 1332 } 1333 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1334 } 1335 PetscCall(VecRestoreArray(coordinates, &coords)); 1336 PetscCall(PetscViewerFlush(viewer)); 1337 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1338 } 1339 /* Plot cells */ 1340 if (dim == 3 || !drawNumbers[1]) { 1341 for (e = eStart; e < eEnd; ++e) { 1342 const PetscInt *cone; 1343 1344 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1345 color = colors[rank % numColors]; 1346 for (l = 0; l < numLabels; ++l) { 1347 PetscInt val; 1348 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1349 if (val >= 0) { 1350 color = lcolors[l % numLColors]; 1351 break; 1352 } 1353 } 1354 PetscCall(DMPlexGetCone(dm, e, &cone)); 1355 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1356 } 1357 } else { 1358 DMPolytopeType ct; 1359 1360 /* Drawing a 2D polygon */ 1361 for (c = cStart; c < cEnd; ++c) { 1362 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1363 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1364 if (DMPolytopeTypeIsHybrid(ct)) { 1365 const PetscInt *cone; 1366 PetscInt coneSize, e; 1367 1368 PetscCall(DMPlexGetCone(dm, c, &cone)); 1369 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1370 for (e = 0; e < coneSize; ++e) { 1371 const PetscInt *econe; 1372 1373 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1374 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)); 1375 } 1376 } else { 1377 PetscInt *closure = NULL; 1378 PetscInt closureSize, Nv = 0, v; 1379 1380 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1381 for (p = 0; p < closureSize * 2; p += 2) { 1382 const PetscInt point = closure[p]; 1383 1384 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1385 } 1386 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1387 for (v = 0; v <= Nv; ++v) { 1388 const PetscInt vertex = closure[v % Nv]; 1389 1390 if (v > 0) { 1391 if (plotEdges) { 1392 const PetscInt *edge; 1393 PetscInt endpoints[2], ne; 1394 1395 endpoints[0] = closure[v - 1]; 1396 endpoints[1] = vertex; 1397 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1398 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1399 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1400 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1401 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1402 } 1403 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1404 } 1405 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1406 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1407 } 1408 } 1409 } 1410 for (c = cStart; c < cEnd; ++c) { 1411 double ccoords[3] = {0.0, 0.0, 0.0}; 1412 PetscBool isLabeled = PETSC_FALSE; 1413 PetscScalar *cellCoords = NULL; 1414 const PetscScalar *array; 1415 PetscInt numCoords, cdim, d; 1416 PetscBool isDG; 1417 1418 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1419 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1420 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1421 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1422 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1423 for (p = 0; p < numCoords / cdim; ++p) { 1424 for (d = 0; d < cdim; ++d) { 1425 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1426 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1427 } 1428 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1429 if (cdim == 3) { 1430 PetscReal tmp = tcoords[1]; 1431 tcoords[1] = tcoords[2]; 1432 tcoords[2] = -tmp; 1433 } 1434 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1435 } 1436 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1437 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1438 for (d = 0; d < cdim; ++d) { 1439 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1440 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", ccoords[d])); 1441 } 1442 if (drawHasse) color = colors[depth % numColors]; 1443 else color = colors[rank % numColors]; 1444 for (l = 0; l < numLabels; ++l) { 1445 PetscInt val; 1446 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1447 if (val >= 0) { 1448 color = lcolors[l % numLColors]; 1449 isLabeled = PETSC_TRUE; 1450 break; 1451 } 1452 } 1453 if (drawNumbers[dim]) { 1454 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1455 } else if (drawColors[dim]) { 1456 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1457 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1458 } 1459 if (drawHasse) { 1460 int height = 0; 1461 1462 color = colors[depth % numColors]; 1463 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1464 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1465 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1466 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,%d) {\\c};\n", rank, color, height++)); 1467 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1468 1469 if (depth > 2) { 1470 color = colors[1 % numColors]; 1471 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Faces\n")); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\f in {\\fStart,...,\\fEnd}\n")); 1473 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1474 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\f_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\fShift+\\f-\\fStart,%d) {\\f};\n", rank, color, height++)); 1475 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1476 } 1477 1478 color = colors[1 % numColors]; 1479 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1480 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1481 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,%d) {\\e};\n", rank, color, height++)); 1483 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1484 1485 color = colors[0 % numColors]; 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1489 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,%d) {\\v};\n", rank, color, height++)); 1490 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1491 1492 for (p = pStart; p < pEnd; ++p) { 1493 const PetscInt *cone; 1494 PetscInt coneSize, cp; 1495 1496 PetscCall(DMPlexGetCone(dm, p, &cone)); 1497 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1498 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1499 } 1500 } 1501 PetscCall(PetscViewerFlush(viewer)); 1502 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1504 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1505 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1506 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1507 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1508 PetscCall(PetscFree3(names, colors, lcolors)); 1509 PetscCall(PetscBTDestroy(&wp)); 1510 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1511 Vec cown, acown; 1512 VecScatter sct; 1513 ISLocalToGlobalMapping g2l; 1514 IS gid, acis; 1515 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1516 MPI_Group ggroup, ngroup; 1517 PetscScalar *array, nid; 1518 const PetscInt *idxs; 1519 PetscInt *idxs2, *start, *adjacency, *work; 1520 PetscInt64 lm[3], gm[3]; 1521 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1522 PetscMPIInt d1, d2, rank; 1523 1524 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1525 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1526 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1527 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1528 #endif 1529 if (ncomm != MPI_COMM_NULL) { 1530 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1531 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1532 d1 = 0; 1533 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1534 nid = d2; 1535 PetscCallMPI(MPI_Group_free(&ggroup)); 1536 PetscCallMPI(MPI_Group_free(&ngroup)); 1537 PetscCallMPI(MPI_Comm_free(&ncomm)); 1538 } else nid = 0.0; 1539 1540 /* Get connectivity */ 1541 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1542 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1543 1544 /* filter overlapped local cells */ 1545 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1546 PetscCall(ISGetIndices(gid, &idxs)); 1547 PetscCall(ISGetLocalSize(gid, &cum)); 1548 PetscCall(PetscMalloc1(cum, &idxs2)); 1549 for (c = cStart, cum = 0; c < cEnd; c++) { 1550 if (idxs[c - cStart] < 0) continue; 1551 idxs2[cum++] = idxs[c - cStart]; 1552 } 1553 PetscCall(ISRestoreIndices(gid, &idxs)); 1554 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1555 PetscCall(ISDestroy(&gid)); 1556 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1557 1558 /* support for node-aware cell locality */ 1559 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1560 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1561 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1562 PetscCall(VecGetArray(cown, &array)); 1563 for (c = 0; c < numVertices; c++) array[c] = nid; 1564 PetscCall(VecRestoreArray(cown, &array)); 1565 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1566 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1567 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1568 PetscCall(ISDestroy(&acis)); 1569 PetscCall(VecScatterDestroy(&sct)); 1570 PetscCall(VecDestroy(&cown)); 1571 1572 /* compute edgeCut */ 1573 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1574 PetscCall(PetscMalloc1(cum, &work)); 1575 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1576 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1577 PetscCall(ISDestroy(&gid)); 1578 PetscCall(VecGetArray(acown, &array)); 1579 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1580 PetscInt totl; 1581 1582 totl = start[c + 1] - start[c]; 1583 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1584 for (i = 0; i < totl; i++) { 1585 if (work[i] < 0) { 1586 ect += 1; 1587 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1588 } 1589 } 1590 } 1591 PetscCall(PetscFree(work)); 1592 PetscCall(VecRestoreArray(acown, &array)); 1593 lm[0] = numVertices > 0 ? numVertices : PETSC_INT_MAX; 1594 lm[1] = -numVertices; 1595 PetscCallMPI(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1596 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt64_FMT ", min %" PetscInt64_FMT, -((double)gm[1]) / ((double)gm[0]), -gm[1], gm[0])); 1597 lm[0] = ect; /* edgeCut */ 1598 lm[1] = ectn; /* node-aware edgeCut */ 1599 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1600 PetscCallMPI(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1601 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt64_FMT ")\n", gm[2])); 1602 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1603 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, gm[0] ? ((double)gm[1]) / ((double)gm[0]) : 1.)); 1604 #else 1605 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt64_FMT " (on node %.3f)\n", gm[0] / 2, 0.0)); 1606 #endif 1607 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1608 PetscCall(PetscFree(start)); 1609 PetscCall(PetscFree(adjacency)); 1610 PetscCall(VecDestroy(&acown)); 1611 } else { 1612 const char *name; 1613 PetscInt *sizes, *hybsizes, *ghostsizes; 1614 PetscInt locDepth, depth, cellHeight, dim, d; 1615 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1616 PetscInt numLabels, l, maxSize = 17; 1617 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1618 MPI_Comm comm; 1619 PetscMPIInt size, rank; 1620 1621 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1622 PetscCallMPI(MPI_Comm_size(comm, &size)); 1623 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1624 PetscCall(DMGetDimension(dm, &dim)); 1625 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1626 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1627 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1628 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1629 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1630 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1631 PetscCallMPI(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1632 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1633 gcNum = gcEnd - gcStart; 1634 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1635 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1636 for (d = 0; d <= depth; d++) { 1637 PetscInt Nc[2] = {0, 0}, ict; 1638 1639 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1640 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1641 ict = ct0; 1642 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1643 ct0 = (DMPolytopeType)ict; 1644 for (p = pStart; p < pEnd; ++p) { 1645 DMPolytopeType ct; 1646 1647 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1648 if (ct == ct0) ++Nc[0]; 1649 else ++Nc[1]; 1650 } 1651 if (size < maxSize) { 1652 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1653 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1654 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1655 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1656 for (p = 0; p < size; ++p) { 1657 if (rank == 0) { 1658 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1659 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1660 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1661 } 1662 } 1663 } else { 1664 PetscInt locMinMax[2]; 1665 1666 locMinMax[0] = Nc[0] + Nc[1]; 1667 locMinMax[1] = Nc[0] + Nc[1]; 1668 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1669 locMinMax[0] = Nc[1]; 1670 locMinMax[1] = Nc[1]; 1671 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1672 if (d == depth) { 1673 locMinMax[0] = gcNum; 1674 locMinMax[1] = gcNum; 1675 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1676 } 1677 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1678 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1679 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1680 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1681 } 1682 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1683 } 1684 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1685 { 1686 const PetscReal *maxCell; 1687 const PetscReal *L; 1688 PetscBool localized; 1689 1690 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1691 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1692 if (L || localized) { 1693 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1694 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1695 if (L) { 1696 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1697 for (d = 0; d < dim; ++d) { 1698 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1699 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1700 } 1701 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1702 } 1703 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1704 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1705 } 1706 } 1707 PetscCall(DMGetNumLabels(dm, &numLabels)); 1708 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1709 for (l = 0; l < numLabels; ++l) { 1710 DMLabel label; 1711 const char *name; 1712 PetscInt *values; 1713 PetscInt numValues, v; 1714 1715 PetscCall(DMGetLabelName(dm, l, &name)); 1716 PetscCall(DMGetLabel(dm, name, &label)); 1717 PetscCall(DMLabelGetNumValues(label, &numValues)); 1718 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1719 1720 { // Extract array of DMLabel values so it can be sorted 1721 IS is_values; 1722 const PetscInt *is_values_local = NULL; 1723 1724 PetscCall(DMLabelGetValueIS(label, &is_values)); 1725 PetscCall(ISGetIndices(is_values, &is_values_local)); 1726 PetscCall(PetscMalloc1(numValues, &values)); 1727 PetscCall(PetscArraycpy(values, is_values_local, numValues)); 1728 PetscCall(PetscSortInt(numValues, values)); 1729 PetscCall(ISRestoreIndices(is_values, &is_values_local)); 1730 PetscCall(ISDestroy(&is_values)); 1731 } 1732 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1733 for (v = 0; v < numValues; ++v) { 1734 PetscInt size; 1735 1736 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1737 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1738 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1739 } 1740 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1741 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1742 PetscCall(PetscFree(values)); 1743 } 1744 { 1745 char **labelNames; 1746 PetscInt Nl = numLabels; 1747 PetscBool flg; 1748 1749 PetscCall(PetscMalloc1(Nl, &labelNames)); 1750 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1751 for (l = 0; l < Nl; ++l) { 1752 DMLabel label; 1753 1754 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1755 if (flg) { 1756 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1757 PetscCall(DMLabelView(label, viewer)); 1758 } 1759 PetscCall(PetscFree(labelNames[l])); 1760 } 1761 PetscCall(PetscFree(labelNames)); 1762 } 1763 /* If no fields are specified, people do not want to see adjacency */ 1764 if (dm->Nf) { 1765 PetscInt f; 1766 1767 for (f = 0; f < dm->Nf; ++f) { 1768 const char *name; 1769 1770 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1771 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1772 PetscCall(PetscViewerASCIIPushTab(viewer)); 1773 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1774 if (dm->fields[f].adjacency[0]) { 1775 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1776 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1777 } else { 1778 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1779 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1780 } 1781 PetscCall(PetscViewerASCIIPopTab(viewer)); 1782 } 1783 } 1784 PetscCall(DMGetCoarseDM(dm, &cdm)); 1785 if (cdm) { 1786 PetscCall(PetscViewerASCIIPushTab(viewer)); 1787 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1788 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1789 PetscCall(PetscViewerASCIIPopTab(viewer)); 1790 } 1791 } 1792 PetscFunctionReturn(PETSC_SUCCESS); 1793 } 1794 1795 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1796 { 1797 DMPolytopeType ct; 1798 PetscMPIInt rank; 1799 PetscInt cdim; 1800 1801 PetscFunctionBegin; 1802 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1803 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1804 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1805 switch (ct) { 1806 case DM_POLYTOPE_SEGMENT: 1807 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1808 switch (cdim) { 1809 case 1: { 1810 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1811 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1812 1813 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1814 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1815 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1816 } break; 1817 case 2: { 1818 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1819 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1820 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1821 1822 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1823 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)); 1824 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)); 1825 } break; 1826 default: 1827 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1828 } 1829 break; 1830 case DM_POLYTOPE_TRIANGLE: 1831 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)); 1832 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1833 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1834 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1835 break; 1836 case DM_POLYTOPE_QUADRILATERAL: 1837 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)); 1838 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)); 1839 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1840 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1841 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1842 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1843 break; 1844 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1845 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)); 1846 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)); 1847 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1848 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1849 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1850 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1851 break; 1852 case DM_POLYTOPE_FV_GHOST: 1853 break; 1854 default: 1855 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1856 } 1857 PetscFunctionReturn(PETSC_SUCCESS); 1858 } 1859 1860 static PetscErrorCode DrawPolygon_Private(DM dm, PetscDraw draw, PetscInt cell, PetscInt Nv, const PetscReal refVertices[], const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1861 { 1862 PetscReal centroid[2] = {0., 0.}; 1863 PetscMPIInt rank; 1864 PetscMPIInt fillColor; 1865 1866 PetscFunctionBegin; 1867 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1868 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1869 for (PetscInt v = 0; v < Nv; ++v) { 1870 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / Nv; 1871 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / Nv; 1872 } 1873 for (PetscInt e = 0; e < Nv; ++e) { 1874 refCoords[0] = refVertices[e * 2 + 0]; 1875 refCoords[1] = refVertices[e * 2 + 1]; 1876 for (PetscInt d = 1; d <= edgeDiv; ++d) { 1877 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % Nv * 2 + 0] - refCoords[0]) * d / edgeDiv; 1878 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % Nv * 2 + 1] - refCoords[1]) * d / edgeDiv; 1879 } 1880 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1881 for (PetscInt d = 0; d < edgeDiv; ++d) { 1882 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)); 1883 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1884 } 1885 } 1886 PetscFunctionReturn(PETSC_SUCCESS); 1887 } 1888 1889 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1890 { 1891 DMPolytopeType ct; 1892 1893 PetscFunctionBegin; 1894 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1895 switch (ct) { 1896 case DM_POLYTOPE_TRIANGLE: { 1897 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1898 1899 PetscCall(DrawPolygon_Private(dm, draw, cell, 3, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1900 } break; 1901 case DM_POLYTOPE_QUADRILATERAL: { 1902 PetscReal refVertices[8] = {-1., -1., 1., -1., 1., 1., -1., 1.}; 1903 1904 PetscCall(DrawPolygon_Private(dm, draw, cell, 4, refVertices, coords, edgeDiv, refCoords, edgeCoords)); 1905 } break; 1906 default: 1907 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1908 } 1909 PetscFunctionReturn(PETSC_SUCCESS); 1910 } 1911 1912 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1913 { 1914 PetscDraw draw; 1915 DM cdm; 1916 PetscSection coordSection; 1917 Vec coordinates; 1918 PetscReal xyl[3], xyr[3]; 1919 PetscReal *refCoords, *edgeCoords; 1920 PetscBool isnull, drawAffine; 1921 PetscInt dim, vStart, vEnd, cStart, cEnd, c, cDegree, edgeDiv; 1922 1923 PetscFunctionBegin; 1924 PetscCall(DMGetCoordinateDim(dm, &dim)); 1925 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1926 PetscCall(DMGetCoordinateDegree_Internal(dm, &cDegree)); 1927 drawAffine = cDegree > 1 ? PETSC_FALSE : PETSC_TRUE; 1928 edgeDiv = cDegree + 1; 1929 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1930 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1931 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1932 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1933 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1934 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1935 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1936 1937 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1938 PetscCall(PetscDrawIsNull(draw, &isnull)); 1939 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1940 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1941 1942 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1943 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1944 PetscCall(PetscDrawClear(draw)); 1945 1946 for (c = cStart; c < cEnd; ++c) { 1947 PetscScalar *coords = NULL; 1948 const PetscScalar *coords_arr; 1949 PetscInt numCoords; 1950 PetscBool isDG; 1951 1952 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1953 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1954 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1955 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1956 } 1957 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1958 PetscCall(PetscDrawFlush(draw)); 1959 PetscCall(PetscDrawPause(draw)); 1960 PetscCall(PetscDrawSave(draw)); 1961 PetscFunctionReturn(PETSC_SUCCESS); 1962 } 1963 1964 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1965 { 1966 DM odm = dm, rdm = dm, cdm; 1967 PetscFE fe; 1968 PetscSpace sp; 1969 PetscClassId id; 1970 PetscInt degree; 1971 PetscBool hoView = PETSC_TRUE; 1972 1973 PetscFunctionBegin; 1974 PetscObjectOptionsBegin((PetscObject)dm); 1975 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1976 PetscOptionsEnd(); 1977 PetscCall(PetscObjectReference((PetscObject)dm)); 1978 *hdm = dm; 1979 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1980 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1981 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1982 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1983 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1984 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1985 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1986 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1987 DM cdm, rcdm; 1988 Mat In; 1989 Vec cl, rcl; 1990 1991 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1992 PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1993 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1994 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1995 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1996 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1997 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1998 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1999 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 2000 PetscCall(MatMult(In, cl, rcl)); 2001 PetscCall(MatDestroy(&In)); 2002 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 2003 PetscCall(DMDestroy(&odm)); 2004 odm = rdm; 2005 } 2006 *hdm = rdm; 2007 PetscFunctionReturn(PETSC_SUCCESS); 2008 } 2009 2010 #if defined(PETSC_HAVE_EXODUSII) 2011 #include <exodusII.h> 2012 #include <petscviewerexodusii.h> 2013 #endif 2014 2015 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 2016 { 2017 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns, ispython; 2018 char name[PETSC_MAX_PATH_LEN]; 2019 2020 PetscFunctionBegin; 2021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2022 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2023 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2024 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 2025 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2026 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 2027 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 2028 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 2029 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 2030 PetscCall(PetscObjectHasFunction((PetscObject)viewer, "PetscViewerPythonViewObject_C", &ispython)); 2031 if (iascii) { 2032 PetscViewerFormat format; 2033 PetscCall(PetscViewerGetFormat(viewer, &format)); 2034 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 2035 else PetscCall(DMPlexView_Ascii(dm, viewer)); 2036 } else if (ishdf5) { 2037 #if defined(PETSC_HAVE_HDF5) 2038 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 2039 #else 2040 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2041 #endif 2042 } else if (isvtk) { 2043 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 2044 } else if (isdraw) { 2045 DM hdm; 2046 2047 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 2048 PetscCall(DMPlexView_Draw(hdm, viewer)); 2049 PetscCall(DMDestroy(&hdm)); 2050 } else if (isglvis) { 2051 PetscCall(DMPlexView_GLVis(dm, viewer)); 2052 #if defined(PETSC_HAVE_EXODUSII) 2053 } else if (isexodus) { 2054 /* 2055 exodusII requires that all sets be part of exactly one cell set. 2056 If the dm does not have a "Cell Sets" label defined, we create one 2057 with ID 1, containing all cells. 2058 Note that if the Cell Sets label is defined but does not cover all cells, 2059 we may still have a problem. This should probably be checked here or in the viewer; 2060 */ 2061 PetscInt numCS; 2062 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 2063 if (!numCS) { 2064 PetscInt cStart, cEnd, c; 2065 PetscCall(DMCreateLabel(dm, "Cell Sets")); 2066 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2067 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 2068 } 2069 PetscCall(DMView_PlexExodusII(dm, viewer)); 2070 #endif 2071 #if defined(PETSC_HAVE_CGNS) 2072 } else if (iscgns) { 2073 PetscCall(DMView_PlexCGNS(dm, viewer)); 2074 #endif 2075 } else if (ispython) { 2076 PetscCall(PetscViewerPythonViewObject(viewer, (PetscObject)dm)); 2077 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 2078 /* Optionally view the partition */ 2079 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 2080 if (flg) { 2081 Vec ranks; 2082 PetscCall(DMPlexCreateRankField(dm, &ranks)); 2083 PetscCall(VecView(ranks, viewer)); 2084 PetscCall(VecDestroy(&ranks)); 2085 } 2086 /* Optionally view a label */ 2087 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 2088 if (flg) { 2089 DMLabel label; 2090 Vec val; 2091 2092 PetscCall(DMGetLabel(dm, name, &label)); 2093 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 2094 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 2095 PetscCall(VecView(val, viewer)); 2096 PetscCall(VecDestroy(&val)); 2097 } 2098 PetscFunctionReturn(PETSC_SUCCESS); 2099 } 2100 2101 /*@ 2102 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 2103 2104 Collective 2105 2106 Input Parameters: 2107 + dm - The `DM` whose topology is to be saved 2108 - viewer - The `PetscViewer` to save it in 2109 2110 Level: advanced 2111 2112 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 2113 @*/ 2114 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2115 { 2116 PetscBool ishdf5; 2117 2118 PetscFunctionBegin; 2119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2120 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2121 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2122 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2123 if (ishdf5) { 2124 #if defined(PETSC_HAVE_HDF5) 2125 PetscViewerFormat format; 2126 PetscCall(PetscViewerGetFormat(viewer, &format)); 2127 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2128 IS globalPointNumbering; 2129 2130 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2131 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2132 PetscCall(ISDestroy(&globalPointNumbering)); 2133 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2134 #else 2135 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2136 #endif 2137 } 2138 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2139 PetscFunctionReturn(PETSC_SUCCESS); 2140 } 2141 2142 /*@ 2143 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2144 2145 Collective 2146 2147 Input Parameters: 2148 + dm - The `DM` whose coordinates are to be saved 2149 - viewer - The `PetscViewer` for saving 2150 2151 Level: advanced 2152 2153 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2154 @*/ 2155 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2156 { 2157 PetscBool ishdf5; 2158 2159 PetscFunctionBegin; 2160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2161 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2162 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2163 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2164 if (ishdf5) { 2165 #if defined(PETSC_HAVE_HDF5) 2166 PetscViewerFormat format; 2167 PetscCall(PetscViewerGetFormat(viewer, &format)); 2168 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2169 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2170 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2171 #else 2172 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2173 #endif 2174 } 2175 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2176 PetscFunctionReturn(PETSC_SUCCESS); 2177 } 2178 2179 /*@ 2180 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2181 2182 Collective 2183 2184 Input Parameters: 2185 + dm - The `DM` whose labels are to be saved 2186 - viewer - The `PetscViewer` for saving 2187 2188 Level: advanced 2189 2190 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2191 @*/ 2192 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2193 { 2194 PetscBool ishdf5; 2195 2196 PetscFunctionBegin; 2197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2198 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2199 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2200 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2201 if (ishdf5) { 2202 #if defined(PETSC_HAVE_HDF5) 2203 IS globalPointNumbering; 2204 PetscViewerFormat format; 2205 2206 PetscCall(PetscViewerGetFormat(viewer, &format)); 2207 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2208 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2209 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2210 PetscCall(ISDestroy(&globalPointNumbering)); 2211 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2212 #else 2213 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2214 #endif 2215 } 2216 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2217 PetscFunctionReturn(PETSC_SUCCESS); 2218 } 2219 2220 /*@ 2221 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2222 2223 Collective 2224 2225 Input Parameters: 2226 + dm - The `DM` that contains the topology on which the section to be saved is defined 2227 . viewer - The `PetscViewer` for saving 2228 - sectiondm - The `DM` that contains the section to be saved, can be `NULL` 2229 2230 Level: advanced 2231 2232 Notes: 2233 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. 2234 2235 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. 2236 2237 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2238 @*/ 2239 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2240 { 2241 PetscBool ishdf5; 2242 2243 PetscFunctionBegin; 2244 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2245 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2246 if (!sectiondm) sectiondm = dm; 2247 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2248 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2249 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2250 if (ishdf5) { 2251 #if defined(PETSC_HAVE_HDF5) 2252 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2253 #else 2254 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2255 #endif 2256 } 2257 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2258 PetscFunctionReturn(PETSC_SUCCESS); 2259 } 2260 2261 /*@ 2262 DMPlexGlobalVectorView - Saves a global vector 2263 2264 Collective 2265 2266 Input Parameters: 2267 + dm - The `DM` that represents the topology 2268 . viewer - The `PetscViewer` to save data with 2269 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2270 - vec - The global vector to be saved 2271 2272 Level: advanced 2273 2274 Notes: 2275 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. 2276 2277 Calling sequence: 2278 .vb 2279 DMCreate(PETSC_COMM_WORLD, &dm); 2280 DMSetType(dm, DMPLEX); 2281 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2282 DMClone(dm, §iondm); 2283 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2284 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2285 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2286 PetscSectionSetChart(section, pStart, pEnd); 2287 PetscSectionSetUp(section); 2288 DMSetLocalSection(sectiondm, section); 2289 PetscSectionDestroy(§ion); 2290 DMGetGlobalVector(sectiondm, &vec); 2291 PetscObjectSetName((PetscObject)vec, "vec_name"); 2292 DMPlexTopologyView(dm, viewer); 2293 DMPlexSectionView(dm, viewer, sectiondm); 2294 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2295 DMRestoreGlobalVector(sectiondm, &vec); 2296 DMDestroy(§iondm); 2297 DMDestroy(&dm); 2298 .ve 2299 2300 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2301 @*/ 2302 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2303 { 2304 PetscBool ishdf5; 2305 2306 PetscFunctionBegin; 2307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2308 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2309 if (!sectiondm) sectiondm = dm; 2310 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2311 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2312 /* Check consistency */ 2313 { 2314 PetscSection section; 2315 PetscBool includesConstraints; 2316 PetscInt m, m1; 2317 2318 PetscCall(VecGetLocalSize(vec, &m1)); 2319 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2320 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2321 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2322 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2323 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2324 } 2325 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2326 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2327 if (ishdf5) { 2328 #if defined(PETSC_HAVE_HDF5) 2329 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2330 #else 2331 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2332 #endif 2333 } 2334 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2335 PetscFunctionReturn(PETSC_SUCCESS); 2336 } 2337 2338 /*@ 2339 DMPlexLocalVectorView - Saves a local vector 2340 2341 Collective 2342 2343 Input Parameters: 2344 + dm - The `DM` that represents the topology 2345 . viewer - The `PetscViewer` to save data with 2346 . sectiondm - The `DM` that contains the local section on which `vec` is defined, can be `NULL` 2347 - vec - The local vector to be saved 2348 2349 Level: advanced 2350 2351 Note: 2352 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. 2353 2354 Calling sequence: 2355 .vb 2356 DMCreate(PETSC_COMM_WORLD, &dm); 2357 DMSetType(dm, DMPLEX); 2358 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2359 DMClone(dm, §iondm); 2360 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2361 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2362 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2363 PetscSectionSetChart(section, pStart, pEnd); 2364 PetscSectionSetUp(section); 2365 DMSetLocalSection(sectiondm, section); 2366 DMGetLocalVector(sectiondm, &vec); 2367 PetscObjectSetName((PetscObject)vec, "vec_name"); 2368 DMPlexTopologyView(dm, viewer); 2369 DMPlexSectionView(dm, viewer, sectiondm); 2370 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2371 DMRestoreLocalVector(sectiondm, &vec); 2372 DMDestroy(§iondm); 2373 DMDestroy(&dm); 2374 .ve 2375 2376 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2377 @*/ 2378 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2379 { 2380 PetscBool ishdf5; 2381 2382 PetscFunctionBegin; 2383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2384 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2385 if (!sectiondm) sectiondm = dm; 2386 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2387 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2388 /* Check consistency */ 2389 { 2390 PetscSection section; 2391 PetscBool includesConstraints; 2392 PetscInt m, m1; 2393 2394 PetscCall(VecGetLocalSize(vec, &m1)); 2395 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2396 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2397 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2398 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2399 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2400 } 2401 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2402 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2403 if (ishdf5) { 2404 #if defined(PETSC_HAVE_HDF5) 2405 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2406 #else 2407 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2408 #endif 2409 } 2410 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2411 PetscFunctionReturn(PETSC_SUCCESS); 2412 } 2413 2414 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2415 { 2416 PetscBool ishdf5; 2417 2418 PetscFunctionBegin; 2419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2420 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2421 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2422 if (ishdf5) { 2423 #if defined(PETSC_HAVE_HDF5) 2424 PetscViewerFormat format; 2425 PetscCall(PetscViewerGetFormat(viewer, &format)); 2426 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2427 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2428 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2429 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2430 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2431 PetscFunctionReturn(PETSC_SUCCESS); 2432 #else 2433 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2434 #endif 2435 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2436 } 2437 2438 /*@ 2439 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2440 2441 Collective 2442 2443 Input Parameters: 2444 + dm - The `DM` into which the topology is loaded 2445 - viewer - The `PetscViewer` for the saved topology 2446 2447 Output Parameter: 2448 . 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; 2449 `NULL` if unneeded 2450 2451 Level: advanced 2452 2453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2454 `PetscViewer`, `PetscSF` 2455 @*/ 2456 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2457 { 2458 PetscBool ishdf5; 2459 2460 PetscFunctionBegin; 2461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2462 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2463 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2464 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2465 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2466 if (ishdf5) { 2467 #if defined(PETSC_HAVE_HDF5) 2468 PetscViewerFormat format; 2469 PetscCall(PetscViewerGetFormat(viewer, &format)); 2470 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2471 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2472 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2473 #else 2474 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2475 #endif 2476 } 2477 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2478 PetscFunctionReturn(PETSC_SUCCESS); 2479 } 2480 2481 /*@ 2482 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2483 2484 Collective 2485 2486 Input Parameters: 2487 + dm - The `DM` into which the coordinates are loaded 2488 . viewer - The `PetscViewer` for the saved coordinates 2489 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2490 2491 Level: advanced 2492 2493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2494 `PetscSF`, `PetscViewer` 2495 @*/ 2496 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2497 { 2498 PetscBool ishdf5; 2499 2500 PetscFunctionBegin; 2501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2502 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2503 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2504 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2505 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2506 if (ishdf5) { 2507 #if defined(PETSC_HAVE_HDF5) 2508 PetscViewerFormat format; 2509 PetscCall(PetscViewerGetFormat(viewer, &format)); 2510 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2511 PetscCall(DMPlexCoordinatesLoad_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_CoordinatesLoad, viewer, 0, 0, 0)); 2518 PetscFunctionReturn(PETSC_SUCCESS); 2519 } 2520 2521 /*@ 2522 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2523 2524 Collective 2525 2526 Input Parameters: 2527 + dm - The `DM` into which the labels are loaded 2528 . viewer - The `PetscViewer` for the saved labels 2529 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2530 2531 Level: advanced 2532 2533 Note: 2534 The `PetscSF` argument must not be `NULL` if the `DM` is distributed, otherwise an error occurs. 2535 2536 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2537 `PetscSF`, `PetscViewer` 2538 @*/ 2539 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2540 { 2541 PetscBool ishdf5; 2542 2543 PetscFunctionBegin; 2544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2545 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2546 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2547 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2548 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2549 if (ishdf5) { 2550 #if defined(PETSC_HAVE_HDF5) 2551 PetscViewerFormat format; 2552 2553 PetscCall(PetscViewerGetFormat(viewer, &format)); 2554 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2555 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2556 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2557 #else 2558 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2559 #endif 2560 } 2561 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2562 PetscFunctionReturn(PETSC_SUCCESS); 2563 } 2564 2565 /*@ 2566 DMPlexSectionLoad - Loads section into a `DMPLEX` 2567 2568 Collective 2569 2570 Input Parameters: 2571 + dm - The `DM` that represents the topology 2572 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2573 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated, can be `NULL` 2574 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2575 2576 Output Parameters: 2577 + 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) 2578 - 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) 2579 2580 Level: advanced 2581 2582 Notes: 2583 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. 2584 2585 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. 2586 2587 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. 2588 2589 Example using 2 processes: 2590 .vb 2591 NX (number of points on dm): 4 2592 sectionA : the on-disk section 2593 vecA : a vector associated with sectionA 2594 sectionB : sectiondm's local section constructed in this function 2595 vecB (local) : a vector associated with sectiondm's local section 2596 vecB (global) : a vector associated with sectiondm's global section 2597 2598 rank 0 rank 1 2599 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2600 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2601 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2602 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2603 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2604 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2605 sectionB->atlasDof : 1 0 1 | 1 3 2606 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2607 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2608 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2609 .ve 2610 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2611 2612 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2613 @*/ 2614 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2615 { 2616 PetscBool ishdf5; 2617 2618 PetscFunctionBegin; 2619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2620 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2621 if (!sectiondm) sectiondm = dm; 2622 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2623 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2624 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2625 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2626 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2627 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2628 if (ishdf5) { 2629 #if defined(PETSC_HAVE_HDF5) 2630 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2631 #else 2632 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2633 #endif 2634 } 2635 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2636 PetscFunctionReturn(PETSC_SUCCESS); 2637 } 2638 2639 /*@ 2640 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2641 2642 Collective 2643 2644 Input Parameters: 2645 + dm - The `DM` that represents the topology 2646 . viewer - The `PetscViewer` that represents the on-disk vector data 2647 . sectiondm - The `DM` that contains the global section on which vec is defined, can be `NULL` 2648 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2649 - vec - The global vector to set values of 2650 2651 Level: advanced 2652 2653 Notes: 2654 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. 2655 2656 Calling sequence: 2657 .vb 2658 DMCreate(PETSC_COMM_WORLD, &dm); 2659 DMSetType(dm, DMPLEX); 2660 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2661 DMPlexTopologyLoad(dm, viewer, &sfX); 2662 DMClone(dm, §iondm); 2663 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2664 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2665 DMGetGlobalVector(sectiondm, &vec); 2666 PetscObjectSetName((PetscObject)vec, "vec_name"); 2667 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2668 DMRestoreGlobalVector(sectiondm, &vec); 2669 PetscSFDestroy(&gsf); 2670 PetscSFDestroy(&sfX); 2671 DMDestroy(§iondm); 2672 DMDestroy(&dm); 2673 .ve 2674 2675 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2676 `PetscSF`, `PetscViewer` 2677 @*/ 2678 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2679 { 2680 PetscBool ishdf5; 2681 2682 PetscFunctionBegin; 2683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2684 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2685 if (!sectiondm) sectiondm = dm; 2686 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2687 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2688 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2689 /* Check consistency */ 2690 { 2691 PetscSection section; 2692 PetscBool includesConstraints; 2693 PetscInt m, m1; 2694 2695 PetscCall(VecGetLocalSize(vec, &m1)); 2696 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2697 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2698 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2699 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2700 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2701 } 2702 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2703 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2704 if (ishdf5) { 2705 #if defined(PETSC_HAVE_HDF5) 2706 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2707 #else 2708 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2709 #endif 2710 } 2711 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2712 PetscFunctionReturn(PETSC_SUCCESS); 2713 } 2714 2715 /*@ 2716 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2717 2718 Collective 2719 2720 Input Parameters: 2721 + dm - The `DM` that represents the topology 2722 . viewer - The `PetscViewer` that represents the on-disk vector data 2723 . sectiondm - The `DM` that contains the local section on which vec is defined, can be `NULL` 2724 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2725 - vec - The local vector to set values of 2726 2727 Level: advanced 2728 2729 Notes: 2730 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. 2731 2732 Calling sequence: 2733 .vb 2734 DMCreate(PETSC_COMM_WORLD, &dm); 2735 DMSetType(dm, DMPLEX); 2736 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2737 DMPlexTopologyLoad(dm, viewer, &sfX); 2738 DMClone(dm, §iondm); 2739 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2740 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2741 DMGetLocalVector(sectiondm, &vec); 2742 PetscObjectSetName((PetscObject)vec, "vec_name"); 2743 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2744 DMRestoreLocalVector(sectiondm, &vec); 2745 PetscSFDestroy(&lsf); 2746 PetscSFDestroy(&sfX); 2747 DMDestroy(§iondm); 2748 DMDestroy(&dm); 2749 .ve 2750 2751 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2752 `PetscSF`, `PetscViewer` 2753 @*/ 2754 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2755 { 2756 PetscBool ishdf5; 2757 2758 PetscFunctionBegin; 2759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2760 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2761 if (!sectiondm) sectiondm = dm; 2762 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2763 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2764 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2765 /* Check consistency */ 2766 { 2767 PetscSection section; 2768 PetscBool includesConstraints; 2769 PetscInt m, m1; 2770 2771 PetscCall(VecGetLocalSize(vec, &m1)); 2772 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2773 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2774 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2775 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2776 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2777 } 2778 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2779 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2780 if (ishdf5) { 2781 #if defined(PETSC_HAVE_HDF5) 2782 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2783 #else 2784 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2785 #endif 2786 } 2787 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2788 PetscFunctionReturn(PETSC_SUCCESS); 2789 } 2790 2791 PetscErrorCode DMDestroy_Plex(DM dm) 2792 { 2793 DM_Plex *mesh = (DM_Plex *)dm->data; 2794 2795 PetscFunctionBegin; 2796 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2797 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2798 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2799 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2800 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2801 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2802 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2803 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2804 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2805 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2806 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2807 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetDefault_C", NULL)); 2808 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetDefault_C", NULL)); 2809 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionGetType_C", NULL)); 2810 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMReorderSectionSetType_C", NULL)); 2811 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2812 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2813 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2814 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2815 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2816 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2817 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2818 PetscCall(PetscFree(mesh->cones)); 2819 PetscCall(PetscFree(mesh->coneOrientations)); 2820 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2821 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2822 PetscCall(PetscFree(mesh->supports)); 2823 PetscCall(PetscFree(mesh->cellTypes)); 2824 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2825 PetscCall(PetscFree(mesh->tetgenOpts)); 2826 PetscCall(PetscFree(mesh->triangleOpts)); 2827 PetscCall(PetscFree(mesh->transformType)); 2828 PetscCall(PetscFree(mesh->distributionName)); 2829 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2830 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2831 PetscCall(ISDestroy(&mesh->subpointIS)); 2832 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2833 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2834 if (mesh->periodic.face_sfs) { 2835 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(PetscSFDestroy(&mesh->periodic.face_sfs[i])); 2836 PetscCall(PetscFree(mesh->periodic.face_sfs)); 2837 } 2838 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2839 if (mesh->periodic.periodic_points) { 2840 for (PetscInt i = 0; i < mesh->periodic.num_face_sfs; i++) PetscCall(ISDestroy(&mesh->periodic.periodic_points[i])); 2841 PetscCall(PetscFree(mesh->periodic.periodic_points)); 2842 } 2843 if (mesh->periodic.transform) PetscCall(PetscFree(mesh->periodic.transform)); 2844 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2845 PetscCall(ISDestroy(&mesh->anchorIS)); 2846 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2847 PetscCall(PetscFree(mesh->parents)); 2848 PetscCall(PetscFree(mesh->childIDs)); 2849 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2850 PetscCall(PetscFree(mesh->children)); 2851 PetscCall(DMDestroy(&mesh->referenceTree)); 2852 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2853 PetscCall(PetscFree(mesh->neighbors)); 2854 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2855 if (mesh->nonempty_comm != MPI_COMM_NULL && mesh->nonempty_comm != MPI_COMM_SELF) PetscCallMPI(MPI_Comm_free(&mesh->nonempty_comm)); 2856 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2857 PetscCall(PetscFree(mesh)); 2858 PetscFunctionReturn(PETSC_SUCCESS); 2859 } 2860 2861 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2862 { 2863 PetscSection sectionGlobal, sectionLocal; 2864 PetscInt bs = -1, mbs; 2865 PetscInt localSize, localStart = 0; 2866 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2867 MatType mtype; 2868 ISLocalToGlobalMapping ltog; 2869 2870 PetscFunctionBegin; 2871 PetscCall(MatInitializePackage()); 2872 mtype = dm->mattype; 2873 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2874 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2875 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2876 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2877 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2878 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2879 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2880 PetscCall(MatSetType(*J, mtype)); 2881 PetscCall(MatSetFromOptions(*J)); 2882 PetscCall(MatGetBlockSize(*J, &mbs)); 2883 if (mbs > 1) bs = mbs; 2884 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2885 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2886 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2887 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2888 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2889 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2890 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2891 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2892 if (!isShell) { 2893 // There are three states with pblocks, since block starts can have no dofs: 2894 // UNKNOWN) New Block: An open block has been signalled by pblocks[p] == 1 2895 // TRUE) Block Start: The first entry in a block has been added 2896 // FALSE) Block Add: An additional block entry has been added, since pblocks[p] == 0 2897 PetscBT blst; 2898 PetscBool3 bstate = PETSC_BOOL3_UNKNOWN; 2899 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2900 const PetscInt *perm = NULL; 2901 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2902 PetscInt pStart, pEnd, dof, cdof, num_fields; 2903 2904 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2905 PetscCall(PetscSectionGetBlockStarts(sectionLocal, &blst)); 2906 if (sectionLocal->perm) PetscCall(ISGetIndices(sectionLocal->perm, &perm)); 2907 2908 PetscCall(PetscCalloc1(localSize, &pblocks)); 2909 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2910 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2911 // We need to process in the permuted order to get block sizes right 2912 for (PetscInt point = pStart; point < pEnd; ++point) { 2913 const PetscInt p = perm ? perm[point] : point; 2914 2915 switch (dm->blocking_type) { 2916 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2917 PetscInt bdof, offset; 2918 2919 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2920 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2921 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2922 if (blst && PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_UNKNOWN; 2923 if (dof > 0) { 2924 // State change 2925 if (bstate == PETSC_BOOL3_UNKNOWN) bstate = PETSC_BOOL3_TRUE; 2926 else if (bstate == PETSC_BOOL3_TRUE && blst && !PetscBTLookup(blst, p)) bstate = PETSC_BOOL3_FALSE; 2927 2928 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2929 // Signal block concatenation 2930 if (bstate == PETSC_BOOL3_FALSE && dof - cdof) pblocks[offset - localStart] = -(dof - cdof); 2931 } 2932 dof = dof < 0 ? -(dof + 1) : dof; 2933 bdof = cdof && (dof - cdof) ? 1 : dof; 2934 if (dof) { 2935 if (bs < 0) { 2936 bs = bdof; 2937 } else if (bs != bdof) { 2938 bs = 1; 2939 } 2940 } 2941 } break; 2942 case DM_BLOCKING_FIELD_NODE: { 2943 for (PetscInt field = 0; field < num_fields; field++) { 2944 PetscInt num_comp, bdof, offset; 2945 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2946 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2947 if (dof < 0) continue; 2948 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2949 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2950 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); 2951 PetscInt num_nodes = dof / num_comp; 2952 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2953 // Handle possibly constant block size (unlikely) 2954 bdof = cdof && (dof - cdof) ? 1 : dof; 2955 if (dof) { 2956 if (bs < 0) { 2957 bs = bdof; 2958 } else if (bs != bdof) { 2959 bs = 1; 2960 } 2961 } 2962 } 2963 } break; 2964 } 2965 } 2966 if (sectionLocal->perm) PetscCall(ISRestoreIndices(sectionLocal->perm, &perm)); 2967 /* Must have same blocksize on all procs (some might have no points) */ 2968 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 2969 bsLocal[1] = bs; 2970 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2971 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2972 else bs = bsMinMax[0]; 2973 bs = PetscMax(1, bs); 2974 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2975 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2976 PetscCall(MatSetBlockSize(*J, bs)); 2977 PetscCall(MatSetUp(*J)); 2978 } else { 2979 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2980 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2981 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2982 } 2983 if (pblocks) { // Consolidate blocks 2984 PetscInt nblocks = 0; 2985 pblocks[0] = PetscAbs(pblocks[0]); 2986 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2987 if (pblocks[i] == 0) continue; 2988 // Negative block size indicates the blocks should be concatenated 2989 if (pblocks[i] < 0) { 2990 pblocks[i] = -pblocks[i]; 2991 pblocks[nblocks - 1] += pblocks[i]; 2992 } else { 2993 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2994 } 2995 for (PetscInt j = 1; j < pblocks[i]; j++) 2996 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); 2997 } 2998 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2999 } 3000 PetscCall(PetscFree(pblocks)); 3001 } 3002 PetscCall(MatSetDM(*J, dm)); 3003 PetscFunctionReturn(PETSC_SUCCESS); 3004 } 3005 3006 /*@ 3007 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 3008 3009 Not Collective 3010 3011 Input Parameter: 3012 . dm - The `DMPLEX` 3013 3014 Output Parameter: 3015 . subsection - The subdomain section 3016 3017 Level: developer 3018 3019 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 3020 @*/ 3021 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 3022 { 3023 DM_Plex *mesh = (DM_Plex *)dm->data; 3024 3025 PetscFunctionBegin; 3026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3027 if (!mesh->subdomainSection) { 3028 PetscSection section; 3029 PetscSF sf; 3030 3031 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 3032 PetscCall(DMGetLocalSection(dm, §ion)); 3033 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 3034 PetscCall(PetscSFDestroy(&sf)); 3035 } 3036 *subsection = mesh->subdomainSection; 3037 PetscFunctionReturn(PETSC_SUCCESS); 3038 } 3039 3040 /*@ 3041 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 3042 3043 Not Collective 3044 3045 Input Parameter: 3046 . dm - The `DMPLEX` 3047 3048 Output Parameters: 3049 + pStart - The first mesh point 3050 - pEnd - The upper bound for mesh points 3051 3052 Level: beginner 3053 3054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 3055 @*/ 3056 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 3057 { 3058 DM_Plex *mesh = (DM_Plex *)dm->data; 3059 3060 PetscFunctionBegin; 3061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3062 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 3063 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 3064 PetscFunctionReturn(PETSC_SUCCESS); 3065 } 3066 3067 /*@ 3068 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 3069 3070 Not Collective 3071 3072 Input Parameters: 3073 + dm - The `DMPLEX` 3074 . pStart - The first mesh point 3075 - pEnd - The upper bound for mesh points 3076 3077 Level: beginner 3078 3079 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 3080 @*/ 3081 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 3082 { 3083 DM_Plex *mesh = (DM_Plex *)dm->data; 3084 3085 PetscFunctionBegin; 3086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3087 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 3088 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 3089 PetscCall(PetscFree(mesh->cellTypes)); 3090 PetscFunctionReturn(PETSC_SUCCESS); 3091 } 3092 3093 /*@ 3094 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 3095 3096 Not Collective 3097 3098 Input Parameters: 3099 + dm - The `DMPLEX` 3100 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3101 3102 Output Parameter: 3103 . size - The cone size for point `p` 3104 3105 Level: beginner 3106 3107 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3108 @*/ 3109 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 3110 { 3111 DM_Plex *mesh = (DM_Plex *)dm->data; 3112 3113 PetscFunctionBegin; 3114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3115 PetscAssertPointer(size, 3); 3116 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 3117 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 3118 PetscFunctionReturn(PETSC_SUCCESS); 3119 } 3120 3121 /*@ 3122 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 3123 3124 Not Collective 3125 3126 Input Parameters: 3127 + dm - The `DMPLEX` 3128 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3129 - size - The cone size for point `p` 3130 3131 Level: beginner 3132 3133 Note: 3134 This should be called after `DMPlexSetChart()`. 3135 3136 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 3137 @*/ 3138 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 3139 { 3140 DM_Plex *mesh = (DM_Plex *)dm->data; 3141 3142 PetscFunctionBegin; 3143 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3144 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 3145 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 3146 PetscFunctionReturn(PETSC_SUCCESS); 3147 } 3148 3149 /*@C 3150 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 3151 3152 Not Collective 3153 3154 Input Parameters: 3155 + dm - The `DMPLEX` 3156 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3157 3158 Output Parameter: 3159 . cone - An array of points which are on the in-edges for point `p`, the length of `cone` is the result of `DMPlexGetConeSize()` 3160 3161 Level: beginner 3162 3163 Fortran Notes: 3164 `cone` must be declared with 3165 .vb 3166 PetscInt, pointer :: cone(:) 3167 .ve 3168 3169 You must also call `DMPlexRestoreCone()` after you finish using the array. 3170 `DMPlexRestoreCone()` is not needed/available in C. 3171 3172 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3173 @*/ 3174 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3175 { 3176 DM_Plex *mesh = (DM_Plex *)dm->data; 3177 PetscInt off; 3178 3179 PetscFunctionBegin; 3180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3181 PetscAssertPointer(cone, 3); 3182 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3183 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3184 PetscFunctionReturn(PETSC_SUCCESS); 3185 } 3186 3187 /*@ 3188 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3189 3190 Not Collective 3191 3192 Input Parameters: 3193 + dm - The `DMPLEX` 3194 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3195 3196 Output Parameters: 3197 + pConesSection - `PetscSection` describing the layout of `pCones` 3198 - pCones - An `IS` containing the points which are on the in-edges for the point set `p` 3199 3200 Level: intermediate 3201 3202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3203 @*/ 3204 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3205 { 3206 PetscSection cs, newcs; 3207 PetscInt *cones; 3208 PetscInt *newarr = NULL; 3209 PetscInt n; 3210 3211 PetscFunctionBegin; 3212 PetscCall(DMPlexGetCones(dm, &cones)); 3213 PetscCall(DMPlexGetConeSection(dm, &cs)); 3214 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3215 if (pConesSection) *pConesSection = newcs; 3216 if (pCones) { 3217 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3218 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3219 } 3220 PetscFunctionReturn(PETSC_SUCCESS); 3221 } 3222 3223 /*@ 3224 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3225 3226 Not Collective 3227 3228 Input Parameters: 3229 + dm - The `DMPLEX` 3230 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3231 3232 Output Parameter: 3233 . expandedPoints - An `IS` containing the of vertices recursively expanded from input points 3234 3235 Level: advanced 3236 3237 Notes: 3238 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3239 3240 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3241 3242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3243 `DMPlexGetDepth()`, `IS` 3244 @*/ 3245 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3246 { 3247 IS *expandedPointsAll; 3248 PetscInt depth; 3249 3250 PetscFunctionBegin; 3251 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3252 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3253 PetscAssertPointer(expandedPoints, 3); 3254 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3255 *expandedPoints = expandedPointsAll[0]; 3256 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3257 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3258 PetscFunctionReturn(PETSC_SUCCESS); 3259 } 3260 3261 /*@ 3262 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices 3263 (DAG points of depth 0, i.e., without cones). 3264 3265 Not Collective 3266 3267 Input Parameters: 3268 + dm - The `DMPLEX` 3269 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3270 3271 Output Parameters: 3272 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3273 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3274 - sections - (optional) An array of sections which describe mappings from points to their cone points 3275 3276 Level: advanced 3277 3278 Notes: 3279 Like `DMPlexGetConeTuple()` but recursive. 3280 3281 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. 3282 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3283 3284 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\: 3285 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3286 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3287 3288 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3289 `DMPlexGetDepth()`, `PetscSection`, `IS` 3290 @*/ 3291 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3292 { 3293 const PetscInt *arr0 = NULL, *cone = NULL; 3294 PetscInt *arr = NULL, *newarr = NULL; 3295 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3296 IS *expandedPoints_; 3297 PetscSection *sections_; 3298 3299 PetscFunctionBegin; 3300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3301 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3302 if (depth) PetscAssertPointer(depth, 3); 3303 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3304 if (sections) PetscAssertPointer(sections, 5); 3305 PetscCall(ISGetLocalSize(points, &n)); 3306 PetscCall(ISGetIndices(points, &arr0)); 3307 PetscCall(DMPlexGetDepth(dm, &depth_)); 3308 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3309 PetscCall(PetscCalloc1(depth_, §ions_)); 3310 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3311 for (d = depth_ - 1; d >= 0; d--) { 3312 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3313 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3314 for (i = 0; i < n; i++) { 3315 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3316 if (arr[i] >= start && arr[i] < end) { 3317 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3318 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3319 } else { 3320 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3321 } 3322 } 3323 PetscCall(PetscSectionSetUp(sections_[d])); 3324 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3325 PetscCall(PetscMalloc1(newn, &newarr)); 3326 for (i = 0; i < n; i++) { 3327 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3328 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3329 if (cn > 1) { 3330 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3331 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3332 } else { 3333 newarr[co] = arr[i]; 3334 } 3335 } 3336 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3337 arr = newarr; 3338 n = newn; 3339 } 3340 PetscCall(ISRestoreIndices(points, &arr0)); 3341 *depth = depth_; 3342 if (expandedPoints) *expandedPoints = expandedPoints_; 3343 else { 3344 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3345 PetscCall(PetscFree(expandedPoints_)); 3346 } 3347 if (sections) *sections = sections_; 3348 else { 3349 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3350 PetscCall(PetscFree(sections_)); 3351 } 3352 PetscFunctionReturn(PETSC_SUCCESS); 3353 } 3354 3355 /*@ 3356 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3357 3358 Not Collective 3359 3360 Input Parameters: 3361 + dm - The `DMPLEX` 3362 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3363 3364 Output Parameters: 3365 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3366 . expandedPoints - (optional) An array of recursively expanded cones 3367 - sections - (optional) An array of sections which describe mappings from points to their cone points 3368 3369 Level: advanced 3370 3371 Note: 3372 See `DMPlexGetConeRecursive()` 3373 3374 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3375 `DMPlexGetDepth()`, `IS`, `PetscSection` 3376 @*/ 3377 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3378 { 3379 PetscInt d, depth_; 3380 3381 PetscFunctionBegin; 3382 PetscCall(DMPlexGetDepth(dm, &depth_)); 3383 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3384 if (depth) *depth = 0; 3385 if (expandedPoints) { 3386 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&(*expandedPoints)[d])); 3387 PetscCall(PetscFree(*expandedPoints)); 3388 } 3389 if (sections) { 3390 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&(*sections)[d])); 3391 PetscCall(PetscFree(*sections)); 3392 } 3393 PetscFunctionReturn(PETSC_SUCCESS); 3394 } 3395 3396 /*@ 3397 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 3398 3399 Not Collective 3400 3401 Input Parameters: 3402 + dm - The `DMPLEX` 3403 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3404 - cone - An array of points which are on the in-edges for point `p`, its length must have been previously provided with `DMPlexSetConeSize()` 3405 3406 Level: beginner 3407 3408 Note: 3409 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3410 3411 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3412 @*/ 3413 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3414 { 3415 DM_Plex *mesh = (DM_Plex *)dm->data; 3416 PetscInt dof, off, c; 3417 3418 PetscFunctionBegin; 3419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3420 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3421 if (dof) PetscAssertPointer(cone, 3); 3422 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3423 if (PetscDefined(USE_DEBUG)) { 3424 PetscInt pStart, pEnd; 3425 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3426 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); 3427 for (c = 0; c < dof; ++c) { 3428 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); 3429 mesh->cones[off + c] = cone[c]; 3430 } 3431 } else { 3432 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3433 } 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /*@C 3438 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3439 3440 Not Collective 3441 3442 Input Parameters: 3443 + dm - The `DMPLEX` 3444 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3445 3446 Output Parameter: 3447 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3448 integer giving the prescription for cone traversal. Its length is given by the result of `DMPlexSetConeSize()` 3449 3450 Level: beginner 3451 3452 Note: 3453 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3454 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3455 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3456 with the identity. 3457 3458 Fortran Notes: 3459 You must call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3460 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3461 3462 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetConeSize()`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, 3463 `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3464 @*/ 3465 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3466 { 3467 DM_Plex *mesh = (DM_Plex *)dm->data; 3468 PetscInt off; 3469 3470 PetscFunctionBegin; 3471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3472 if (PetscDefined(USE_DEBUG)) { 3473 PetscInt dof; 3474 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3475 if (dof) PetscAssertPointer(coneOrientation, 3); 3476 } 3477 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3478 3479 *coneOrientation = &mesh->coneOrientations[off]; 3480 PetscFunctionReturn(PETSC_SUCCESS); 3481 } 3482 3483 /*@ 3484 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3485 3486 Not Collective 3487 3488 Input Parameters: 3489 + dm - The `DMPLEX` 3490 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3491 - coneOrientation - An array of orientations. Its length is given by the result of `DMPlexSetConeSize()` 3492 3493 Level: beginner 3494 3495 Notes: 3496 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3497 3498 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3499 3500 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3501 @*/ 3502 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3503 { 3504 DM_Plex *mesh = (DM_Plex *)dm->data; 3505 PetscInt pStart, pEnd; 3506 PetscInt dof, off, c; 3507 3508 PetscFunctionBegin; 3509 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3510 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3511 if (dof) PetscAssertPointer(coneOrientation, 3); 3512 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3513 if (PetscDefined(USE_DEBUG)) { 3514 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3515 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); 3516 for (c = 0; c < dof; ++c) { 3517 PetscInt cdof, o = coneOrientation[c]; 3518 3519 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3520 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); 3521 mesh->coneOrientations[off + c] = o; 3522 } 3523 } else { 3524 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3525 } 3526 PetscFunctionReturn(PETSC_SUCCESS); 3527 } 3528 3529 /*@ 3530 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3531 3532 Not Collective 3533 3534 Input Parameters: 3535 + dm - The `DMPLEX` 3536 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3537 . conePos - The local index in the cone where the point should be put 3538 - conePoint - The mesh point to insert 3539 3540 Level: beginner 3541 3542 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3543 @*/ 3544 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3545 { 3546 DM_Plex *mesh = (DM_Plex *)dm->data; 3547 PetscInt pStart, pEnd; 3548 PetscInt dof, off; 3549 3550 PetscFunctionBegin; 3551 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3552 if (PetscDefined(USE_DEBUG)) { 3553 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3554 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); 3555 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); 3556 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3557 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); 3558 } 3559 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3560 mesh->cones[off + conePos] = conePoint; 3561 PetscFunctionReturn(PETSC_SUCCESS); 3562 } 3563 3564 /*@ 3565 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3566 3567 Not Collective 3568 3569 Input Parameters: 3570 + dm - The `DMPLEX` 3571 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3572 . conePos - The local index in the cone where the point should be put 3573 - coneOrientation - The point orientation to insert 3574 3575 Level: beginner 3576 3577 Note: 3578 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3579 3580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3581 @*/ 3582 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3583 { 3584 DM_Plex *mesh = (DM_Plex *)dm->data; 3585 PetscInt pStart, pEnd; 3586 PetscInt dof, off; 3587 3588 PetscFunctionBegin; 3589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3590 if (PetscDefined(USE_DEBUG)) { 3591 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3592 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); 3593 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3594 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); 3595 } 3596 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3597 mesh->coneOrientations[off + conePos] = coneOrientation; 3598 PetscFunctionReturn(PETSC_SUCCESS); 3599 } 3600 3601 /*@C 3602 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3603 3604 Not collective 3605 3606 Input Parameters: 3607 + dm - The DMPlex 3608 - p - The point, which must lie in the chart set with DMPlexSetChart() 3609 3610 Output Parameters: 3611 + cone - An array of points which are on the in-edges for point `p` 3612 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3613 integer giving the prescription for cone traversal. 3614 3615 Level: beginner 3616 3617 Notes: 3618 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3619 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3620 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3621 with the identity. 3622 3623 You must also call `DMPlexRestoreOrientedCone()` after you finish using the returned array. 3624 3625 Fortran Notes: 3626 `cone` and `ornt` must be declared with 3627 .vb 3628 PetscInt, pointer :: cone(:) 3629 PetscInt, pointer :: ornt(:) 3630 .ve 3631 3632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3633 @*/ 3634 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3635 { 3636 DM_Plex *mesh = (DM_Plex *)dm->data; 3637 3638 PetscFunctionBegin; 3639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3640 if (mesh->tr) { 3641 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3642 } else { 3643 PetscInt off; 3644 if (PetscDefined(USE_DEBUG)) { 3645 PetscInt dof; 3646 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3647 if (dof) { 3648 if (cone) PetscAssertPointer(cone, 3); 3649 if (ornt) PetscAssertPointer(ornt, 4); 3650 } 3651 } 3652 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3653 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3654 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3655 } 3656 PetscFunctionReturn(PETSC_SUCCESS); 3657 } 3658 3659 /*@C 3660 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG obtained with `DMPlexGetOrientedCone()` 3661 3662 Not Collective 3663 3664 Input Parameters: 3665 + dm - The DMPlex 3666 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3667 . cone - An array of points which are on the in-edges for point p 3668 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3669 integer giving the prescription for cone traversal. 3670 3671 Level: beginner 3672 3673 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3674 @*/ 3675 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3676 { 3677 DM_Plex *mesh = (DM_Plex *)dm->data; 3678 3679 PetscFunctionBegin; 3680 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3681 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3682 PetscFunctionReturn(PETSC_SUCCESS); 3683 } 3684 3685 /*@ 3686 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3687 3688 Not Collective 3689 3690 Input Parameters: 3691 + dm - The `DMPLEX` 3692 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3693 3694 Output Parameter: 3695 . size - The support size for point `p` 3696 3697 Level: beginner 3698 3699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3700 @*/ 3701 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3702 { 3703 DM_Plex *mesh = (DM_Plex *)dm->data; 3704 3705 PetscFunctionBegin; 3706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3707 PetscAssertPointer(size, 3); 3708 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3709 PetscFunctionReturn(PETSC_SUCCESS); 3710 } 3711 3712 /*@ 3713 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3714 3715 Not Collective 3716 3717 Input Parameters: 3718 + dm - The `DMPLEX` 3719 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3720 - size - The support size for point `p` 3721 3722 Level: beginner 3723 3724 Note: 3725 This should be called after `DMPlexSetChart()`. 3726 3727 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3728 @*/ 3729 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3730 { 3731 DM_Plex *mesh = (DM_Plex *)dm->data; 3732 3733 PetscFunctionBegin; 3734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3735 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3736 PetscFunctionReturn(PETSC_SUCCESS); 3737 } 3738 3739 /*@C 3740 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3741 3742 Not Collective 3743 3744 Input Parameters: 3745 + dm - The `DMPLEX` 3746 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3747 3748 Output Parameter: 3749 . support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3750 3751 Level: beginner 3752 3753 Fortran Notes: 3754 `support` must be declared with 3755 .vb 3756 PetscInt, pointer :: support(:) 3757 .ve 3758 3759 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3760 `DMPlexRestoreSupport()` is not needed/available in C. 3761 3762 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3763 @*/ 3764 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3765 { 3766 DM_Plex *mesh = (DM_Plex *)dm->data; 3767 PetscInt off; 3768 3769 PetscFunctionBegin; 3770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3771 PetscAssertPointer(support, 3); 3772 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3773 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3774 PetscFunctionReturn(PETSC_SUCCESS); 3775 } 3776 3777 /*@ 3778 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3779 3780 Not Collective 3781 3782 Input Parameters: 3783 + dm - The `DMPLEX` 3784 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3785 - support - An array of points which are on the out-edges for point `p`, its length is that obtained from `DMPlexGetSupportSize()` 3786 3787 Level: beginner 3788 3789 Note: 3790 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3791 3792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3793 @*/ 3794 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3795 { 3796 DM_Plex *mesh = (DM_Plex *)dm->data; 3797 PetscInt pStart, pEnd; 3798 PetscInt dof, off, c; 3799 3800 PetscFunctionBegin; 3801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3802 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3803 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3804 if (dof) PetscAssertPointer(support, 3); 3805 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3806 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); 3807 for (c = 0; c < dof; ++c) { 3808 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); 3809 mesh->supports[off + c] = support[c]; 3810 } 3811 PetscFunctionReturn(PETSC_SUCCESS); 3812 } 3813 3814 /*@ 3815 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3816 3817 Not Collective 3818 3819 Input Parameters: 3820 + dm - The `DMPLEX` 3821 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3822 . supportPos - The local index in the cone where the point should be put 3823 - supportPoint - The mesh point to insert 3824 3825 Level: beginner 3826 3827 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3828 @*/ 3829 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3830 { 3831 DM_Plex *mesh = (DM_Plex *)dm->data; 3832 PetscInt pStart, pEnd; 3833 PetscInt dof, off; 3834 3835 PetscFunctionBegin; 3836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3837 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3838 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3839 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3840 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); 3841 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); 3842 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); 3843 mesh->supports[off + supportPos] = supportPoint; 3844 PetscFunctionReturn(PETSC_SUCCESS); 3845 } 3846 3847 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3848 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3849 { 3850 switch (ct) { 3851 case DM_POLYTOPE_SEGMENT: 3852 if (o == -1) return -2; 3853 break; 3854 case DM_POLYTOPE_TRIANGLE: 3855 if (o == -3) return -1; 3856 if (o == -2) return -3; 3857 if (o == -1) return -2; 3858 break; 3859 case DM_POLYTOPE_QUADRILATERAL: 3860 if (o == -4) return -2; 3861 if (o == -3) return -1; 3862 if (o == -2) return -4; 3863 if (o == -1) return -3; 3864 break; 3865 default: 3866 return o; 3867 } 3868 return o; 3869 } 3870 3871 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3872 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3873 { 3874 switch (ct) { 3875 case DM_POLYTOPE_SEGMENT: 3876 if ((o == -2) || (o == 1)) return -1; 3877 if (o == -1) return 0; 3878 break; 3879 case DM_POLYTOPE_TRIANGLE: 3880 if (o == -3) return -2; 3881 if (o == -2) return -1; 3882 if (o == -1) return -3; 3883 break; 3884 case DM_POLYTOPE_QUADRILATERAL: 3885 if (o == -4) return -2; 3886 if (o == -3) return -1; 3887 if (o == -2) return -4; 3888 if (o == -1) return -3; 3889 break; 3890 default: 3891 return o; 3892 } 3893 return o; 3894 } 3895 3896 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3897 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3898 { 3899 PetscInt pStart, pEnd, p; 3900 3901 PetscFunctionBegin; 3902 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3903 for (p = pStart; p < pEnd; ++p) { 3904 const PetscInt *cone, *ornt; 3905 PetscInt coneSize, c; 3906 3907 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3908 PetscCall(DMPlexGetCone(dm, p, &cone)); 3909 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3910 for (c = 0; c < coneSize; ++c) { 3911 DMPolytopeType ct; 3912 const PetscInt o = ornt[c]; 3913 3914 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3915 switch (ct) { 3916 case DM_POLYTOPE_SEGMENT: 3917 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3918 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3919 break; 3920 case DM_POLYTOPE_TRIANGLE: 3921 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3922 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3923 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3924 break; 3925 case DM_POLYTOPE_QUADRILATERAL: 3926 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3927 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3928 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3929 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3930 break; 3931 default: 3932 break; 3933 } 3934 } 3935 } 3936 PetscFunctionReturn(PETSC_SUCCESS); 3937 } 3938 3939 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3940 { 3941 DM_Plex *mesh = (DM_Plex *)dm->data; 3942 3943 PetscFunctionBeginHot; 3944 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3945 if (useCone) { 3946 PetscCall(DMPlexGetConeSize(dm, p, size)); 3947 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3948 } else { 3949 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3950 PetscCall(DMPlexGetSupport(dm, p, arr)); 3951 } 3952 } else { 3953 if (useCone) { 3954 const PetscSection s = mesh->coneSection; 3955 const PetscInt ps = p - s->pStart; 3956 const PetscInt off = s->atlasOff[ps]; 3957 3958 *size = s->atlasDof[ps]; 3959 *arr = mesh->cones + off; 3960 *ornt = mesh->coneOrientations + off; 3961 } else { 3962 const PetscSection s = mesh->supportSection; 3963 const PetscInt ps = p - s->pStart; 3964 const PetscInt off = s->atlasOff[ps]; 3965 3966 *size = s->atlasDof[ps]; 3967 *arr = mesh->supports + off; 3968 } 3969 } 3970 PetscFunctionReturn(PETSC_SUCCESS); 3971 } 3972 3973 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3974 { 3975 DM_Plex *mesh = (DM_Plex *)dm->data; 3976 3977 PetscFunctionBeginHot; 3978 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3979 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3980 } 3981 PetscFunctionReturn(PETSC_SUCCESS); 3982 } 3983 3984 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3985 { 3986 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3987 PetscInt *closure; 3988 const PetscInt *tmp = NULL, *tmpO = NULL; 3989 PetscInt off = 0, tmpSize, t; 3990 3991 PetscFunctionBeginHot; 3992 if (ornt) { 3993 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3994 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; 3995 } 3996 if (*points) { 3997 closure = *points; 3998 } else { 3999 PetscInt maxConeSize, maxSupportSize; 4000 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4001 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 4002 } 4003 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4004 if (ct == DM_POLYTOPE_UNKNOWN) { 4005 closure[off++] = p; 4006 closure[off++] = 0; 4007 for (t = 0; t < tmpSize; ++t) { 4008 closure[off++] = tmp[t]; 4009 closure[off++] = tmpO ? tmpO[t] : 0; 4010 } 4011 } else { 4012 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 4013 4014 /* We assume that cells with a valid type have faces with a valid type */ 4015 closure[off++] = p; 4016 closure[off++] = ornt; 4017 for (t = 0; t < tmpSize; ++t) { 4018 DMPolytopeType ft; 4019 4020 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 4021 closure[off++] = tmp[arr[t]]; 4022 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 4023 } 4024 } 4025 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 4026 if (numPoints) *numPoints = tmpSize + 1; 4027 if (points) *points = closure; 4028 PetscFunctionReturn(PETSC_SUCCESS); 4029 } 4030 4031 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 4032 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 4033 { 4034 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 4035 const PetscInt *cone, *ornt; 4036 PetscInt *pts, *closure = NULL; 4037 DMPolytopeType ft; 4038 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 4039 PetscInt dim, coneSize, c, d, clSize, cl; 4040 4041 PetscFunctionBeginHot; 4042 PetscCall(DMGetDimension(dm, &dim)); 4043 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4044 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4045 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 4046 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 4047 maxSize = PetscMax(coneSeries, supportSeries); 4048 if (*points) { 4049 pts = *points; 4050 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 4051 c = 0; 4052 pts[c++] = point; 4053 pts[c++] = o; 4054 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 4055 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 4056 for (cl = 0; cl < clSize * 2; cl += 2) { 4057 pts[c++] = closure[cl]; 4058 pts[c++] = closure[cl + 1]; 4059 } 4060 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 4061 for (cl = 0; cl < clSize * 2; cl += 2) { 4062 pts[c++] = closure[cl]; 4063 pts[c++] = closure[cl + 1]; 4064 } 4065 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 4066 for (d = 2; d < coneSize; ++d) { 4067 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 4068 pts[c++] = cone[arr[d * 2 + 0]]; 4069 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 4070 } 4071 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 4072 if (dim >= 3) { 4073 for (d = 2; d < coneSize; ++d) { 4074 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 4075 const PetscInt *fcone, *fornt; 4076 PetscInt fconeSize, fc, i; 4077 4078 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 4079 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 4080 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4081 for (fc = 0; fc < fconeSize; ++fc) { 4082 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 4083 const PetscInt co = farr[fc * 2 + 1]; 4084 4085 for (i = 0; i < c; i += 2) 4086 if (pts[i] == cp) break; 4087 if (i == c) { 4088 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 4089 pts[c++] = cp; 4090 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 4091 } 4092 } 4093 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 4094 } 4095 } 4096 *numPoints = c / 2; 4097 *points = pts; 4098 PetscFunctionReturn(PETSC_SUCCESS); 4099 } 4100 4101 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4102 { 4103 DMPolytopeType ct; 4104 PetscInt *closure, *fifo; 4105 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 4106 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 4107 PetscInt depth, maxSize; 4108 4109 PetscFunctionBeginHot; 4110 PetscCall(DMPlexGetDepth(dm, &depth)); 4111 if (depth == 1) { 4112 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 4113 PetscFunctionReturn(PETSC_SUCCESS); 4114 } 4115 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4116 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; 4117 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 4118 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 4119 PetscFunctionReturn(PETSC_SUCCESS); 4120 } 4121 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 4122 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 4123 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 4124 maxSize = PetscMax(coneSeries, supportSeries); 4125 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4126 if (*points) { 4127 closure = *points; 4128 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 4129 closure[closureSize++] = p; 4130 closure[closureSize++] = ornt; 4131 fifo[fifoSize++] = p; 4132 fifo[fifoSize++] = ornt; 4133 fifo[fifoSize++] = ct; 4134 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 4135 while (fifoSize - fifoStart) { 4136 const PetscInt q = fifo[fifoStart++]; 4137 const PetscInt o = fifo[fifoStart++]; 4138 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 4139 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 4140 const PetscInt *tmp, *tmpO = NULL; 4141 PetscInt tmpSize, t; 4142 4143 if (PetscDefined(USE_DEBUG)) { 4144 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 4145 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); 4146 } 4147 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4148 for (t = 0; t < tmpSize; ++t) { 4149 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 4150 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 4151 const PetscInt cp = tmp[ip]; 4152 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 4153 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 4154 PetscInt c; 4155 4156 /* Check for duplicate */ 4157 for (c = 0; c < closureSize; c += 2) { 4158 if (closure[c] == cp) break; 4159 } 4160 if (c == closureSize) { 4161 closure[closureSize++] = cp; 4162 closure[closureSize++] = co; 4163 fifo[fifoSize++] = cp; 4164 fifo[fifoSize++] = co; 4165 fifo[fifoSize++] = ct; 4166 } 4167 } 4168 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4169 } 4170 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4171 if (numPoints) *numPoints = closureSize / 2; 4172 if (points) *points = closure; 4173 PetscFunctionReturn(PETSC_SUCCESS); 4174 } 4175 4176 /*@C 4177 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4178 4179 Not Collective 4180 4181 Input Parameters: 4182 + dm - The `DMPLEX` 4183 . p - The mesh point 4184 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4185 4186 Input/Output Parameter: 4187 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4188 if *points is `NULL` on input, internal storage will be returned, use `DMPlexRestoreTransitiveClosure()`, 4189 otherwise the provided array is used to hold the values 4190 4191 Output Parameter: 4192 . numPoints - The number of points in the closure, so `points` is of size 2*`numPoints` 4193 4194 Level: beginner 4195 4196 Note: 4197 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4198 4199 Fortran Notes: 4200 `points` must be declared with 4201 .vb 4202 PetscInt, pointer :: points(:) 4203 .ve 4204 and is always allocated by the function. 4205 4206 The `numPoints` argument is not present in the Fortran binding. 4207 4208 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4209 @*/ 4210 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4211 { 4212 PetscFunctionBeginHot; 4213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4214 if (numPoints) PetscAssertPointer(numPoints, 4); 4215 if (points) PetscAssertPointer(points, 5); 4216 if (PetscDefined(USE_DEBUG)) { 4217 PetscInt pStart, pEnd; 4218 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4219 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); 4220 } 4221 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4222 PetscFunctionReturn(PETSC_SUCCESS); 4223 } 4224 4225 /*@C 4226 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4227 4228 Not Collective 4229 4230 Input Parameters: 4231 + dm - The `DMPLEX` 4232 . p - The mesh point 4233 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4234 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4235 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4236 4237 Level: beginner 4238 4239 Note: 4240 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4241 4242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4243 @*/ 4244 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4245 { 4246 PetscFunctionBeginHot; 4247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4248 if (numPoints) *numPoints = 0; 4249 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4250 PetscFunctionReturn(PETSC_SUCCESS); 4251 } 4252 4253 /*@ 4254 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4255 4256 Not Collective 4257 4258 Input Parameter: 4259 . dm - The `DMPLEX` 4260 4261 Output Parameters: 4262 + maxConeSize - The maximum number of in-edges 4263 - maxSupportSize - The maximum number of out-edges 4264 4265 Level: beginner 4266 4267 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4268 @*/ 4269 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4270 { 4271 DM_Plex *mesh = (DM_Plex *)dm->data; 4272 4273 PetscFunctionBegin; 4274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4275 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4276 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4277 PetscFunctionReturn(PETSC_SUCCESS); 4278 } 4279 4280 PetscErrorCode DMSetUp_Plex(DM dm) 4281 { 4282 DM_Plex *mesh = (DM_Plex *)dm->data; 4283 PetscInt size, maxSupportSize; 4284 4285 PetscFunctionBegin; 4286 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4287 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4288 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4289 PetscCall(PetscMalloc1(size, &mesh->cones)); 4290 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4291 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4292 if (maxSupportSize) { 4293 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4294 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4295 PetscCall(PetscMalloc1(size, &mesh->supports)); 4296 } 4297 PetscFunctionReturn(PETSC_SUCCESS); 4298 } 4299 4300 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4301 { 4302 PetscFunctionBegin; 4303 if (subdm) PetscCall(DMClone(dm, subdm)); 4304 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, NULL, NULL, is, subdm)); 4305 if (subdm) (*subdm)->useNatural = dm->useNatural; 4306 if (dm->useNatural && dm->sfMigration) { 4307 PetscSF sfNatural; 4308 4309 (*subdm)->sfMigration = dm->sfMigration; 4310 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4311 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4312 (*subdm)->sfNatural = sfNatural; 4313 } 4314 PetscFunctionReturn(PETSC_SUCCESS); 4315 } 4316 4317 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4318 { 4319 PetscInt i = 0; 4320 4321 PetscFunctionBegin; 4322 PetscCall(DMClone(dms[0], superdm)); 4323 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4324 (*superdm)->useNatural = PETSC_FALSE; 4325 for (i = 0; i < len; i++) { 4326 if (dms[i]->useNatural && dms[i]->sfMigration) { 4327 PetscSF sfNatural; 4328 4329 (*superdm)->sfMigration = dms[i]->sfMigration; 4330 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4331 (*superdm)->useNatural = PETSC_TRUE; 4332 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4333 (*superdm)->sfNatural = sfNatural; 4334 break; 4335 } 4336 } 4337 PetscFunctionReturn(PETSC_SUCCESS); 4338 } 4339 4340 /*@ 4341 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4342 4343 Not Collective 4344 4345 Input Parameter: 4346 . dm - The `DMPLEX` 4347 4348 Level: beginner 4349 4350 Note: 4351 This should be called after all calls to `DMPlexSetCone()` 4352 4353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4354 @*/ 4355 PetscErrorCode DMPlexSymmetrize(DM dm) 4356 { 4357 DM_Plex *mesh = (DM_Plex *)dm->data; 4358 PetscInt *offsets; 4359 PetscInt supportSize; 4360 PetscInt pStart, pEnd, p; 4361 4362 PetscFunctionBegin; 4363 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4364 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4365 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4366 /* Calculate support sizes */ 4367 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4368 for (p = pStart; p < pEnd; ++p) { 4369 PetscInt dof, off, c; 4370 4371 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4372 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4373 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4374 } 4375 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4376 /* Calculate supports */ 4377 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4378 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4379 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4380 for (p = pStart; p < pEnd; ++p) { 4381 PetscInt dof, off, c; 4382 4383 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4384 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4385 for (c = off; c < off + dof; ++c) { 4386 const PetscInt q = mesh->cones[c]; 4387 PetscInt offS; 4388 4389 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4390 4391 mesh->supports[offS + offsets[q]] = p; 4392 ++offsets[q]; 4393 } 4394 } 4395 PetscCall(PetscFree(offsets)); 4396 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4397 PetscFunctionReturn(PETSC_SUCCESS); 4398 } 4399 4400 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4401 { 4402 IS stratumIS; 4403 4404 PetscFunctionBegin; 4405 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4406 if (PetscDefined(USE_DEBUG)) { 4407 PetscInt qStart, qEnd, numLevels, level; 4408 PetscBool overlap = PETSC_FALSE; 4409 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4410 for (level = 0; level < numLevels; level++) { 4411 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4412 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4413 overlap = PETSC_TRUE; 4414 break; 4415 } 4416 } 4417 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); 4418 } 4419 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4420 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4421 PetscCall(ISDestroy(&stratumIS)); 4422 PetscFunctionReturn(PETSC_SUCCESS); 4423 } 4424 4425 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4426 { 4427 PetscInt *pMin, *pMax; 4428 PetscInt pStart, pEnd; 4429 PetscInt dmin = PETSC_INT_MAX, dmax = PETSC_INT_MIN; 4430 4431 PetscFunctionBegin; 4432 { 4433 DMLabel label2; 4434 4435 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4436 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4437 } 4438 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4439 for (PetscInt p = pStart; p < pEnd; ++p) { 4440 DMPolytopeType ct; 4441 4442 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4443 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4444 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4445 } 4446 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4447 for (PetscInt d = dmin; d <= dmax; ++d) { 4448 pMin[d] = PETSC_INT_MAX; 4449 pMax[d] = PETSC_INT_MIN; 4450 } 4451 for (PetscInt p = pStart; p < pEnd; ++p) { 4452 DMPolytopeType ct; 4453 PetscInt d; 4454 4455 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4456 d = DMPolytopeTypeGetDim(ct); 4457 pMin[d] = PetscMin(p, pMin[d]); 4458 pMax[d] = PetscMax(p, pMax[d]); 4459 } 4460 for (PetscInt d = dmin; d <= dmax; ++d) { 4461 if (pMin[d] > pMax[d]) continue; 4462 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4463 } 4464 PetscCall(PetscFree2(pMin, pMax)); 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4469 { 4470 PetscInt pStart, pEnd; 4471 PetscInt numRoots = 0, numLeaves = 0; 4472 4473 PetscFunctionBegin; 4474 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4475 { 4476 /* Initialize roots and count leaves */ 4477 PetscInt sMin = PETSC_INT_MAX; 4478 PetscInt sMax = PETSC_INT_MIN; 4479 PetscInt coneSize, supportSize; 4480 4481 for (PetscInt p = pStart; p < pEnd; ++p) { 4482 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4483 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4484 if (!coneSize && supportSize) { 4485 sMin = PetscMin(p, sMin); 4486 sMax = PetscMax(p, sMax); 4487 ++numRoots; 4488 } else if (!supportSize && coneSize) { 4489 ++numLeaves; 4490 } else if (!supportSize && !coneSize) { 4491 /* Isolated points */ 4492 sMin = PetscMin(p, sMin); 4493 sMax = PetscMax(p, sMax); 4494 } 4495 } 4496 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4497 } 4498 4499 if (numRoots + numLeaves == (pEnd - pStart)) { 4500 PetscInt sMin = PETSC_INT_MAX; 4501 PetscInt sMax = PETSC_INT_MIN; 4502 PetscInt coneSize, supportSize; 4503 4504 for (PetscInt p = pStart; p < pEnd; ++p) { 4505 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4506 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4507 if (!supportSize && coneSize) { 4508 sMin = PetscMin(p, sMin); 4509 sMax = PetscMax(p, sMax); 4510 } 4511 } 4512 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4513 } else { 4514 PetscInt level = 0; 4515 PetscInt qStart, qEnd; 4516 4517 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4518 while (qEnd > qStart) { 4519 PetscInt sMin = PETSC_INT_MAX; 4520 PetscInt sMax = PETSC_INT_MIN; 4521 4522 for (PetscInt q = qStart; q < qEnd; ++q) { 4523 const PetscInt *support; 4524 PetscInt supportSize; 4525 4526 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4527 PetscCall(DMPlexGetSupport(dm, q, &support)); 4528 for (PetscInt s = 0; s < supportSize; ++s) { 4529 sMin = PetscMin(support[s], sMin); 4530 sMax = PetscMax(support[s], sMax); 4531 } 4532 } 4533 PetscCall(DMLabelGetNumValues(label, &level)); 4534 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4535 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4536 } 4537 } 4538 PetscFunctionReturn(PETSC_SUCCESS); 4539 } 4540 4541 /*@ 4542 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4543 4544 Collective 4545 4546 Input Parameter: 4547 . dm - The `DMPLEX` 4548 4549 Level: beginner 4550 4551 Notes: 4552 The strata group all points of the same grade, and this function calculates the strata. This 4553 grade can be seen as the height (or depth) of the point in the DAG. 4554 4555 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4556 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4557 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4558 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4559 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4560 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4561 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4562 4563 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4564 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4565 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 4566 to interpolate only that one (e0), so that 4567 .vb 4568 cone(c0) = {e0, v2} 4569 cone(e0) = {v0, v1} 4570 .ve 4571 If `DMPlexStratify()` is run on this mesh, it will give depths 4572 .vb 4573 depth 0 = {v0, v1, v2} 4574 depth 1 = {e0, c0} 4575 .ve 4576 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4577 4578 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4579 4580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4581 @*/ 4582 PetscErrorCode DMPlexStratify(DM dm) 4583 { 4584 DM_Plex *mesh = (DM_Plex *)dm->data; 4585 DMLabel label; 4586 PetscBool flg = PETSC_FALSE; 4587 4588 PetscFunctionBegin; 4589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4590 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4591 4592 // Create depth label 4593 PetscCall(DMRemoveLabel(dm, "depth", NULL)); 4594 PetscCall(DMCreateLabel(dm, "depth")); 4595 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4596 4597 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4598 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4599 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4600 4601 { /* just in case there is an empty process */ 4602 PetscInt numValues, maxValues = 0, v; 4603 4604 PetscCall(DMLabelGetNumValues(label, &numValues)); 4605 PetscCallMPI(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4606 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4607 } 4608 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4609 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4610 PetscFunctionReturn(PETSC_SUCCESS); 4611 } 4612 4613 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4614 { 4615 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4616 PetscInt dim, depth, pheight, coneSize; 4617 PetscBool preferTensor; 4618 4619 PetscFunctionBeginHot; 4620 PetscCall(DMGetDimension(dm, &dim)); 4621 PetscCall(DMPlexGetDepth(dm, &depth)); 4622 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4623 PetscCall(DMPlexGetInterpolatePreferTensor(dm, &preferTensor)); 4624 pheight = depth - pdepth; 4625 if (depth <= 1) { 4626 switch (pdepth) { 4627 case 0: 4628 ct = DM_POLYTOPE_POINT; 4629 break; 4630 case 1: 4631 switch (coneSize) { 4632 case 2: 4633 ct = DM_POLYTOPE_SEGMENT; 4634 break; 4635 case 3: 4636 ct = DM_POLYTOPE_TRIANGLE; 4637 break; 4638 case 4: 4639 switch (dim) { 4640 case 2: 4641 ct = DM_POLYTOPE_QUADRILATERAL; 4642 break; 4643 case 3: 4644 ct = DM_POLYTOPE_TETRAHEDRON; 4645 break; 4646 default: 4647 break; 4648 } 4649 break; 4650 case 5: 4651 ct = DM_POLYTOPE_PYRAMID; 4652 break; 4653 case 6: 4654 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4655 break; 4656 case 8: 4657 ct = DM_POLYTOPE_HEXAHEDRON; 4658 break; 4659 default: 4660 break; 4661 } 4662 } 4663 } else { 4664 if (pdepth == 0) { 4665 ct = DM_POLYTOPE_POINT; 4666 } else if (pheight == 0) { 4667 switch (dim) { 4668 case 1: 4669 switch (coneSize) { 4670 case 2: 4671 ct = DM_POLYTOPE_SEGMENT; 4672 break; 4673 default: 4674 break; 4675 } 4676 break; 4677 case 2: 4678 switch (coneSize) { 4679 case 3: 4680 ct = DM_POLYTOPE_TRIANGLE; 4681 break; 4682 case 4: 4683 ct = DM_POLYTOPE_QUADRILATERAL; 4684 break; 4685 default: 4686 break; 4687 } 4688 break; 4689 case 3: 4690 switch (coneSize) { 4691 case 4: 4692 ct = DM_POLYTOPE_TETRAHEDRON; 4693 break; 4694 case 5: { 4695 const PetscInt *cone; 4696 PetscInt faceConeSize; 4697 4698 PetscCall(DMPlexGetCone(dm, p, &cone)); 4699 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4700 switch (faceConeSize) { 4701 case 3: 4702 ct = preferTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 4703 break; 4704 case 4: 4705 ct = DM_POLYTOPE_PYRAMID; 4706 break; 4707 } 4708 } break; 4709 case 6: 4710 ct = DM_POLYTOPE_HEXAHEDRON; 4711 break; 4712 default: 4713 break; 4714 } 4715 break; 4716 default: 4717 break; 4718 } 4719 } else if (pheight > 0) { 4720 switch (coneSize) { 4721 case 2: 4722 ct = DM_POLYTOPE_SEGMENT; 4723 break; 4724 case 3: 4725 ct = DM_POLYTOPE_TRIANGLE; 4726 break; 4727 case 4: 4728 ct = DM_POLYTOPE_QUADRILATERAL; 4729 break; 4730 default: 4731 break; 4732 } 4733 } 4734 } 4735 *pt = ct; 4736 PetscFunctionReturn(PETSC_SUCCESS); 4737 } 4738 4739 /*@ 4740 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4741 4742 Collective 4743 4744 Input Parameter: 4745 . dm - The `DMPLEX` 4746 4747 Level: developer 4748 4749 Note: 4750 This function is normally called automatically when a cell type is requested. It creates an 4751 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4752 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4753 4754 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4755 4756 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4757 @*/ 4758 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4759 { 4760 DM_Plex *mesh; 4761 DMLabel ctLabel; 4762 PetscInt pStart, pEnd, p; 4763 4764 PetscFunctionBegin; 4765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4766 mesh = (DM_Plex *)dm->data; 4767 PetscCall(DMCreateLabel(dm, "celltype")); 4768 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4769 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4770 PetscCall(PetscFree(mesh->cellTypes)); 4771 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4772 for (p = pStart; p < pEnd; ++p) { 4773 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4774 PetscInt pdepth; 4775 4776 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4777 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4778 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]); 4779 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4780 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 4781 } 4782 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4783 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4784 PetscFunctionReturn(PETSC_SUCCESS); 4785 } 4786 4787 /*@C 4788 DMPlexGetJoin - Get an array for the join of the set of points 4789 4790 Not Collective 4791 4792 Input Parameters: 4793 + dm - The `DMPLEX` object 4794 . numPoints - The number of input points for the join 4795 - points - The input points 4796 4797 Output Parameters: 4798 + numCoveredPoints - The number of points in the join 4799 - coveredPoints - The points in the join 4800 4801 Level: intermediate 4802 4803 Note: 4804 Currently, this is restricted to a single level join 4805 4806 Fortran Notes: 4807 `converedPoints` must be declared with 4808 .vb 4809 PetscInt, pointer :: coveredPints(:) 4810 .ve 4811 4812 The `numCoveredPoints` argument is not present in the Fortran binding. 4813 4814 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4815 @*/ 4816 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4817 { 4818 DM_Plex *mesh = (DM_Plex *)dm->data; 4819 PetscInt *join[2]; 4820 PetscInt joinSize, i = 0; 4821 PetscInt dof, off, p, c, m; 4822 PetscInt maxSupportSize; 4823 4824 PetscFunctionBegin; 4825 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4826 PetscAssertPointer(points, 3); 4827 PetscAssertPointer(numCoveredPoints, 4); 4828 PetscAssertPointer(coveredPoints, 5); 4829 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4830 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4831 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4832 /* Copy in support of first point */ 4833 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4834 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4835 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4836 /* Check each successive support */ 4837 for (p = 1; p < numPoints; ++p) { 4838 PetscInt newJoinSize = 0; 4839 4840 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4841 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4842 for (c = 0; c < dof; ++c) { 4843 const PetscInt point = mesh->supports[off + c]; 4844 4845 for (m = 0; m < joinSize; ++m) { 4846 if (point == join[i][m]) { 4847 join[1 - i][newJoinSize++] = point; 4848 break; 4849 } 4850 } 4851 } 4852 joinSize = newJoinSize; 4853 i = 1 - i; 4854 } 4855 *numCoveredPoints = joinSize; 4856 *coveredPoints = join[i]; 4857 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4858 PetscFunctionReturn(PETSC_SUCCESS); 4859 } 4860 4861 /*@C 4862 DMPlexRestoreJoin - Restore an array for the join of the set of points obtained with `DMPlexGetJoin()` 4863 4864 Not Collective 4865 4866 Input Parameters: 4867 + dm - The `DMPLEX` object 4868 . numPoints - The number of input points for the join 4869 - points - The input points 4870 4871 Output Parameters: 4872 + numCoveredPoints - The number of points in the join 4873 - coveredPoints - The points in the join 4874 4875 Level: intermediate 4876 4877 Fortran Notes: 4878 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4879 4880 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4881 @*/ 4882 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4883 { 4884 PetscFunctionBegin; 4885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4886 if (points) PetscAssertPointer(points, 3); 4887 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4888 PetscAssertPointer(coveredPoints, 5); 4889 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4890 if (numCoveredPoints) *numCoveredPoints = 0; 4891 PetscFunctionReturn(PETSC_SUCCESS); 4892 } 4893 4894 /*@C 4895 DMPlexGetFullJoin - Get an array for the join of the set of points 4896 4897 Not Collective 4898 4899 Input Parameters: 4900 + dm - The `DMPLEX` object 4901 . numPoints - The number of input points for the join 4902 - points - The input points, its length is `numPoints` 4903 4904 Output Parameters: 4905 + numCoveredPoints - The number of points in the join 4906 - coveredPoints - The points in the join, its length is `numCoveredPoints` 4907 4908 Level: intermediate 4909 4910 Fortran Notes: 4911 `points` and `converedPoints` must be declared with 4912 .vb 4913 PetscInt, pointer :: points(:) 4914 PetscInt, pointer :: coveredPints(:) 4915 .ve 4916 4917 The `numCoveredPoints` argument is not present in the Fortran binding. 4918 4919 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4920 @*/ 4921 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 4922 { 4923 PetscInt *offsets, **closures; 4924 PetscInt *join[2]; 4925 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4926 PetscInt p, d, c, m, ms; 4927 4928 PetscFunctionBegin; 4929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4930 PetscAssertPointer(points, 3); 4931 PetscAssertPointer(numCoveredPoints, 4); 4932 PetscAssertPointer(coveredPoints, 5); 4933 4934 PetscCall(DMPlexGetDepth(dm, &depth)); 4935 PetscCall(PetscCalloc1(numPoints, &closures)); 4936 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4937 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4938 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4939 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4940 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4941 4942 for (p = 0; p < numPoints; ++p) { 4943 PetscInt closureSize; 4944 4945 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4946 4947 offsets[p * (depth + 2) + 0] = 0; 4948 for (d = 0; d < depth + 1; ++d) { 4949 PetscInt pStart, pEnd, i; 4950 4951 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4952 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4953 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4954 offsets[p * (depth + 2) + d + 1] = i; 4955 break; 4956 } 4957 } 4958 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4959 } 4960 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); 4961 } 4962 for (d = 0; d < depth + 1; ++d) { 4963 PetscInt dof; 4964 4965 /* Copy in support of first point */ 4966 dof = offsets[d + 1] - offsets[d]; 4967 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4968 /* Check each successive cone */ 4969 for (p = 1; p < numPoints && joinSize; ++p) { 4970 PetscInt newJoinSize = 0; 4971 4972 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4973 for (c = 0; c < dof; ++c) { 4974 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4975 4976 for (m = 0; m < joinSize; ++m) { 4977 if (point == join[i][m]) { 4978 join[1 - i][newJoinSize++] = point; 4979 break; 4980 } 4981 } 4982 } 4983 joinSize = newJoinSize; 4984 i = 1 - i; 4985 } 4986 if (joinSize) break; 4987 } 4988 *numCoveredPoints = joinSize; 4989 *coveredPoints = join[i]; 4990 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4991 PetscCall(PetscFree(closures)); 4992 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4993 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4994 PetscFunctionReturn(PETSC_SUCCESS); 4995 } 4996 4997 /*@C 4998 DMPlexGetMeet - Get an array for the meet of the set of points 4999 5000 Not Collective 5001 5002 Input Parameters: 5003 + dm - The `DMPLEX` object 5004 . numPoints - The number of input points for the meet 5005 - points - The input points, of length `numPoints` 5006 5007 Output Parameters: 5008 + numCoveringPoints - The number of points in the meet 5009 - coveringPoints - The points in the meet, of length `numCoveringPoints` 5010 5011 Level: intermediate 5012 5013 Note: 5014 Currently, this is restricted to a single level meet 5015 5016 Fortran Notes: 5017 `coveringPoints` must be declared with 5018 .vb 5019 PetscInt, pointer :: coveringPoints(:) 5020 .ve 5021 5022 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5023 5024 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5025 @*/ 5026 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt *coveringPoints[]) 5027 { 5028 DM_Plex *mesh = (DM_Plex *)dm->data; 5029 PetscInt *meet[2]; 5030 PetscInt meetSize, i = 0; 5031 PetscInt dof, off, p, c, m; 5032 PetscInt maxConeSize; 5033 5034 PetscFunctionBegin; 5035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5036 PetscAssertPointer(points, 3); 5037 PetscAssertPointer(numCoveringPoints, 4); 5038 PetscAssertPointer(coveringPoints, 5); 5039 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 5040 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 5041 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 5042 /* Copy in cone of first point */ 5043 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 5044 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 5045 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 5046 /* Check each successive cone */ 5047 for (p = 1; p < numPoints; ++p) { 5048 PetscInt newMeetSize = 0; 5049 5050 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 5051 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 5052 for (c = 0; c < dof; ++c) { 5053 const PetscInt point = mesh->cones[off + c]; 5054 5055 for (m = 0; m < meetSize; ++m) { 5056 if (point == meet[i][m]) { 5057 meet[1 - i][newMeetSize++] = point; 5058 break; 5059 } 5060 } 5061 } 5062 meetSize = newMeetSize; 5063 i = 1 - i; 5064 } 5065 *numCoveringPoints = meetSize; 5066 *coveringPoints = meet[i]; 5067 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 5068 PetscFunctionReturn(PETSC_SUCCESS); 5069 } 5070 5071 /*@C 5072 DMPlexRestoreMeet - Restore an array for the meet of the set of points obtained with `DMPlexGetMeet()` 5073 5074 Not Collective 5075 5076 Input Parameters: 5077 + dm - The `DMPLEX` object 5078 . numPoints - The number of input points for the meet 5079 - points - The input points 5080 5081 Output Parameters: 5082 + numCoveredPoints - The number of points in the meet 5083 - coveredPoints - The points in the meet 5084 5085 Level: intermediate 5086 5087 Fortran Notes: 5088 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5089 5090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 5091 @*/ 5092 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5093 { 5094 PetscFunctionBegin; 5095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5096 if (points) PetscAssertPointer(points, 3); 5097 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 5098 PetscAssertPointer(coveredPoints, 5); 5099 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 5100 if (numCoveredPoints) *numCoveredPoints = 0; 5101 PetscFunctionReturn(PETSC_SUCCESS); 5102 } 5103 5104 /*@C 5105 DMPlexGetFullMeet - Get an array for the meet of the set of points 5106 5107 Not Collective 5108 5109 Input Parameters: 5110 + dm - The `DMPLEX` object 5111 . numPoints - The number of input points for the meet 5112 - points - The input points, of length `numPoints` 5113 5114 Output Parameters: 5115 + numCoveredPoints - The number of points in the meet 5116 - coveredPoints - The points in the meet, of length `numCoveredPoints` 5117 5118 Level: intermediate 5119 5120 Fortran Notes: 5121 `points` and `coveredPoints` must be declared with 5122 .vb 5123 PetscInt, pointer :: points(:) 5124 PetscInt, pointer :: coveredPoints(:) 5125 .ve 5126 5127 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 5128 5129 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 5130 @*/ 5131 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt *coveredPoints[]) 5132 { 5133 PetscInt *offsets, **closures; 5134 PetscInt *meet[2]; 5135 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 5136 PetscInt p, h, c, m, mc; 5137 5138 PetscFunctionBegin; 5139 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5140 PetscAssertPointer(points, 3); 5141 PetscAssertPointer(numCoveredPoints, 4); 5142 PetscAssertPointer(coveredPoints, 5); 5143 5144 PetscCall(DMPlexGetDepth(dm, &height)); 5145 PetscCall(PetscMalloc1(numPoints, &closures)); 5146 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5147 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 5148 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 5149 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 5150 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 5151 5152 for (p = 0; p < numPoints; ++p) { 5153 PetscInt closureSize; 5154 5155 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 5156 5157 offsets[p * (height + 2) + 0] = 0; 5158 for (h = 0; h < height + 1; ++h) { 5159 PetscInt pStart, pEnd, i; 5160 5161 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 5162 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 5163 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 5164 offsets[p * (height + 2) + h + 1] = i; 5165 break; 5166 } 5167 } 5168 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 5169 } 5170 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); 5171 } 5172 for (h = 0; h < height + 1; ++h) { 5173 PetscInt dof; 5174 5175 /* Copy in cone of first point */ 5176 dof = offsets[h + 1] - offsets[h]; 5177 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 5178 /* Check each successive cone */ 5179 for (p = 1; p < numPoints && meetSize; ++p) { 5180 PetscInt newMeetSize = 0; 5181 5182 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 5183 for (c = 0; c < dof; ++c) { 5184 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 5185 5186 for (m = 0; m < meetSize; ++m) { 5187 if (point == meet[i][m]) { 5188 meet[1 - i][newMeetSize++] = point; 5189 break; 5190 } 5191 } 5192 } 5193 meetSize = newMeetSize; 5194 i = 1 - i; 5195 } 5196 if (meetSize) break; 5197 } 5198 *numCoveredPoints = meetSize; 5199 *coveredPoints = meet[i]; 5200 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5201 PetscCall(PetscFree(closures)); 5202 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5203 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5204 PetscFunctionReturn(PETSC_SUCCESS); 5205 } 5206 5207 /*@ 5208 DMPlexEqual - Determine if two `DM` have the same topology 5209 5210 Not Collective 5211 5212 Input Parameters: 5213 + dmA - A `DMPLEX` object 5214 - dmB - A `DMPLEX` object 5215 5216 Output Parameter: 5217 . equal - `PETSC_TRUE` if the topologies are identical 5218 5219 Level: intermediate 5220 5221 Note: 5222 We are not solving graph isomorphism, so we do not permute. 5223 5224 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5225 @*/ 5226 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5227 { 5228 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5229 5230 PetscFunctionBegin; 5231 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5232 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5233 PetscAssertPointer(equal, 3); 5234 5235 *equal = PETSC_FALSE; 5236 PetscCall(DMPlexGetDepth(dmA, &depth)); 5237 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5238 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5239 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5240 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5241 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5242 for (p = pStart; p < pEnd; ++p) { 5243 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5244 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5245 5246 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5247 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5248 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5249 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5250 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5251 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5252 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5253 for (c = 0; c < coneSize; ++c) { 5254 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5255 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5256 } 5257 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5258 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5259 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5260 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5261 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5262 for (s = 0; s < supportSize; ++s) { 5263 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5264 } 5265 } 5266 *equal = PETSC_TRUE; 5267 PetscFunctionReturn(PETSC_SUCCESS); 5268 } 5269 5270 /*@ 5271 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5272 5273 Not Collective 5274 5275 Input Parameters: 5276 + dm - The `DMPLEX` 5277 . cellDim - The cell dimension 5278 - numCorners - The number of vertices on a cell 5279 5280 Output Parameter: 5281 . numFaceVertices - The number of vertices on a face 5282 5283 Level: developer 5284 5285 Note: 5286 Of course this can only work for a restricted set of symmetric shapes 5287 5288 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5289 @*/ 5290 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5291 { 5292 MPI_Comm comm; 5293 5294 PetscFunctionBegin; 5295 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5296 PetscAssertPointer(numFaceVertices, 4); 5297 switch (cellDim) { 5298 case 0: 5299 *numFaceVertices = 0; 5300 break; 5301 case 1: 5302 *numFaceVertices = 1; 5303 break; 5304 case 2: 5305 switch (numCorners) { 5306 case 3: /* triangle */ 5307 *numFaceVertices = 2; /* Edge has 2 vertices */ 5308 break; 5309 case 4: /* quadrilateral */ 5310 *numFaceVertices = 2; /* Edge has 2 vertices */ 5311 break; 5312 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5313 *numFaceVertices = 3; /* Edge has 3 vertices */ 5314 break; 5315 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5316 *numFaceVertices = 3; /* Edge has 3 vertices */ 5317 break; 5318 default: 5319 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5320 } 5321 break; 5322 case 3: 5323 switch (numCorners) { 5324 case 4: /* tetradehdron */ 5325 *numFaceVertices = 3; /* Face has 3 vertices */ 5326 break; 5327 case 6: /* tet cohesive cells */ 5328 *numFaceVertices = 4; /* Face has 4 vertices */ 5329 break; 5330 case 8: /* hexahedron */ 5331 *numFaceVertices = 4; /* Face has 4 vertices */ 5332 break; 5333 case 9: /* tet cohesive Lagrange cells */ 5334 *numFaceVertices = 6; /* Face has 6 vertices */ 5335 break; 5336 case 10: /* quadratic tetrahedron */ 5337 *numFaceVertices = 6; /* Face has 6 vertices */ 5338 break; 5339 case 12: /* hex cohesive Lagrange cells */ 5340 *numFaceVertices = 6; /* Face has 6 vertices */ 5341 break; 5342 case 18: /* quadratic tet cohesive Lagrange cells */ 5343 *numFaceVertices = 6; /* Face has 6 vertices */ 5344 break; 5345 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5346 *numFaceVertices = 9; /* Face has 9 vertices */ 5347 break; 5348 default: 5349 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5350 } 5351 break; 5352 default: 5353 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5354 } 5355 PetscFunctionReturn(PETSC_SUCCESS); 5356 } 5357 5358 /*@ 5359 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5360 5361 Not Collective 5362 5363 Input Parameter: 5364 . dm - The `DMPLEX` object 5365 5366 Output Parameter: 5367 . depthLabel - The `DMLabel` recording point depth 5368 5369 Level: developer 5370 5371 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5372 @*/ 5373 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5374 { 5375 PetscFunctionBegin; 5376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5377 PetscAssertPointer(depthLabel, 2); 5378 *depthLabel = dm->depthLabel; 5379 PetscFunctionReturn(PETSC_SUCCESS); 5380 } 5381 5382 /*@ 5383 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5384 5385 Not Collective 5386 5387 Input Parameter: 5388 . dm - The `DMPLEX` object 5389 5390 Output Parameter: 5391 . depth - The number of strata (breadth first levels) in the DAG 5392 5393 Level: developer 5394 5395 Notes: 5396 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5397 5398 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5399 5400 An empty mesh gives -1. 5401 5402 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5403 @*/ 5404 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5405 { 5406 DM_Plex *mesh = (DM_Plex *)dm->data; 5407 DMLabel label; 5408 PetscInt d = -1; 5409 5410 PetscFunctionBegin; 5411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5412 PetscAssertPointer(depth, 2); 5413 if (mesh->tr) { 5414 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5415 } else { 5416 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5417 // Allow missing depths 5418 if (label) PetscCall(DMLabelGetValueBounds(label, NULL, &d)); 5419 *depth = d; 5420 } 5421 PetscFunctionReturn(PETSC_SUCCESS); 5422 } 5423 5424 /*@ 5425 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5426 5427 Not Collective 5428 5429 Input Parameters: 5430 + dm - The `DMPLEX` object 5431 - depth - The requested depth 5432 5433 Output Parameters: 5434 + start - The first point at this `depth` 5435 - end - One beyond the last point at this `depth` 5436 5437 Level: developer 5438 5439 Notes: 5440 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5441 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5442 higher dimension, e.g., "edges". 5443 5444 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5445 @*/ 5446 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5447 { 5448 DM_Plex *mesh = (DM_Plex *)dm->data; 5449 DMLabel label; 5450 PetscInt pStart, pEnd; 5451 5452 PetscFunctionBegin; 5453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5454 if (start) { 5455 PetscAssertPointer(start, 3); 5456 *start = 0; 5457 } 5458 if (end) { 5459 PetscAssertPointer(end, 4); 5460 *end = 0; 5461 } 5462 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5463 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5464 if (depth < 0) { 5465 if (start) *start = pStart; 5466 if (end) *end = pEnd; 5467 PetscFunctionReturn(PETSC_SUCCESS); 5468 } 5469 if (mesh->tr) { 5470 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5471 } else { 5472 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5473 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5474 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5475 } 5476 PetscFunctionReturn(PETSC_SUCCESS); 5477 } 5478 5479 /*@ 5480 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5481 5482 Not Collective 5483 5484 Input Parameters: 5485 + dm - The `DMPLEX` object 5486 - height - The requested height 5487 5488 Output Parameters: 5489 + start - The first point at this `height` 5490 - end - One beyond the last point at this `height` 5491 5492 Level: developer 5493 5494 Notes: 5495 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5496 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5497 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5498 5499 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5500 @*/ 5501 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5502 { 5503 DMLabel label; 5504 PetscInt depth, pStart, pEnd; 5505 5506 PetscFunctionBegin; 5507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5508 if (start) { 5509 PetscAssertPointer(start, 3); 5510 *start = 0; 5511 } 5512 if (end) { 5513 PetscAssertPointer(end, 4); 5514 *end = 0; 5515 } 5516 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5517 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5518 if (height < 0) { 5519 if (start) *start = pStart; 5520 if (end) *end = pEnd; 5521 PetscFunctionReturn(PETSC_SUCCESS); 5522 } 5523 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5524 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5525 else PetscCall(DMGetDimension(dm, &depth)); 5526 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5527 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5528 PetscFunctionReturn(PETSC_SUCCESS); 5529 } 5530 5531 /*@ 5532 DMPlexGetPointDepth - Get the `depth` of a given point 5533 5534 Not Collective 5535 5536 Input Parameters: 5537 + dm - The `DMPLEX` object 5538 - point - The point 5539 5540 Output Parameter: 5541 . depth - The depth of the `point` 5542 5543 Level: intermediate 5544 5545 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5546 @*/ 5547 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5548 { 5549 PetscFunctionBegin; 5550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5551 PetscAssertPointer(depth, 3); 5552 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5553 PetscFunctionReturn(PETSC_SUCCESS); 5554 } 5555 5556 /*@ 5557 DMPlexGetPointHeight - Get the `height` of a given point 5558 5559 Not Collective 5560 5561 Input Parameters: 5562 + dm - The `DMPLEX` object 5563 - point - The point 5564 5565 Output Parameter: 5566 . height - The height of the `point` 5567 5568 Level: intermediate 5569 5570 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5571 @*/ 5572 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5573 { 5574 PetscInt n, pDepth; 5575 5576 PetscFunctionBegin; 5577 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5578 PetscAssertPointer(height, 3); 5579 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5580 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5581 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5582 PetscFunctionReturn(PETSC_SUCCESS); 5583 } 5584 5585 /*@ 5586 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5587 5588 Not Collective 5589 5590 Input Parameter: 5591 . dm - The `DMPLEX` object 5592 5593 Output Parameter: 5594 . celltypeLabel - The `DMLabel` recording cell polytope type 5595 5596 Level: developer 5597 5598 Note: 5599 This function will trigger automatica computation of cell types. This can be disabled by calling 5600 `DMCreateLabel`(dm, "celltype") beforehand. 5601 5602 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5603 @*/ 5604 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5605 { 5606 PetscFunctionBegin; 5607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5608 PetscAssertPointer(celltypeLabel, 2); 5609 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5610 *celltypeLabel = dm->celltypeLabel; 5611 PetscFunctionReturn(PETSC_SUCCESS); 5612 } 5613 5614 /*@ 5615 DMPlexGetCellType - Get the polytope type of a given cell 5616 5617 Not Collective 5618 5619 Input Parameters: 5620 + dm - The `DMPLEX` object 5621 - cell - The cell 5622 5623 Output Parameter: 5624 . celltype - The polytope type of the cell 5625 5626 Level: intermediate 5627 5628 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5629 @*/ 5630 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5631 { 5632 DM_Plex *mesh = (DM_Plex *)dm->data; 5633 DMLabel label; 5634 PetscInt ct; 5635 5636 PetscFunctionBegin; 5637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5638 PetscAssertPointer(celltype, 3); 5639 if (mesh->tr) { 5640 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5641 } else { 5642 PetscInt pStart, pEnd; 5643 5644 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5645 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5646 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5647 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5648 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5649 for (PetscInt p = pStart; p < pEnd; p++) { 5650 PetscCall(DMLabelGetValue(label, p, &ct)); 5651 mesh->cellTypes[p - pStart].value_as_uint8 = (uint8_t)ct; 5652 } 5653 } 5654 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5655 if (PetscDefined(USE_DEBUG)) { 5656 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5657 PetscCall(DMLabelGetValue(label, cell, &ct)); 5658 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5659 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5660 } 5661 } 5662 PetscFunctionReturn(PETSC_SUCCESS); 5663 } 5664 5665 /*@ 5666 DMPlexSetCellType - Set the polytope type of a given cell 5667 5668 Not Collective 5669 5670 Input Parameters: 5671 + dm - The `DMPLEX` object 5672 . cell - The cell 5673 - celltype - The polytope type of the cell 5674 5675 Level: advanced 5676 5677 Note: 5678 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5679 is executed. This function will override the computed type. However, if automatic classification will not succeed 5680 and a user wants to manually specify all types, the classification must be disabled by calling 5681 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5682 5683 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5684 @*/ 5685 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5686 { 5687 DM_Plex *mesh = (DM_Plex *)dm->data; 5688 DMLabel label; 5689 PetscInt pStart, pEnd; 5690 5691 PetscFunctionBegin; 5692 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5693 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5694 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5695 PetscCall(DMLabelSetValue(label, cell, celltype)); 5696 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5697 mesh->cellTypes[cell - pStart].value_as_uint8 = (uint8_t)celltype; 5698 PetscFunctionReturn(PETSC_SUCCESS); 5699 } 5700 5701 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5702 { 5703 PetscSection section; 5704 PetscInt maxHeight; 5705 const char *prefix; 5706 5707 PetscFunctionBegin; 5708 PetscCall(DMClone(dm, cdm)); 5709 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5710 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5711 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5712 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5713 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5714 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5715 PetscCall(DMSetLocalSection(*cdm, section)); 5716 PetscCall(PetscSectionDestroy(§ion)); 5717 5718 PetscCall(DMSetNumFields(*cdm, 1)); 5719 PetscCall(DMCreateDS(*cdm)); 5720 (*cdm)->cloneOpts = PETSC_TRUE; 5721 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5722 PetscFunctionReturn(PETSC_SUCCESS); 5723 } 5724 5725 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5726 { 5727 Vec coordsLocal, cellCoordsLocal; 5728 DM coordsDM, cellCoordsDM; 5729 5730 PetscFunctionBegin; 5731 *field = NULL; 5732 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5733 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5734 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5735 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5736 if (coordsLocal && coordsDM) { 5737 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5738 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5739 } 5740 PetscFunctionReturn(PETSC_SUCCESS); 5741 } 5742 5743 /*@ 5744 DMPlexGetConeSection - Return a section which describes the layout of cone data 5745 5746 Not Collective 5747 5748 Input Parameter: 5749 . dm - The `DMPLEX` object 5750 5751 Output Parameter: 5752 . section - The `PetscSection` object 5753 5754 Level: developer 5755 5756 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5757 @*/ 5758 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5759 { 5760 DM_Plex *mesh = (DM_Plex *)dm->data; 5761 5762 PetscFunctionBegin; 5763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5764 if (section) *section = mesh->coneSection; 5765 PetscFunctionReturn(PETSC_SUCCESS); 5766 } 5767 5768 /*@ 5769 DMPlexGetSupportSection - Return a section which describes the layout of support data 5770 5771 Not Collective 5772 5773 Input Parameter: 5774 . dm - The `DMPLEX` object 5775 5776 Output Parameter: 5777 . section - The `PetscSection` object 5778 5779 Level: developer 5780 5781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5782 @*/ 5783 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5784 { 5785 DM_Plex *mesh = (DM_Plex *)dm->data; 5786 5787 PetscFunctionBegin; 5788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5789 if (section) *section = mesh->supportSection; 5790 PetscFunctionReturn(PETSC_SUCCESS); 5791 } 5792 5793 /*@C 5794 DMPlexGetCones - Return cone data 5795 5796 Not Collective 5797 5798 Input Parameter: 5799 . dm - The `DMPLEX` object 5800 5801 Output Parameter: 5802 . cones - The cone for each point 5803 5804 Level: developer 5805 5806 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5807 @*/ 5808 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5809 { 5810 DM_Plex *mesh = (DM_Plex *)dm->data; 5811 5812 PetscFunctionBegin; 5813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5814 if (cones) *cones = mesh->cones; 5815 PetscFunctionReturn(PETSC_SUCCESS); 5816 } 5817 5818 /*@C 5819 DMPlexGetConeOrientations - Return cone orientation data 5820 5821 Not Collective 5822 5823 Input Parameter: 5824 . dm - The `DMPLEX` object 5825 5826 Output Parameter: 5827 . coneOrientations - The array of cone orientations for all points 5828 5829 Level: developer 5830 5831 Notes: 5832 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points 5833 as returned by `DMPlexGetConeOrientation()`. 5834 5835 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5836 5837 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5838 @*/ 5839 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5840 { 5841 DM_Plex *mesh = (DM_Plex *)dm->data; 5842 5843 PetscFunctionBegin; 5844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5845 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5846 PetscFunctionReturn(PETSC_SUCCESS); 5847 } 5848 5849 /* FEM Support */ 5850 5851 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5852 { 5853 PetscInt depth; 5854 5855 PetscFunctionBegin; 5856 PetscCall(DMPlexGetDepth(plex, &depth)); 5857 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5858 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5859 PetscFunctionReturn(PETSC_SUCCESS); 5860 } 5861 5862 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5863 { 5864 PetscInt depth; 5865 5866 PetscFunctionBegin; 5867 PetscCall(DMPlexGetDepth(plex, &depth)); 5868 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5869 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5870 PetscFunctionReturn(PETSC_SUCCESS); 5871 } 5872 5873 /* 5874 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5875 representing a line in the section. 5876 */ 5877 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5878 { 5879 PetscObject obj; 5880 PetscClassId id; 5881 PetscFE fe = NULL; 5882 5883 PetscFunctionBeginHot; 5884 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5885 PetscCall(DMGetField(dm, field, NULL, &obj)); 5886 PetscCall(PetscObjectGetClassId(obj, &id)); 5887 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5888 5889 if (!fe) { 5890 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5891 /* An order k SEM disc has k-1 dofs on an edge */ 5892 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5893 *k = *k / *Nc + 1; 5894 } else { 5895 PetscInt dual_space_size, dim; 5896 PetscDualSpace dsp; 5897 5898 PetscCall(DMGetDimension(dm, &dim)); 5899 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5900 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5901 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5902 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5903 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5904 } 5905 PetscFunctionReturn(PETSC_SUCCESS); 5906 } 5907 5908 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5909 { 5910 PetscFunctionBeginHot; 5911 if (tensor) { 5912 *dof = PetscPowInt(k + 1, dim); 5913 } else { 5914 switch (dim) { 5915 case 1: 5916 *dof = k + 1; 5917 break; 5918 case 2: 5919 *dof = ((k + 1) * (k + 2)) / 2; 5920 break; 5921 case 3: 5922 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5923 break; 5924 default: 5925 *dof = 0; 5926 } 5927 } 5928 PetscFunctionReturn(PETSC_SUCCESS); 5929 } 5930 5931 /*@ 5932 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5933 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5934 section provided (or the section of the `DM`). 5935 5936 Input Parameters: 5937 + dm - The `DM` 5938 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5939 - section - The `PetscSection` to reorder, or `NULL` for the default section 5940 5941 Example: 5942 A typical interpolated single-quad mesh might order points as 5943 .vb 5944 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5945 5946 v4 -- e6 -- v3 5947 | | 5948 e7 c0 e8 5949 | | 5950 v1 -- e5 -- v2 5951 .ve 5952 5953 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5954 dofs in the order of points, e.g., 5955 .vb 5956 c0 -> [0,1,2,3] 5957 v1 -> [4] 5958 ... 5959 e5 -> [8, 9] 5960 .ve 5961 5962 which corresponds to the dofs 5963 .vb 5964 6 10 11 7 5965 13 2 3 15 5966 12 0 1 14 5967 4 8 9 5 5968 .ve 5969 5970 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5971 .vb 5972 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5973 .ve 5974 5975 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5976 .vb 5977 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5978 .ve 5979 5980 Level: developer 5981 5982 Notes: 5983 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5984 degree of the basis. 5985 5986 This is required to run with libCEED. 5987 5988 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5989 @*/ 5990 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5991 { 5992 DMLabel label; 5993 PetscInt dim, depth = -1, eStart = -1, Nf; 5994 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5995 5996 PetscFunctionBegin; 5997 PetscCall(DMGetDimension(dm, &dim)); 5998 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5999 if (point < 0) { 6000 PetscInt sStart, sEnd; 6001 6002 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 6003 point = sEnd - sStart ? sStart : point; 6004 } 6005 PetscCall(DMPlexGetDepthLabel(dm, &label)); 6006 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 6007 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6008 if (depth == 1) { 6009 eStart = point; 6010 } else if (depth == dim) { 6011 const PetscInt *cone; 6012 6013 PetscCall(DMPlexGetCone(dm, point, &cone)); 6014 if (dim == 2) eStart = cone[0]; 6015 else if (dim == 3) { 6016 const PetscInt *cone2; 6017 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 6018 eStart = cone2[0]; 6019 } 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); 6020 } 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); 6021 6022 PetscCall(PetscSectionGetNumFields(section, &Nf)); 6023 for (PetscInt d = 1; d <= dim; d++) { 6024 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 6025 PetscInt *perm; 6026 6027 for (f = 0; f < Nf; ++f) { 6028 PetscInt dof; 6029 6030 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6031 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 6032 if (!continuous && d < dim) continue; 6033 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6034 size += dof * Nc; 6035 } 6036 PetscCall(PetscMalloc1(size, &perm)); 6037 for (f = 0; f < Nf; ++f) { 6038 switch (d) { 6039 case 1: 6040 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6041 if (!continuous && d < dim) continue; 6042 /* 6043 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 6044 We want [ vtx0; edge of length k-1; vtx1 ] 6045 */ 6046 if (continuous) { 6047 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 6048 for (i = 0; i < k - 1; i++) 6049 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 6050 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 6051 foffset = offset; 6052 } else { 6053 PetscInt dof; 6054 6055 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6056 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6057 foffset = offset; 6058 } 6059 break; 6060 case 2: 6061 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 6062 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6063 if (!continuous && d < dim) continue; 6064 /* The SEM order is 6065 6066 v_lb, {e_b}, v_rb, 6067 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 6068 v_lt, reverse {e_t}, v_rt 6069 */ 6070 if (continuous) { 6071 const PetscInt of = 0; 6072 const PetscInt oeb = of + PetscSqr(k - 1); 6073 const PetscInt oer = oeb + (k - 1); 6074 const PetscInt oet = oer + (k - 1); 6075 const PetscInt oel = oet + (k - 1); 6076 const PetscInt ovlb = oel + (k - 1); 6077 const PetscInt ovrb = ovlb + 1; 6078 const PetscInt ovrt = ovrb + 1; 6079 const PetscInt ovlt = ovrt + 1; 6080 PetscInt o; 6081 6082 /* bottom */ 6083 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 6084 for (o = oeb; o < oer; ++o) 6085 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6086 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 6087 /* middle */ 6088 for (i = 0; i < k - 1; ++i) { 6089 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 6090 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 6091 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6092 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 6093 } 6094 /* top */ 6095 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 6096 for (o = oel - 1; o >= oet; --o) 6097 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6098 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 6099 foffset = offset; 6100 } else { 6101 PetscInt dof; 6102 6103 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6104 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6105 foffset = offset; 6106 } 6107 break; 6108 case 3: 6109 /* The original hex closure is 6110 6111 {c, 6112 f_b, f_t, f_f, f_b, f_r, f_l, 6113 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 6114 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 6115 */ 6116 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 6117 if (!continuous && d < dim) continue; 6118 /* The SEM order is 6119 Bottom Slice 6120 v_blf, {e^{(k-1)-n}_bf}, v_brf, 6121 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 6122 v_blb, {e_bb}, v_brb, 6123 6124 Middle Slice (j) 6125 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 6126 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 6127 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 6128 6129 Top Slice 6130 v_tlf, {e_tf}, v_trf, 6131 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 6132 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 6133 */ 6134 if (continuous) { 6135 const PetscInt oc = 0; 6136 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 6137 const PetscInt oft = ofb + PetscSqr(k - 1); 6138 const PetscInt off = oft + PetscSqr(k - 1); 6139 const PetscInt ofk = off + PetscSqr(k - 1); 6140 const PetscInt ofr = ofk + PetscSqr(k - 1); 6141 const PetscInt ofl = ofr + PetscSqr(k - 1); 6142 const PetscInt oebl = ofl + PetscSqr(k - 1); 6143 const PetscInt oebb = oebl + (k - 1); 6144 const PetscInt oebr = oebb + (k - 1); 6145 const PetscInt oebf = oebr + (k - 1); 6146 const PetscInt oetf = oebf + (k - 1); 6147 const PetscInt oetr = oetf + (k - 1); 6148 const PetscInt oetb = oetr + (k - 1); 6149 const PetscInt oetl = oetb + (k - 1); 6150 const PetscInt oerf = oetl + (k - 1); 6151 const PetscInt oelf = oerf + (k - 1); 6152 const PetscInt oelb = oelf + (k - 1); 6153 const PetscInt oerb = oelb + (k - 1); 6154 const PetscInt ovblf = oerb + (k - 1); 6155 const PetscInt ovblb = ovblf + 1; 6156 const PetscInt ovbrb = ovblb + 1; 6157 const PetscInt ovbrf = ovbrb + 1; 6158 const PetscInt ovtlf = ovbrf + 1; 6159 const PetscInt ovtrf = ovtlf + 1; 6160 const PetscInt ovtrb = ovtrf + 1; 6161 const PetscInt ovtlb = ovtrb + 1; 6162 PetscInt o, n; 6163 6164 /* Bottom Slice */ 6165 /* bottom */ 6166 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 6167 for (o = oetf - 1; o >= oebf; --o) 6168 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6169 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 6170 /* middle */ 6171 for (i = 0; i < k - 1; ++i) { 6172 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 6173 for (n = 0; n < k - 1; ++n) { 6174 o = ofb + n * (k - 1) + i; 6175 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6176 } 6177 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 6178 } 6179 /* top */ 6180 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 6181 for (o = oebb; o < oebr; ++o) 6182 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6183 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 6184 6185 /* Middle Slice */ 6186 for (j = 0; j < k - 1; ++j) { 6187 /* bottom */ 6188 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 6189 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 6190 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6191 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 6192 /* middle */ 6193 for (i = 0; i < k - 1; ++i) { 6194 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6195 for (n = 0; n < k - 1; ++n) 6196 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6197 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6198 } 6199 /* top */ 6200 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6201 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6202 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6203 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6204 } 6205 6206 /* Top Slice */ 6207 /* bottom */ 6208 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6209 for (o = oetf; o < oetr; ++o) 6210 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6211 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6212 /* middle */ 6213 for (i = 0; i < k - 1; ++i) { 6214 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6215 for (n = 0; n < k - 1; ++n) 6216 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6217 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6218 } 6219 /* top */ 6220 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6221 for (o = oetl - 1; o >= oetb; --o) 6222 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6223 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6224 6225 foffset = offset; 6226 } else { 6227 PetscInt dof; 6228 6229 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6230 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6231 foffset = offset; 6232 } 6233 break; 6234 default: 6235 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6236 } 6237 } 6238 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6239 /* Check permutation */ 6240 { 6241 PetscInt *check; 6242 6243 PetscCall(PetscMalloc1(size, &check)); 6244 for (i = 0; i < size; ++i) { 6245 check[i] = -1; 6246 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6247 } 6248 for (i = 0; i < size; ++i) check[perm[i]] = i; 6249 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6250 PetscCall(PetscFree(check)); 6251 } 6252 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6253 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6254 PetscInt *loc_perm; 6255 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6256 for (PetscInt i = 0; i < size; i++) { 6257 loc_perm[i] = perm[i]; 6258 loc_perm[size + i] = size + perm[i]; 6259 } 6260 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6261 } 6262 } 6263 PetscFunctionReturn(PETSC_SUCCESS); 6264 } 6265 6266 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6267 { 6268 PetscDS prob; 6269 PetscInt depth, Nf, h; 6270 DMLabel label; 6271 6272 PetscFunctionBeginHot; 6273 PetscCall(DMGetDS(dm, &prob)); 6274 Nf = prob->Nf; 6275 label = dm->depthLabel; 6276 *dspace = NULL; 6277 if (field < Nf) { 6278 PetscObject disc = prob->disc[field]; 6279 6280 if (disc->classid == PETSCFE_CLASSID) { 6281 PetscDualSpace dsp; 6282 6283 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6284 PetscCall(DMLabelGetNumValues(label, &depth)); 6285 PetscCall(DMLabelGetValue(label, point, &h)); 6286 h = depth - 1 - h; 6287 if (h) { 6288 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6289 } else { 6290 *dspace = dsp; 6291 } 6292 } 6293 } 6294 PetscFunctionReturn(PETSC_SUCCESS); 6295 } 6296 6297 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6298 { 6299 PetscScalar *array; 6300 const PetscScalar *vArray; 6301 const PetscInt *cone, *coneO; 6302 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6303 6304 PetscFunctionBeginHot; 6305 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6306 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6307 PetscCall(DMPlexGetCone(dm, point, &cone)); 6308 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6309 if (!values || !*values) { 6310 if ((point >= pStart) && (point < pEnd)) { 6311 PetscInt dof; 6312 6313 PetscCall(PetscSectionGetDof(section, point, &dof)); 6314 size += dof; 6315 } 6316 for (p = 0; p < numPoints; ++p) { 6317 const PetscInt cp = cone[p]; 6318 PetscInt dof; 6319 6320 if ((cp < pStart) || (cp >= pEnd)) continue; 6321 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6322 size += dof; 6323 } 6324 if (!values) { 6325 if (csize) *csize = size; 6326 PetscFunctionReturn(PETSC_SUCCESS); 6327 } 6328 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6329 } else { 6330 array = *values; 6331 } 6332 size = 0; 6333 PetscCall(VecGetArrayRead(v, &vArray)); 6334 if ((point >= pStart) && (point < pEnd)) { 6335 PetscInt dof, off, d; 6336 const PetscScalar *varr; 6337 6338 PetscCall(PetscSectionGetDof(section, point, &dof)); 6339 PetscCall(PetscSectionGetOffset(section, point, &off)); 6340 varr = PetscSafePointerPlusOffset(vArray, off); 6341 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6342 size += dof; 6343 } 6344 for (p = 0; p < numPoints; ++p) { 6345 const PetscInt cp = cone[p]; 6346 PetscInt o = coneO[p]; 6347 PetscInt dof, off, d; 6348 const PetscScalar *varr; 6349 6350 if ((cp < pStart) || (cp >= pEnd)) continue; 6351 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6352 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6353 varr = PetscSafePointerPlusOffset(vArray, off); 6354 if (o >= 0) { 6355 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6356 } else { 6357 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6358 } 6359 size += dof; 6360 } 6361 PetscCall(VecRestoreArrayRead(v, &vArray)); 6362 if (!*values) { 6363 if (csize) *csize = size; 6364 *values = array; 6365 } else { 6366 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6367 *csize = size; 6368 } 6369 PetscFunctionReturn(PETSC_SUCCESS); 6370 } 6371 6372 /* Compress out points not in the section */ 6373 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6374 { 6375 const PetscInt np = *numPoints; 6376 PetscInt pStart, pEnd, p, q; 6377 6378 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6379 for (p = 0, q = 0; p < np; ++p) { 6380 const PetscInt r = points[p * 2]; 6381 if ((r >= pStart) && (r < pEnd)) { 6382 points[q * 2] = r; 6383 points[q * 2 + 1] = points[p * 2 + 1]; 6384 ++q; 6385 } 6386 } 6387 *numPoints = q; 6388 return PETSC_SUCCESS; 6389 } 6390 6391 /* Compressed closure does not apply closure permutation */ 6392 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6393 { 6394 const PetscInt *cla = NULL; 6395 PetscInt np, *pts = NULL; 6396 6397 PetscFunctionBeginHot; 6398 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6399 if (!ornt && *clPoints) { 6400 PetscInt dof, off; 6401 6402 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6403 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6404 PetscCall(ISGetIndices(*clPoints, &cla)); 6405 np = dof / 2; 6406 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6407 } else { 6408 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6409 PetscCall(CompressPoints_Private(section, &np, pts)); 6410 } 6411 *numPoints = np; 6412 *points = pts; 6413 *clp = cla; 6414 PetscFunctionReturn(PETSC_SUCCESS); 6415 } 6416 6417 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6418 { 6419 PetscFunctionBeginHot; 6420 if (!*clPoints) { 6421 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6422 } else { 6423 PetscCall(ISRestoreIndices(*clPoints, clp)); 6424 } 6425 *numPoints = 0; 6426 *points = NULL; 6427 *clSec = NULL; 6428 *clPoints = NULL; 6429 *clp = NULL; 6430 PetscFunctionReturn(PETSC_SUCCESS); 6431 } 6432 6433 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6434 { 6435 PetscInt offset = 0, p; 6436 const PetscInt **perms = NULL; 6437 const PetscScalar **flips = NULL; 6438 6439 PetscFunctionBeginHot; 6440 *size = 0; 6441 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6442 for (p = 0; p < numPoints; p++) { 6443 const PetscInt point = points[2 * p]; 6444 const PetscInt *perm = perms ? perms[p] : NULL; 6445 const PetscScalar *flip = flips ? flips[p] : NULL; 6446 PetscInt dof, off, d; 6447 const PetscScalar *varr; 6448 6449 PetscCall(PetscSectionGetDof(section, point, &dof)); 6450 PetscCall(PetscSectionGetOffset(section, point, &off)); 6451 varr = PetscSafePointerPlusOffset(vArray, off); 6452 if (clperm) { 6453 if (perm) { 6454 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6455 } else { 6456 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6457 } 6458 if (flip) { 6459 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6460 } 6461 } else { 6462 if (perm) { 6463 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6464 } else { 6465 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6466 } 6467 if (flip) { 6468 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6469 } 6470 } 6471 offset += dof; 6472 } 6473 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6474 *size = offset; 6475 PetscFunctionReturn(PETSC_SUCCESS); 6476 } 6477 6478 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[]) 6479 { 6480 PetscInt offset = 0, f; 6481 6482 PetscFunctionBeginHot; 6483 *size = 0; 6484 for (f = 0; f < numFields; ++f) { 6485 PetscInt p; 6486 const PetscInt **perms = NULL; 6487 const PetscScalar **flips = NULL; 6488 6489 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6490 for (p = 0; p < numPoints; p++) { 6491 const PetscInt point = points[2 * p]; 6492 PetscInt fdof, foff, b; 6493 const PetscScalar *varr; 6494 const PetscInt *perm = perms ? perms[p] : NULL; 6495 const PetscScalar *flip = flips ? flips[p] : NULL; 6496 6497 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6498 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6499 varr = &vArray[foff]; 6500 if (clperm) { 6501 if (perm) { 6502 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6503 } else { 6504 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6505 } 6506 if (flip) { 6507 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6508 } 6509 } else { 6510 if (perm) { 6511 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6512 } else { 6513 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6514 } 6515 if (flip) { 6516 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6517 } 6518 } 6519 offset += fdof; 6520 } 6521 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6522 } 6523 *size = offset; 6524 PetscFunctionReturn(PETSC_SUCCESS); 6525 } 6526 6527 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6528 { 6529 PetscSection clSection; 6530 IS clPoints; 6531 PetscInt *points = NULL; 6532 const PetscInt *clp, *perm = NULL; 6533 PetscInt depth, numFields, numPoints, asize; 6534 6535 PetscFunctionBeginHot; 6536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6537 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6538 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6539 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6540 PetscCall(DMPlexGetDepth(dm, &depth)); 6541 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6542 if (depth == 1 && numFields < 2) { 6543 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6544 PetscFunctionReturn(PETSC_SUCCESS); 6545 } 6546 /* Get points */ 6547 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6548 /* Get sizes */ 6549 asize = 0; 6550 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6551 PetscInt dof; 6552 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6553 asize += dof; 6554 } 6555 if (values) { 6556 const PetscScalar *vArray; 6557 PetscInt size; 6558 6559 if (*values) { 6560 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); 6561 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6562 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6563 PetscCall(VecGetArrayRead(v, &vArray)); 6564 /* Get values */ 6565 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6566 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6567 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6568 /* Cleanup array */ 6569 PetscCall(VecRestoreArrayRead(v, &vArray)); 6570 } 6571 if (csize) *csize = asize; 6572 /* Cleanup points */ 6573 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6574 PetscFunctionReturn(PETSC_SUCCESS); 6575 } 6576 6577 /*@C 6578 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6579 6580 Not collective 6581 6582 Input Parameters: 6583 + dm - The `DM` 6584 . section - The section describing the layout in `v`, or `NULL` to use the default section 6585 . v - The local vector 6586 - point - The point in the `DM` 6587 6588 Input/Output Parameters: 6589 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6590 - values - An array to use for the values, or *values = `NULL` to have it allocated automatically; 6591 if the user provided `NULL`, it is a borrowed array and should not be freed, use `DMPlexVecRestoreClosure()` to return it 6592 6593 Level: intermediate 6594 6595 Notes: 6596 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6597 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6598 assembly function, and a user may already have allocated storage for this operation. 6599 6600 A typical use could be 6601 .vb 6602 values = NULL; 6603 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6604 for (cl = 0; cl < clSize; ++cl) { 6605 <Compute on closure> 6606 } 6607 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6608 .ve 6609 or 6610 .vb 6611 PetscMalloc1(clMaxSize, &values); 6612 for (p = pStart; p < pEnd; ++p) { 6613 clSize = clMaxSize; 6614 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6615 for (cl = 0; cl < clSize; ++cl) { 6616 <Compute on closure> 6617 } 6618 } 6619 PetscFree(values); 6620 .ve 6621 6622 Fortran Notes: 6623 The `csize` argument is not present in the Fortran binding. 6624 6625 `values` must be declared with 6626 .vb 6627 PetscScalar,dimension(:),pointer :: values 6628 .ve 6629 and it will be allocated internally by PETSc to hold the values returned 6630 6631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6632 @*/ 6633 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6634 { 6635 PetscFunctionBeginHot; 6636 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6637 PetscFunctionReturn(PETSC_SUCCESS); 6638 } 6639 6640 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6641 { 6642 DMLabel depthLabel; 6643 PetscSection clSection; 6644 IS clPoints; 6645 PetscScalar *array; 6646 const PetscScalar *vArray; 6647 PetscInt *points = NULL; 6648 const PetscInt *clp, *perm = NULL; 6649 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6650 6651 PetscFunctionBeginHot; 6652 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6653 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6654 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6655 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6656 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6657 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6658 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6659 if (mdepth == 1 && numFields < 2) { 6660 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6661 PetscFunctionReturn(PETSC_SUCCESS); 6662 } 6663 /* Get points */ 6664 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6665 for (clsize = 0, p = 0; p < Np; p++) { 6666 PetscInt dof; 6667 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6668 clsize += dof; 6669 } 6670 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6671 /* Filter points */ 6672 for (p = 0; p < numPoints * 2; p += 2) { 6673 PetscInt dep; 6674 6675 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6676 if (dep != depth) continue; 6677 points[Np * 2 + 0] = points[p]; 6678 points[Np * 2 + 1] = points[p + 1]; 6679 ++Np; 6680 } 6681 /* Get array */ 6682 if (!values || !*values) { 6683 PetscInt asize = 0, dof; 6684 6685 for (p = 0; p < Np * 2; p += 2) { 6686 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6687 asize += dof; 6688 } 6689 if (!values) { 6690 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6691 if (csize) *csize = asize; 6692 PetscFunctionReturn(PETSC_SUCCESS); 6693 } 6694 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6695 } else { 6696 array = *values; 6697 } 6698 PetscCall(VecGetArrayRead(v, &vArray)); 6699 /* Get values */ 6700 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6701 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6702 /* Cleanup points */ 6703 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6704 /* Cleanup array */ 6705 PetscCall(VecRestoreArrayRead(v, &vArray)); 6706 if (!*values) { 6707 if (csize) *csize = size; 6708 *values = array; 6709 } else { 6710 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6711 *csize = size; 6712 } 6713 PetscFunctionReturn(PETSC_SUCCESS); 6714 } 6715 6716 /*@C 6717 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' obtained with `DMPlexVecGetClosure()` 6718 6719 Not collective 6720 6721 Input Parameters: 6722 + dm - The `DM` 6723 . section - The section describing the layout in `v`, or `NULL` to use the default section 6724 . v - The local vector 6725 . point - The point in the `DM` 6726 . csize - The number of values in the closure, or `NULL` 6727 - values - The array of values 6728 6729 Level: intermediate 6730 6731 Note: 6732 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6733 6734 Fortran Note: 6735 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6736 6737 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6738 @*/ 6739 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6740 { 6741 PetscInt size = 0; 6742 6743 PetscFunctionBegin; 6744 /* Should work without recalculating size */ 6745 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6746 *values = NULL; 6747 PetscFunctionReturn(PETSC_SUCCESS); 6748 } 6749 6750 static inline void add(PetscScalar *x, PetscScalar y) 6751 { 6752 *x += y; 6753 } 6754 static inline void insert(PetscScalar *x, PetscScalar y) 6755 { 6756 *x = y; 6757 } 6758 6759 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[]) 6760 { 6761 PetscInt cdof; /* The number of constraints on this point */ 6762 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6763 PetscScalar *a; 6764 PetscInt off, cind = 0, k; 6765 6766 PetscFunctionBegin; 6767 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6768 PetscCall(PetscSectionGetOffset(section, point, &off)); 6769 a = &array[off]; 6770 if (!cdof || setBC) { 6771 if (clperm) { 6772 if (perm) { 6773 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6774 } else { 6775 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6776 } 6777 } else { 6778 if (perm) { 6779 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6780 } else { 6781 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6782 } 6783 } 6784 } else { 6785 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6786 if (clperm) { 6787 if (perm) { 6788 for (k = 0; k < dof; ++k) { 6789 if ((cind < cdof) && (k == cdofs[cind])) { 6790 ++cind; 6791 continue; 6792 } 6793 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6794 } 6795 } else { 6796 for (k = 0; k < dof; ++k) { 6797 if ((cind < cdof) && (k == cdofs[cind])) { 6798 ++cind; 6799 continue; 6800 } 6801 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6802 } 6803 } 6804 } else { 6805 if (perm) { 6806 for (k = 0; k < dof; ++k) { 6807 if ((cind < cdof) && (k == cdofs[cind])) { 6808 ++cind; 6809 continue; 6810 } 6811 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6812 } 6813 } else { 6814 for (k = 0; k < dof; ++k) { 6815 if ((cind < cdof) && (k == cdofs[cind])) { 6816 ++cind; 6817 continue; 6818 } 6819 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6820 } 6821 } 6822 } 6823 } 6824 PetscFunctionReturn(PETSC_SUCCESS); 6825 } 6826 6827 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[]) 6828 { 6829 PetscInt cdof; /* The number of constraints on this point */ 6830 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6831 PetscScalar *a; 6832 PetscInt off, cind = 0, k; 6833 6834 PetscFunctionBegin; 6835 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6836 PetscCall(PetscSectionGetOffset(section, point, &off)); 6837 a = &array[off]; 6838 if (cdof) { 6839 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6840 if (clperm) { 6841 if (perm) { 6842 for (k = 0; k < dof; ++k) { 6843 if ((cind < cdof) && (k == cdofs[cind])) { 6844 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6845 cind++; 6846 } 6847 } 6848 } else { 6849 for (k = 0; k < dof; ++k) { 6850 if ((cind < cdof) && (k == cdofs[cind])) { 6851 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6852 cind++; 6853 } 6854 } 6855 } 6856 } else { 6857 if (perm) { 6858 for (k = 0; k < dof; ++k) { 6859 if ((cind < cdof) && (k == cdofs[cind])) { 6860 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6861 cind++; 6862 } 6863 } 6864 } else { 6865 for (k = 0; k < dof; ++k) { 6866 if ((cind < cdof) && (k == cdofs[cind])) { 6867 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6868 cind++; 6869 } 6870 } 6871 } 6872 } 6873 } 6874 PetscFunctionReturn(PETSC_SUCCESS); 6875 } 6876 6877 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[]) 6878 { 6879 PetscScalar *a; 6880 PetscInt fdof, foff, fcdof, foffset = *offset; 6881 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6882 PetscInt cind = 0, b; 6883 6884 PetscFunctionBegin; 6885 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6886 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6887 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6888 a = &array[foff]; 6889 if (!fcdof || setBC) { 6890 if (clperm) { 6891 if (perm) { 6892 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6893 } else { 6894 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6895 } 6896 } else { 6897 if (perm) { 6898 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6899 } else { 6900 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6901 } 6902 } 6903 } else { 6904 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6905 if (clperm) { 6906 if (perm) { 6907 for (b = 0; b < fdof; b++) { 6908 if ((cind < fcdof) && (b == fcdofs[cind])) { 6909 ++cind; 6910 continue; 6911 } 6912 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6913 } 6914 } else { 6915 for (b = 0; b < fdof; b++) { 6916 if ((cind < fcdof) && (b == fcdofs[cind])) { 6917 ++cind; 6918 continue; 6919 } 6920 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6921 } 6922 } 6923 } else { 6924 if (perm) { 6925 for (b = 0; b < fdof; b++) { 6926 if ((cind < fcdof) && (b == fcdofs[cind])) { 6927 ++cind; 6928 continue; 6929 } 6930 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6931 } 6932 } else { 6933 for (b = 0; b < fdof; b++) { 6934 if ((cind < fcdof) && (b == fcdofs[cind])) { 6935 ++cind; 6936 continue; 6937 } 6938 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6939 } 6940 } 6941 } 6942 } 6943 *offset += fdof; 6944 PetscFunctionReturn(PETSC_SUCCESS); 6945 } 6946 6947 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[]) 6948 { 6949 PetscScalar *a; 6950 PetscInt fdof, foff, fcdof, foffset = *offset; 6951 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6952 PetscInt Nc, cind = 0, ncind = 0, b; 6953 PetscBool ncSet, fcSet; 6954 6955 PetscFunctionBegin; 6956 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6957 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6958 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6959 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6960 a = &array[foff]; 6961 if (fcdof) { 6962 /* We just override fcdof and fcdofs with Ncc and comps */ 6963 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6964 if (clperm) { 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[clperm[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[clperm[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[clperm[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[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 7005 ++cind; 7006 } 7007 } 7008 } 7009 } 7010 } else { 7011 if (perm) { 7012 if (comps) { 7013 for (b = 0; b < fdof; b++) { 7014 ncSet = fcSet = PETSC_FALSE; 7015 if (b % Nc == comps[ncind]) { 7016 ncind = (ncind + 1) % Ncc; 7017 ncSet = PETSC_TRUE; 7018 } 7019 if ((cind < fcdof) && (b == fcdofs[cind])) { 7020 ++cind; 7021 fcSet = PETSC_TRUE; 7022 } 7023 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7024 } 7025 } else { 7026 for (b = 0; b < fdof; b++) { 7027 if ((cind < fcdof) && (b == fcdofs[cind])) { 7028 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 7029 ++cind; 7030 } 7031 } 7032 } 7033 } else { 7034 if (comps) { 7035 for (b = 0; b < fdof; b++) { 7036 ncSet = fcSet = PETSC_FALSE; 7037 if (b % Nc == comps[ncind]) { 7038 ncind = (ncind + 1) % Ncc; 7039 ncSet = PETSC_TRUE; 7040 } 7041 if ((cind < fcdof) && (b == fcdofs[cind])) { 7042 ++cind; 7043 fcSet = PETSC_TRUE; 7044 } 7045 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7046 } 7047 } else { 7048 for (b = 0; b < fdof; b++) { 7049 if ((cind < fcdof) && (b == fcdofs[cind])) { 7050 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 7051 ++cind; 7052 } 7053 } 7054 } 7055 } 7056 } 7057 } 7058 *offset += fdof; 7059 PetscFunctionReturn(PETSC_SUCCESS); 7060 } 7061 7062 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7063 { 7064 PetscScalar *array; 7065 const PetscInt *cone, *coneO; 7066 PetscInt pStart, pEnd, p, numPoints, off, dof; 7067 7068 PetscFunctionBeginHot; 7069 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 7070 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 7071 PetscCall(DMPlexGetCone(dm, point, &cone)); 7072 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 7073 PetscCall(VecGetArray(v, &array)); 7074 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 7075 const PetscInt cp = !p ? point : cone[p - 1]; 7076 const PetscInt o = !p ? 0 : coneO[p - 1]; 7077 7078 if ((cp < pStart) || (cp >= pEnd)) { 7079 dof = 0; 7080 continue; 7081 } 7082 PetscCall(PetscSectionGetDof(section, cp, &dof)); 7083 /* ADD_VALUES */ 7084 { 7085 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7086 PetscScalar *a; 7087 PetscInt cdof, coff, cind = 0, k; 7088 7089 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 7090 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 7091 a = &array[coff]; 7092 if (!cdof) { 7093 if (o >= 0) { 7094 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 7095 } else { 7096 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 7097 } 7098 } else { 7099 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 7100 if (o >= 0) { 7101 for (k = 0; k < dof; ++k) { 7102 if ((cind < cdof) && (k == cdofs[cind])) { 7103 ++cind; 7104 continue; 7105 } 7106 a[k] += values[off + k]; 7107 } 7108 } else { 7109 for (k = 0; k < dof; ++k) { 7110 if ((cind < cdof) && (k == cdofs[cind])) { 7111 ++cind; 7112 continue; 7113 } 7114 a[k] += values[off + dof - k - 1]; 7115 } 7116 } 7117 } 7118 } 7119 } 7120 PetscCall(VecRestoreArray(v, &array)); 7121 PetscFunctionReturn(PETSC_SUCCESS); 7122 } 7123 7124 /*@C 7125 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 7126 7127 Not collective 7128 7129 Input Parameters: 7130 + dm - The `DM` 7131 . section - The section describing the layout in `v`, or `NULL` to use the default section 7132 . v - The local vector 7133 . point - The point in the `DM` 7134 . values - The array of values 7135 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 7136 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 7137 7138 Level: intermediate 7139 7140 Note: 7141 Usually the input arrays were obtained with `DMPlexVecGetClosure()` 7142 7143 Fortran Note: 7144 `values` must be declared with 7145 .vb 7146 PetscScalar,dimension(:),pointer :: values 7147 .ve 7148 7149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 7150 @*/ 7151 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 7152 { 7153 PetscSection clSection; 7154 IS clPoints; 7155 PetscScalar *array; 7156 PetscInt *points = NULL; 7157 const PetscInt *clp, *clperm = NULL; 7158 PetscInt depth, numFields, numPoints, p, clsize; 7159 7160 PetscFunctionBeginHot; 7161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7162 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7163 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7164 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7165 PetscCall(DMPlexGetDepth(dm, &depth)); 7166 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7167 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 7168 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 7169 PetscFunctionReturn(PETSC_SUCCESS); 7170 } 7171 /* Get points */ 7172 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7173 for (clsize = 0, p = 0; p < numPoints; p++) { 7174 PetscInt dof; 7175 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7176 clsize += dof; 7177 } 7178 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7179 /* Get array */ 7180 PetscCall(VecGetArray(v, &array)); 7181 /* Get values */ 7182 if (numFields > 0) { 7183 PetscInt offset = 0, f; 7184 for (f = 0; f < numFields; ++f) { 7185 const PetscInt **perms = NULL; 7186 const PetscScalar **flips = NULL; 7187 7188 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7189 switch (mode) { 7190 case INSERT_VALUES: 7191 for (p = 0; p < numPoints; p++) { 7192 const PetscInt point = points[2 * p]; 7193 const PetscInt *perm = perms ? perms[p] : NULL; 7194 const PetscScalar *flip = flips ? flips[p] : NULL; 7195 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 7196 } 7197 break; 7198 case INSERT_ALL_VALUES: 7199 for (p = 0; p < numPoints; p++) { 7200 const PetscInt point = points[2 * p]; 7201 const PetscInt *perm = perms ? perms[p] : NULL; 7202 const PetscScalar *flip = flips ? flips[p] : NULL; 7203 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 7204 } 7205 break; 7206 case INSERT_BC_VALUES: 7207 for (p = 0; p < numPoints; p++) { 7208 const PetscInt point = points[2 * p]; 7209 const PetscInt *perm = perms ? perms[p] : NULL; 7210 const PetscScalar *flip = flips ? flips[p] : NULL; 7211 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7212 } 7213 break; 7214 case ADD_VALUES: 7215 for (p = 0; p < numPoints; p++) { 7216 const PetscInt point = points[2 * p]; 7217 const PetscInt *perm = perms ? perms[p] : NULL; 7218 const PetscScalar *flip = flips ? flips[p] : NULL; 7219 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7220 } 7221 break; 7222 case ADD_ALL_VALUES: 7223 for (p = 0; p < numPoints; p++) { 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(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7228 } 7229 break; 7230 case ADD_BC_VALUES: 7231 for (p = 0; p < numPoints; p++) { 7232 const PetscInt point = points[2 * p]; 7233 const PetscInt *perm = perms ? perms[p] : NULL; 7234 const PetscScalar *flip = flips ? flips[p] : NULL; 7235 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7236 } 7237 break; 7238 default: 7239 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7240 } 7241 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7242 } 7243 } else { 7244 PetscInt dof, off; 7245 const PetscInt **perms = NULL; 7246 const PetscScalar **flips = NULL; 7247 7248 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7249 switch (mode) { 7250 case INSERT_VALUES: 7251 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7252 const PetscInt point = points[2 * p]; 7253 const PetscInt *perm = perms ? perms[p] : NULL; 7254 const PetscScalar *flip = flips ? flips[p] : NULL; 7255 PetscCall(PetscSectionGetDof(section, point, &dof)); 7256 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7257 } 7258 break; 7259 case INSERT_ALL_VALUES: 7260 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7261 const PetscInt point = points[2 * p]; 7262 const PetscInt *perm = perms ? perms[p] : NULL; 7263 const PetscScalar *flip = flips ? flips[p] : NULL; 7264 PetscCall(PetscSectionGetDof(section, point, &dof)); 7265 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7266 } 7267 break; 7268 case INSERT_BC_VALUES: 7269 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7270 const PetscInt point = points[2 * p]; 7271 const PetscInt *perm = perms ? perms[p] : NULL; 7272 const PetscScalar *flip = flips ? flips[p] : NULL; 7273 PetscCall(PetscSectionGetDof(section, point, &dof)); 7274 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7275 } 7276 break; 7277 case ADD_VALUES: 7278 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7279 const PetscInt point = points[2 * p]; 7280 const PetscInt *perm = perms ? perms[p] : NULL; 7281 const PetscScalar *flip = flips ? flips[p] : NULL; 7282 PetscCall(PetscSectionGetDof(section, point, &dof)); 7283 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7284 } 7285 break; 7286 case ADD_ALL_VALUES: 7287 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7288 const PetscInt point = points[2 * p]; 7289 const PetscInt *perm = perms ? perms[p] : NULL; 7290 const PetscScalar *flip = flips ? flips[p] : NULL; 7291 PetscCall(PetscSectionGetDof(section, point, &dof)); 7292 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7293 } 7294 break; 7295 case ADD_BC_VALUES: 7296 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7297 const PetscInt point = points[2 * p]; 7298 const PetscInt *perm = perms ? perms[p] : NULL; 7299 const PetscScalar *flip = flips ? flips[p] : NULL; 7300 PetscCall(PetscSectionGetDof(section, point, &dof)); 7301 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7302 } 7303 break; 7304 default: 7305 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7306 } 7307 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7308 } 7309 /* Cleanup points */ 7310 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7311 /* Cleanup array */ 7312 PetscCall(VecRestoreArray(v, &array)); 7313 PetscFunctionReturn(PETSC_SUCCESS); 7314 } 7315 7316 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7317 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7318 { 7319 PetscFunctionBegin; 7320 *contains = PETSC_TRUE; 7321 if (label) { 7322 PetscInt fdof; 7323 7324 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7325 if (!*contains) { 7326 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7327 *offset += fdof; 7328 PetscFunctionReturn(PETSC_SUCCESS); 7329 } 7330 } 7331 PetscFunctionReturn(PETSC_SUCCESS); 7332 } 7333 7334 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7335 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) 7336 { 7337 PetscSection clSection; 7338 IS clPoints; 7339 PetscScalar *array; 7340 PetscInt *points = NULL; 7341 const PetscInt *clp; 7342 PetscInt numFields, numPoints, p; 7343 PetscInt offset = 0, f; 7344 7345 PetscFunctionBeginHot; 7346 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7347 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7348 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7349 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7350 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7351 /* Get points */ 7352 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7353 /* Get array */ 7354 PetscCall(VecGetArray(v, &array)); 7355 /* Get values */ 7356 for (f = 0; f < numFields; ++f) { 7357 const PetscInt **perms = NULL; 7358 const PetscScalar **flips = NULL; 7359 PetscBool contains; 7360 7361 if (!fieldActive[f]) { 7362 for (p = 0; p < numPoints * 2; p += 2) { 7363 PetscInt fdof; 7364 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7365 offset += fdof; 7366 } 7367 continue; 7368 } 7369 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7370 switch (mode) { 7371 case INSERT_VALUES: 7372 for (p = 0; p < numPoints; p++) { 7373 const PetscInt point = points[2 * p]; 7374 const PetscInt *perm = perms ? perms[p] : NULL; 7375 const PetscScalar *flip = flips ? flips[p] : NULL; 7376 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7377 if (!contains) continue; 7378 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7379 } 7380 break; 7381 case INSERT_ALL_VALUES: 7382 for (p = 0; p < numPoints; p++) { 7383 const PetscInt point = points[2 * p]; 7384 const PetscInt *perm = perms ? perms[p] : NULL; 7385 const PetscScalar *flip = flips ? flips[p] : NULL; 7386 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7387 if (!contains) continue; 7388 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7389 } 7390 break; 7391 case INSERT_BC_VALUES: 7392 for (p = 0; p < numPoints; p++) { 7393 const PetscInt point = points[2 * p]; 7394 const PetscInt *perm = perms ? perms[p] : NULL; 7395 const PetscScalar *flip = flips ? flips[p] : NULL; 7396 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7397 if (!contains) continue; 7398 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7399 } 7400 break; 7401 case ADD_VALUES: 7402 for (p = 0; p < numPoints; p++) { 7403 const PetscInt point = points[2 * p]; 7404 const PetscInt *perm = perms ? perms[p] : NULL; 7405 const PetscScalar *flip = flips ? flips[p] : NULL; 7406 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7407 if (!contains) continue; 7408 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7409 } 7410 break; 7411 case ADD_ALL_VALUES: 7412 for (p = 0; p < numPoints; p++) { 7413 const PetscInt point = points[2 * p]; 7414 const PetscInt *perm = perms ? perms[p] : NULL; 7415 const PetscScalar *flip = flips ? flips[p] : NULL; 7416 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7417 if (!contains) continue; 7418 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7419 } 7420 break; 7421 default: 7422 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7423 } 7424 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7425 } 7426 /* Cleanup points */ 7427 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7428 /* Cleanup array */ 7429 PetscCall(VecRestoreArray(v, &array)); 7430 PetscFunctionReturn(PETSC_SUCCESS); 7431 } 7432 7433 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7434 { 7435 PetscMPIInt rank; 7436 PetscInt i, j; 7437 7438 PetscFunctionBegin; 7439 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7440 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7441 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7442 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7443 numCIndices = numCIndices ? numCIndices : numRIndices; 7444 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7445 for (i = 0; i < numRIndices; i++) { 7446 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7447 for (j = 0; j < numCIndices; j++) { 7448 #if defined(PETSC_USE_COMPLEX) 7449 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7450 #else 7451 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7452 #endif 7453 } 7454 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7455 } 7456 PetscFunctionReturn(PETSC_SUCCESS); 7457 } 7458 7459 /* 7460 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7461 7462 Input Parameters: 7463 + section - The section for this data layout 7464 . islocal - Is the section (and thus indices being requested) local or global? 7465 . point - The point contributing dofs with these indices 7466 . off - The global offset of this point 7467 . loff - The local offset of each field 7468 . setBC - The flag determining whether to include indices of boundary values 7469 . perm - A permutation of the dofs on this point, or NULL 7470 - indperm - A permutation of the entire indices array, or NULL 7471 7472 Output Parameter: 7473 . indices - Indices for dofs on this point 7474 7475 Level: developer 7476 7477 Note: The indices could be local or global, depending on the value of 'off'. 7478 */ 7479 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7480 { 7481 PetscInt dof; /* The number of unknowns on this point */ 7482 PetscInt cdof; /* The number of constraints on this point */ 7483 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7484 PetscInt cind = 0, k; 7485 7486 PetscFunctionBegin; 7487 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7488 PetscCall(PetscSectionGetDof(section, point, &dof)); 7489 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7490 if (!cdof || setBC) { 7491 for (k = 0; k < dof; ++k) { 7492 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7493 const PetscInt ind = indperm ? indperm[preind] : preind; 7494 7495 indices[ind] = off + k; 7496 } 7497 } else { 7498 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7499 for (k = 0; k < dof; ++k) { 7500 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7501 const PetscInt ind = indperm ? indperm[preind] : preind; 7502 7503 if ((cind < cdof) && (k == cdofs[cind])) { 7504 /* Insert check for returning constrained indices */ 7505 indices[ind] = -(off + k + 1); 7506 ++cind; 7507 } else { 7508 indices[ind] = off + k - (islocal ? 0 : cind); 7509 } 7510 } 7511 } 7512 *loff += dof; 7513 PetscFunctionReturn(PETSC_SUCCESS); 7514 } 7515 7516 /* 7517 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7518 7519 Input Parameters: 7520 + section - a section (global or local) 7521 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7522 . point - point within section 7523 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7524 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7525 . setBC - identify constrained (boundary condition) points via involution. 7526 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7527 . permsoff - offset 7528 - indperm - index permutation 7529 7530 Output Parameter: 7531 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7532 . indices - array to hold indices (as defined by section) of each dof associated with point 7533 7534 Notes: 7535 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7536 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7537 in the local vector. 7538 7539 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7540 significant). It is invalid to call with a global section and setBC=true. 7541 7542 Developer Note: 7543 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7544 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7545 offset could be obtained from the section instead of passing it explicitly as we do now. 7546 7547 Example: 7548 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7549 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7550 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7551 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. 7552 7553 Level: developer 7554 */ 7555 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[]) 7556 { 7557 PetscInt numFields, foff, f; 7558 7559 PetscFunctionBegin; 7560 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7561 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7562 for (f = 0, foff = 0; f < numFields; ++f) { 7563 PetscInt fdof, cfdof; 7564 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7565 PetscInt cind = 0, b; 7566 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7567 7568 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7569 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7570 if (!cfdof || setBC) { 7571 for (b = 0; b < fdof; ++b) { 7572 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7573 const PetscInt ind = indperm ? indperm[preind] : preind; 7574 7575 indices[ind] = off + foff + b; 7576 } 7577 } else { 7578 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7579 for (b = 0; b < fdof; ++b) { 7580 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7581 const PetscInt ind = indperm ? indperm[preind] : preind; 7582 7583 if ((cind < cfdof) && (b == fcdofs[cind])) { 7584 indices[ind] = -(off + foff + b + 1); 7585 ++cind; 7586 } else { 7587 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7588 } 7589 } 7590 } 7591 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7592 foffs[f] += fdof; 7593 } 7594 PetscFunctionReturn(PETSC_SUCCESS); 7595 } 7596 7597 /* 7598 This version believes the globalSection offsets for each field, rather than just the point offset 7599 7600 . foffs - The offset into 'indices' for each field, since it is segregated by field 7601 7602 Notes: 7603 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7604 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7605 */ 7606 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7607 { 7608 PetscInt numFields, foff, f; 7609 7610 PetscFunctionBegin; 7611 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7612 for (f = 0; f < numFields; ++f) { 7613 PetscInt fdof, cfdof; 7614 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7615 PetscInt cind = 0, b; 7616 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7617 7618 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7619 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7620 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7621 if (!cfdof) { 7622 for (b = 0; b < fdof; ++b) { 7623 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7624 const PetscInt ind = indperm ? indperm[preind] : preind; 7625 7626 indices[ind] = foff + b; 7627 } 7628 } else { 7629 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7630 for (b = 0; b < fdof; ++b) { 7631 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7632 const PetscInt ind = indperm ? indperm[preind] : preind; 7633 7634 if ((cind < cfdof) && (b == fcdofs[cind])) { 7635 indices[ind] = -(foff + b + 1); 7636 ++cind; 7637 } else { 7638 indices[ind] = foff + b - cind; 7639 } 7640 } 7641 } 7642 foffs[f] += fdof; 7643 } 7644 PetscFunctionReturn(PETSC_SUCCESS); 7645 } 7646 7647 static PetscErrorCode DMPlexAnchorsGetSubMatIndices(PetscInt nPoints, const PetscInt pnts[], PetscSection section, PetscSection cSec, PetscInt tmpIndices[], PetscInt fieldOffsets[], PetscInt indices[], const PetscInt ***perms) 7648 { 7649 PetscInt numFields, sStart, sEnd, cStart, cEnd; 7650 7651 PetscFunctionBegin; 7652 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7653 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7654 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7655 for (PetscInt p = 0; p < nPoints; p++) { 7656 PetscInt b = pnts[2 * p]; 7657 PetscInt bSecDof = 0, bOff; 7658 PetscInt cSecDof = 0; 7659 PetscSection indices_section; 7660 7661 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7662 if (!bSecDof) continue; 7663 if (b >= cStart && b < cEnd) PetscCall(PetscSectionGetDof(cSec, b, &cSecDof)); 7664 indices_section = cSecDof > 0 ? cSec : section; 7665 if (numFields) { 7666 PetscInt fStart[32], fEnd[32]; 7667 7668 fStart[0] = 0; 7669 fEnd[0] = 0; 7670 for (PetscInt f = 0; f < numFields; f++) { 7671 PetscInt fDof = 0; 7672 7673 PetscCall(PetscSectionGetFieldDof(indices_section, b, f, &fDof)); 7674 fStart[f + 1] = fStart[f] + fDof; 7675 fEnd[f + 1] = fStart[f + 1]; 7676 } 7677 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7678 // only apply permutations on one side 7679 PetscCall(DMPlexGetIndicesPointFields_Internal(indices_section, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, perms ? p : -1, NULL, tmpIndices)); 7680 for (PetscInt f = 0; f < numFields; f++) { 7681 for (PetscInt i = fStart[f]; i < fEnd[f]; i++) { indices[fieldOffsets[f]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); } 7682 } 7683 } else { 7684 PetscInt bEnd = 0; 7685 7686 PetscCall(PetscSectionGetOffset(indices_section, b, &bOff)); 7687 PetscCall(DMPlexGetIndicesPoint_Internal(indices_section, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, tmpIndices)); 7688 7689 for (PetscInt i = 0; i < bEnd; i++) indices[fieldOffsets[0]++] = (cSecDof > 0) ? tmpIndices[i] : -(tmpIndices[i] + 1); 7690 } 7691 } 7692 PetscFunctionReturn(PETSC_SUCCESS); 7693 } 7694 7695 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[]) 7696 { 7697 Mat cMat; 7698 PetscSection aSec, cSec; 7699 IS aIS; 7700 PetscInt aStart = -1, aEnd = -1; 7701 PetscInt sStart = -1, sEnd = -1; 7702 PetscInt cStart = -1, cEnd = -1; 7703 const PetscInt *anchors; 7704 PetscInt numFields, p; 7705 PetscInt newNumPoints = 0, newNumIndices = 0; 7706 PetscInt *newPoints, *indices, *newIndices, *tmpIndices, *tmpNewIndices; 7707 PetscInt oldOffsets[32]; 7708 PetscInt newOffsets[32]; 7709 PetscInt oldOffsetsCopy[32]; 7710 PetscInt newOffsetsCopy[32]; 7711 PetscScalar *modMat = NULL; 7712 PetscBool anyConstrained = PETSC_FALSE; 7713 7714 PetscFunctionBegin; 7715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7716 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7717 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7718 7719 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7720 /* if there are point-to-point constraints */ 7721 if (aSec) { 7722 PetscCall(PetscArrayzero(newOffsets, 32)); 7723 PetscCall(PetscArrayzero(oldOffsets, 32)); 7724 PetscCall(ISGetIndices(aIS, &anchors)); 7725 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7726 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 7727 /* figure out how many points are going to be in the new element matrix 7728 * (we allow double counting, because it's all just going to be summed 7729 * into the global matrix anyway) */ 7730 for (p = 0; p < 2 * numPoints; p += 2) { 7731 PetscInt b = points[p]; 7732 PetscInt bDof = 0, bSecDof = 0; 7733 7734 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7735 if (!bSecDof) continue; 7736 7737 for (PetscInt f = 0; f < numFields; f++) { 7738 PetscInt fDof = 0; 7739 7740 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7741 oldOffsets[f + 1] += fDof; 7742 } 7743 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7744 if (bDof) { 7745 /* this point is constrained */ 7746 /* it is going to be replaced by its anchors */ 7747 PetscInt bOff, q; 7748 7749 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7750 for (q = 0; q < bDof; q++) { 7751 PetscInt a = anchors[bOff + q]; 7752 PetscInt aDof = 0; 7753 7754 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7755 if (aDof) { 7756 anyConstrained = PETSC_TRUE; 7757 newNumPoints += 1; 7758 } 7759 newNumIndices += aDof; 7760 for (PetscInt f = 0; f < numFields; ++f) { 7761 PetscInt fDof = 0; 7762 7763 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7764 newOffsets[f + 1] += fDof; 7765 } 7766 } 7767 } else { 7768 /* this point is not constrained */ 7769 newNumPoints++; 7770 newNumIndices += bSecDof; 7771 for (PetscInt f = 0; f < numFields; ++f) { 7772 PetscInt fDof; 7773 7774 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7775 newOffsets[f + 1] += fDof; 7776 } 7777 } 7778 } 7779 } 7780 if (!anyConstrained) { 7781 if (outNumPoints) *outNumPoints = 0; 7782 if (outNumIndices) *outNumIndices = 0; 7783 if (outPoints) *outPoints = NULL; 7784 if (outMat) *outMat = NULL; 7785 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7786 PetscFunctionReturn(PETSC_SUCCESS); 7787 } 7788 7789 if (outNumPoints) *outNumPoints = newNumPoints; 7790 if (outNumIndices) *outNumIndices = newNumIndices; 7791 7792 for (PetscInt f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7793 for (PetscInt f = 0; f < numFields; ++f) oldOffsets[f + 1] += oldOffsets[f]; 7794 7795 if (!outPoints && !outMat) { 7796 if (offsets) { 7797 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7798 } 7799 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7800 PetscFunctionReturn(PETSC_SUCCESS); 7801 } 7802 7803 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7804 PetscCheck(!numFields || oldOffsets[numFields] == numIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, oldOffsets[numFields], numIndices); 7805 7806 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7807 PetscCall(PetscSectionGetChart(cSec, &cStart, &cEnd)); 7808 7809 /* output arrays */ 7810 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7811 PetscCall(PetscArrayzero(newPoints, 2 * newNumPoints)); 7812 7813 // get the new Points 7814 for (PetscInt p = 0, newP = 0; p < numPoints; p++) { 7815 PetscInt b = points[2 * p]; 7816 PetscInt bDof = 0, bSecDof = 0, bOff; 7817 7818 if (b >= sStart && b < sEnd) PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7819 if (!bSecDof) continue; 7820 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7821 if (bDof) { 7822 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7823 for (PetscInt q = 0; q < bDof; q++) { 7824 PetscInt a = anchors[bOff + q], aDof = 0; 7825 7826 if (a >= sStart && a < sEnd) PetscCall(PetscSectionGetDof(section, a, &aDof)); 7827 if (aDof) { 7828 newPoints[2 * newP] = a; 7829 newPoints[2 * newP + 1] = 0; // orientations are accounted for in constructing the matrix, newly added points are in default orientation 7830 newP++; 7831 } 7832 } 7833 } else { 7834 newPoints[2 * newP] = b; 7835 newPoints[2 * newP + 1] = points[2 * p + 1]; 7836 newP++; 7837 } 7838 } 7839 7840 if (outMat) { 7841 PetscScalar *tmpMat; 7842 PetscCall(PetscArraycpy(oldOffsetsCopy, oldOffsets, 32)); 7843 PetscCall(PetscArraycpy(newOffsetsCopy, newOffsets, 32)); 7844 7845 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &indices)); 7846 PetscCall(DMGetWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7847 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7848 PetscCall(DMGetWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7849 7850 for (PetscInt i = 0; i < numIndices; i++) indices[i] = -1; 7851 for (PetscInt i = 0; i < newNumIndices; i++) newIndices[i] = -1; 7852 7853 PetscCall(DMPlexAnchorsGetSubMatIndices(numPoints, points, section, cSec, tmpIndices, oldOffsetsCopy, indices, perms)); 7854 PetscCall(DMPlexAnchorsGetSubMatIndices(newNumPoints, newPoints, section, section, tmpNewIndices, newOffsetsCopy, newIndices, NULL)); 7855 7856 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7857 PetscCall(DMGetWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7858 PetscCall(PetscArrayzero(modMat, newNumIndices * numIndices)); 7859 // for each field, insert the anchor modification into modMat 7860 for (PetscInt f = 0; f < PetscMax(1, numFields); f++) { 7861 PetscInt fStart = oldOffsets[f]; 7862 PetscInt fNewStart = newOffsets[f]; 7863 for (PetscInt p = 0, newP = 0, o = fStart, oNew = fNewStart; p < numPoints; p++) { 7864 PetscInt b = points[2 * p]; 7865 PetscInt bDof = 0, bSecDof = 0, bOff; 7866 7867 if (b >= sStart && b < sEnd) { 7868 if (numFields) { 7869 PetscCall(PetscSectionGetFieldDof(section, b, f, &bSecDof)); 7870 } else { 7871 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7872 } 7873 } 7874 if (!bSecDof) continue; 7875 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7876 if (bDof) { 7877 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7878 for (PetscInt q = 0; q < bDof; q++, newP++) { 7879 PetscInt a = anchors[bOff + q], aDof = 0; 7880 7881 if (a >= sStart && a < sEnd) { 7882 if (numFields) { 7883 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 7884 } else { 7885 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7886 } 7887 } 7888 if (aDof) { 7889 PetscCall(MatGetValues(cMat, bSecDof, &indices[o], aDof, &newIndices[oNew], tmpMat)); 7890 for (PetscInt d = 0; d < bSecDof; d++) { 7891 for (PetscInt e = 0; e < aDof; e++) modMat[(o + d) * newNumIndices + oNew + e] = tmpMat[d * aDof + e]; 7892 } 7893 } 7894 oNew += aDof; 7895 } 7896 } else { 7897 // Insert the identity matrix in this block 7898 for (PetscInt d = 0; d < bSecDof; d++) modMat[(o + d) * newNumIndices + oNew + d] = 1; 7899 oNew += bSecDof; 7900 newP++; 7901 } 7902 o += bSecDof; 7903 } 7904 } 7905 7906 *outMat = modMat; 7907 7908 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &tmpMat)); 7909 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &tmpNewIndices)); 7910 PetscCall(DMRestoreWorkArray(dm, newNumIndices, MPIU_INT, &newIndices)); 7911 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &tmpIndices)); 7912 PetscCall(DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices)); 7913 } 7914 PetscCall(ISRestoreIndices(aIS, &anchors)); 7915 7916 /* output */ 7917 if (outPoints) { 7918 *outPoints = newPoints; 7919 } else { 7920 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7921 } 7922 for (PetscInt f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7923 PetscFunctionReturn(PETSC_SUCCESS); 7924 } 7925 7926 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) 7927 { 7928 PetscScalar *modMat = NULL; 7929 PetscInt newNumIndices = -1; 7930 7931 PetscFunctionBegin; 7932 /* 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. 7933 modMat is that matrix C */ 7934 PetscCall(DMPlexAnchorsGetSubMatModification(dm, section, numPoints, numIndices, points, perms, outNumPoints, &newNumIndices, outPoints, offsets, outValues ? &modMat : NULL)); 7935 if (outNumIndices) *outNumIndices = newNumIndices; 7936 if (modMat) { 7937 const PetscScalar *newValues = values; 7938 7939 if (multiplyRight) { 7940 PetscScalar *newNewValues = NULL; 7941 PetscBLASInt M, N, K; 7942 PetscScalar a = 1.0, b = 0.0; 7943 7944 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); 7945 7946 PetscCall(PetscBLASIntCast(newNumIndices, &M)); 7947 PetscCall(PetscBLASIntCast(numRows, &N)); 7948 PetscCall(PetscBLASIntCast(numIndices, &K)); 7949 PetscCall(DMGetWorkArray(dm, numRows * newNumIndices, MPIU_SCALAR, &newNewValues)); 7950 // row-major to column-major conversion, right multiplication becomes left multiplication 7951 PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &M, &N, &K, &a, modMat, &M, newValues, &K, &b, newNewValues, &M)); 7952 numCols = newNumIndices; 7953 newValues = newNewValues; 7954 } 7955 7956 if (multiplyLeft) { 7957 PetscScalar *newNewValues = NULL; 7958 PetscBLASInt M, N, K; 7959 PetscScalar a = 1.0, b = 0.0; 7960 7961 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); 7962 7963 PetscCall(PetscBLASIntCast(numCols, &M)); 7964 PetscCall(PetscBLASIntCast(newNumIndices, &N)); 7965 PetscCall(PetscBLASIntCast(numIndices, &K)); 7966 PetscCall(DMGetWorkArray(dm, newNumIndices * numCols, MPIU_SCALAR, &newNewValues)); 7967 // row-major to column-major conversion, left multiplication becomes right multiplication 7968 PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &M, &N, &K, &a, newValues, &M, modMat, &N, &b, newNewValues, &M)); 7969 if (newValues != values) PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7970 newValues = newNewValues; 7971 } 7972 *outValues = (PetscScalar *)newValues; 7973 PetscCall(DMRestoreWorkArray(dm, numIndices * newNumIndices, MPIU_SCALAR, &modMat)); 7974 } 7975 PetscFunctionReturn(PETSC_SUCCESS); 7976 } 7977 7978 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) 7979 { 7980 PetscFunctionBegin; 7981 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, numPoints, numIndices, points, perms, numIndices, numIndices, values, outNumPoints, outNumIndices, outPoints, outValues, offsets, PETSC_TRUE, multiplyLeft)); 7982 PetscFunctionReturn(PETSC_SUCCESS); 7983 } 7984 7985 static PetscErrorCode DMPlexGetClosureIndicesSize_Internal(DM dm, PetscSection section, PetscInt point, PetscInt *closureSize) 7986 { 7987 /* Closure ordering */ 7988 PetscSection clSection; 7989 IS clPoints; 7990 const PetscInt *clp; 7991 PetscInt *points; 7992 PetscInt Ncl, Ni = 0; 7993 7994 PetscFunctionBeginHot; 7995 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7996 for (PetscInt p = 0; p < Ncl * 2; p += 2) { 7997 PetscInt dof; 7998 7999 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8000 Ni += dof; 8001 } 8002 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8003 *closureSize = Ni; 8004 PetscFunctionReturn(PETSC_SUCCESS); 8005 } 8006 8007 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) 8008 { 8009 /* Closure ordering */ 8010 PetscSection clSection; 8011 IS clPoints; 8012 const PetscInt *clp; 8013 PetscInt *points; 8014 const PetscInt *clperm = NULL; 8015 /* Dof permutation and sign flips */ 8016 const PetscInt **perms[32] = {NULL}; 8017 const PetscScalar **flips[32] = {NULL}; 8018 PetscScalar *valCopy = NULL; 8019 /* Hanging node constraints */ 8020 PetscInt *pointsC = NULL; 8021 PetscScalar *valuesC = NULL; 8022 PetscInt NclC, NiC; 8023 8024 PetscInt *idx; 8025 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 8026 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 8027 PetscInt idxStart, idxEnd; 8028 PetscInt nRows, nCols; 8029 8030 PetscFunctionBeginHot; 8031 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8032 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8033 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 8034 PetscAssertPointer(numRows, 6); 8035 PetscAssertPointer(numCols, 7); 8036 if (indices) PetscAssertPointer(indices, 8); 8037 if (outOffsets) PetscAssertPointer(outOffsets, 9); 8038 if (values) PetscAssertPointer(values, 10); 8039 PetscCall(PetscSectionGetNumFields(section, &Nf)); 8040 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 8041 PetscCall(PetscArrayzero(offsets, 32)); 8042 /* 1) Get points in closure */ 8043 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 8044 if (useClPerm) { 8045 PetscInt depth, clsize; 8046 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 8047 for (clsize = 0, p = 0; p < Ncl; p++) { 8048 PetscInt dof; 8049 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 8050 clsize += dof; 8051 } 8052 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 8053 } 8054 /* 2) Get number of indices on these points and field offsets from section */ 8055 for (p = 0; p < Ncl * 2; p += 2) { 8056 PetscInt dof, fdof; 8057 8058 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 8059 for (f = 0; f < Nf; ++f) { 8060 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 8061 offsets[f + 1] += fdof; 8062 } 8063 Ni += dof; 8064 } 8065 if (*numRows == -1) *numRows = Ni; 8066 if (*numCols == -1) *numCols = Ni; 8067 nRows = *numRows; 8068 nCols = *numCols; 8069 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 8070 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 8071 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 8072 if (multiplyRight) PetscCheck(nCols == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " columns, got %" PetscInt_FMT, Ni, nCols); 8073 if (multiplyLeft) PetscCheck(nRows == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Expected %" PetscInt_FMT " rows, got %" PetscInt_FMT, Ni, nRows); 8074 for (f = 0; f < PetscMax(1, Nf); ++f) { 8075 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8076 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 8077 /* may need to apply sign changes to the element matrix */ 8078 if (values && flips[f]) { 8079 PetscInt foffset = offsets[f]; 8080 8081 for (p = 0; p < Ncl; ++p) { 8082 PetscInt pnt = points[2 * p], fdof; 8083 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8084 8085 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8086 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8087 if (flip) { 8088 PetscInt i, j, k; 8089 8090 if (!valCopy) { 8091 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8092 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8093 *values = valCopy; 8094 } 8095 for (i = 0; i < fdof; ++i) { 8096 PetscScalar fval = flip[i]; 8097 8098 if (multiplyRight) { 8099 for (k = 0; k < nRows; ++k) { valCopy[Ni * k + (foffset + i)] *= fval; } 8100 } 8101 if (multiplyLeft) { 8102 for (k = 0; k < nCols; ++k) { valCopy[nCols * (foffset + i) + k] *= fval; } 8103 } 8104 } 8105 } 8106 foffset += fdof; 8107 } 8108 } 8109 } 8110 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8111 PetscCall(DMPlexAnchorsModifyMat_Internal(dm, section, Ncl, Ni, points, perms, nRows, nCols, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, multiplyRight, multiplyLeft)); 8112 if (NclC) { 8113 if (multiplyRight) *numCols = NiC; 8114 if (multiplyLeft) *numRows = NiC; 8115 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8116 for (f = 0; f < PetscMax(1, Nf); ++f) { 8117 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8118 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8119 } 8120 for (f = 0; f < PetscMax(1, Nf); ++f) { 8121 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8122 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8123 } 8124 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8125 Ncl = NclC; 8126 Ni = NiC; 8127 points = pointsC; 8128 if (values) *values = valuesC; 8129 } 8130 /* 5) Calculate indices */ 8131 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8132 PetscCall(PetscSectionGetChart(idxSection, &idxStart, &idxEnd)); 8133 if (Nf) { 8134 PetscInt idxOff; 8135 PetscBool useFieldOffsets; 8136 8137 if (outOffsets) { 8138 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8139 } 8140 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8141 if (useFieldOffsets) { 8142 for (p = 0; p < Ncl; ++p) { 8143 const PetscInt pnt = points[p * 2]; 8144 8145 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8146 } 8147 } else { 8148 for (p = 0; p < Ncl; ++p) { 8149 const PetscInt pnt = points[p * 2]; 8150 8151 if (pnt < idxStart || pnt >= idxEnd) continue; 8152 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8153 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8154 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8155 * global section. */ 8156 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8157 } 8158 } 8159 } else { 8160 PetscInt off = 0, idxOff; 8161 8162 for (p = 0; p < Ncl; ++p) { 8163 const PetscInt pnt = points[p * 2]; 8164 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8165 8166 if (pnt < idxStart || pnt >= idxEnd) continue; 8167 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8168 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8169 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8170 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8171 } 8172 } 8173 /* 6) Cleanup */ 8174 for (f = 0; f < PetscMax(1, Nf); ++f) { 8175 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8176 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8177 } 8178 if (NclC) { 8179 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8180 } else { 8181 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8182 } 8183 8184 if (indices) *indices = idx; 8185 PetscFunctionReturn(PETSC_SUCCESS); 8186 } 8187 8188 /*@C 8189 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 8190 8191 Not collective 8192 8193 Input Parameters: 8194 + dm - The `DM` 8195 . section - The `PetscSection` describing the points (a local section) 8196 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8197 . point - The point defining the closure 8198 - useClPerm - Use the closure point permutation if available 8199 8200 Output Parameters: 8201 + numIndices - The number of dof indices in the closure of point with the input sections 8202 . indices - The dof indices 8203 . outOffsets - Array to write the field offsets into, or `NULL` 8204 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8205 8206 Level: advanced 8207 8208 Notes: 8209 Call `DMPlexRestoreClosureIndices()` to free allocated memory 8210 8211 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8212 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 8213 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8214 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 8215 indices (with the above semantics) are implied. 8216 8217 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 8218 `PetscSection`, `DMGetGlobalSection()` 8219 @*/ 8220 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8221 { 8222 PetscInt numRows = -1, numCols = -1; 8223 8224 PetscFunctionBeginHot; 8225 PetscCall(DMPlexGetClosureIndices_Internal(dm, section, idxSection, point, useClPerm, &numRows, &numCols, indices, outOffsets, values, PETSC_TRUE, PETSC_TRUE)); 8226 PetscCheck(numRows == numCols, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Symmetric matrix transformation produces rectangular dimensions (%" PetscInt_FMT ", %" PetscInt_FMT ")", numRows, numCols); 8227 *numIndices = numRows; 8228 PetscFunctionReturn(PETSC_SUCCESS); 8229 } 8230 8231 /*@C 8232 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8233 8234 Not collective 8235 8236 Input Parameters: 8237 + dm - The `DM` 8238 . section - The `PetscSection` describing the points (a local section) 8239 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8240 . point - The point defining the closure 8241 - useClPerm - Use the closure point permutation if available 8242 8243 Output Parameters: 8244 + numIndices - The number of dof indices in the closure of point with the input sections 8245 . indices - The dof indices 8246 . outOffsets - Array to write the field offsets into, or `NULL` 8247 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8248 8249 Level: advanced 8250 8251 Notes: 8252 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8253 8254 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8255 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8256 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8257 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8258 indices (with the above semantics) are implied. 8259 8260 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8261 @*/ 8262 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8263 { 8264 PetscFunctionBegin; 8265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8266 PetscAssertPointer(indices, 7); 8267 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8268 PetscFunctionReturn(PETSC_SUCCESS); 8269 } 8270 8271 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8272 { 8273 DM_Plex *mesh = (DM_Plex *)dm->data; 8274 PetscInt *indices; 8275 PetscInt numIndices; 8276 const PetscScalar *valuesOrig = values; 8277 PetscErrorCode ierr; 8278 8279 PetscFunctionBegin; 8280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8281 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8282 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8283 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8284 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8285 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8286 8287 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8288 8289 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8290 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8291 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8292 if (ierr) { 8293 PetscMPIInt rank; 8294 8295 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8296 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8297 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8298 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8299 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8300 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8301 } 8302 if (mesh->printFEM > 1) { 8303 PetscInt i; 8304 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8305 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8306 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8307 } 8308 8309 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8310 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8311 PetscFunctionReturn(PETSC_SUCCESS); 8312 } 8313 8314 /*@C 8315 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8316 8317 Not collective 8318 8319 Input Parameters: 8320 + dm - The `DM` 8321 . section - The section describing the layout in `v`, or `NULL` to use the default section 8322 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8323 . A - The matrix 8324 . point - The point in the `DM` 8325 . values - The array of values 8326 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8327 8328 Level: intermediate 8329 8330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8331 @*/ 8332 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8333 { 8334 PetscFunctionBegin; 8335 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8336 PetscFunctionReturn(PETSC_SUCCESS); 8337 } 8338 8339 /*@C 8340 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8341 8342 Not collective 8343 8344 Input Parameters: 8345 + dmRow - The `DM` for the row fields 8346 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8347 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8348 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8349 . dmCol - The `DM` for the column fields 8350 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8351 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8352 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8353 . A - The matrix 8354 . point - The point in the `DM` 8355 . values - The array of values 8356 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8357 8358 Level: intermediate 8359 8360 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8361 @*/ 8362 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) 8363 { 8364 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8365 PetscInt *indicesRow, *indicesCol; 8366 PetscInt numIndicesRow = -1, numIndicesCol = -1; 8367 const PetscScalar *valuesV0 = values, *valuesV1, *valuesV2; 8368 8369 PetscErrorCode ierr; 8370 8371 PetscFunctionBegin; 8372 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8373 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8374 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8375 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8376 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8377 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8378 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8379 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8380 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8381 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8382 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8383 8384 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmRow, sectionRow, point, &numIndicesRow)); 8385 PetscCall(DMPlexGetClosureIndicesSize_Internal(dmCol, sectionCol, point, &numIndicesCol)); 8386 valuesV1 = valuesV0; 8387 PetscCall(DMPlexGetClosureIndices_Internal(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV1, PETSC_FALSE, PETSC_TRUE)); 8388 valuesV2 = valuesV1; 8389 PetscCall(DMPlexGetClosureIndices_Internal(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesRow, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2, PETSC_TRUE, PETSC_FALSE)); 8390 8391 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2)); 8392 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8393 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, valuesV2, mode); 8394 if (ierr) { 8395 PetscMPIInt rank; 8396 8397 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8398 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8399 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8400 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&valuesV2)); 8401 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8402 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8403 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8404 } 8405 8406 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&valuesV2)); 8407 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&valuesV1)); 8408 if (valuesV2 != valuesV1) PetscCall(DMRestoreWorkArray(dmCol, 0, MPIU_SCALAR, &valuesV2)); 8409 if (valuesV1 != valuesV0) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &valuesV1)); 8410 PetscFunctionReturn(PETSC_SUCCESS); 8411 } 8412 8413 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8414 { 8415 DM_Plex *mesh = (DM_Plex *)dmf->data; 8416 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8417 PetscInt *cpoints = NULL; 8418 PetscInt *findices, *cindices; 8419 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8420 PetscInt foffsets[32], coffsets[32]; 8421 DMPolytopeType ct; 8422 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8423 PetscErrorCode ierr; 8424 8425 PetscFunctionBegin; 8426 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8427 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8428 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8429 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8430 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8431 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8432 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8433 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8434 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8435 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8436 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8437 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8438 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8439 PetscCall(PetscArrayzero(foffsets, 32)); 8440 PetscCall(PetscArrayzero(coffsets, 32)); 8441 /* Column indices */ 8442 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8443 maxFPoints = numCPoints; 8444 /* Compress out points not in the section */ 8445 /* TODO: Squeeze out points with 0 dof as well */ 8446 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8447 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8448 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8449 cpoints[q * 2] = cpoints[p]; 8450 cpoints[q * 2 + 1] = cpoints[p + 1]; 8451 ++q; 8452 } 8453 } 8454 numCPoints = q; 8455 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8456 PetscInt fdof; 8457 8458 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8459 if (!dof) continue; 8460 for (f = 0; f < numFields; ++f) { 8461 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8462 coffsets[f + 1] += fdof; 8463 } 8464 numCIndices += dof; 8465 } 8466 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8467 /* Row indices */ 8468 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8469 { 8470 DMPlexTransform tr; 8471 DMPolytopeType *rct; 8472 PetscInt *rsize, *rcone, *rornt, Nt; 8473 8474 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8475 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8476 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8477 numSubcells = rsize[Nt - 1]; 8478 PetscCall(DMPlexTransformDestroy(&tr)); 8479 } 8480 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8481 for (r = 0, q = 0; r < numSubcells; ++r) { 8482 /* TODO Map from coarse to fine cells */ 8483 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8484 /* Compress out points not in the section */ 8485 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8486 for (p = 0; p < numFPoints * 2; p += 2) { 8487 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8488 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8489 if (!dof) continue; 8490 for (s = 0; s < q; ++s) 8491 if (fpoints[p] == ftotpoints[s * 2]) break; 8492 if (s < q) continue; 8493 ftotpoints[q * 2] = fpoints[p]; 8494 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8495 ++q; 8496 } 8497 } 8498 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8499 } 8500 numFPoints = q; 8501 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8502 PetscInt fdof; 8503 8504 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8505 if (!dof) continue; 8506 for (f = 0; f < numFields; ++f) { 8507 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8508 foffsets[f + 1] += fdof; 8509 } 8510 numFIndices += dof; 8511 } 8512 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8513 8514 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8515 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8516 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8517 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8518 if (numFields) { 8519 const PetscInt **permsF[32] = {NULL}; 8520 const PetscInt **permsC[32] = {NULL}; 8521 8522 for (f = 0; f < numFields; f++) { 8523 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8524 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8525 } 8526 for (p = 0; p < numFPoints; p++) { 8527 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8528 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8529 } 8530 for (p = 0; p < numCPoints; p++) { 8531 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8532 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8533 } 8534 for (f = 0; f < numFields; f++) { 8535 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8536 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8537 } 8538 } else { 8539 const PetscInt **permsF = NULL; 8540 const PetscInt **permsC = NULL; 8541 8542 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8543 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8544 for (p = 0, off = 0; p < numFPoints; p++) { 8545 const PetscInt *perm = permsF ? permsF[p] : NULL; 8546 8547 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8548 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8549 } 8550 for (p = 0, off = 0; p < numCPoints; p++) { 8551 const PetscInt *perm = permsC ? permsC[p] : NULL; 8552 8553 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8554 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8555 } 8556 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8557 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8558 } 8559 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8560 /* TODO: flips */ 8561 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8562 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8563 if (ierr) { 8564 PetscMPIInt rank; 8565 8566 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8567 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8568 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8569 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8570 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8571 } 8572 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8573 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8574 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8575 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8576 PetscFunctionReturn(PETSC_SUCCESS); 8577 } 8578 8579 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8580 { 8581 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8582 PetscInt *cpoints = NULL; 8583 PetscInt foffsets[32] = {0}, coffsets[32] = {0}; 8584 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8585 DMPolytopeType ct; 8586 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8587 8588 PetscFunctionBegin; 8589 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8590 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8591 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8592 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8593 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8594 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8595 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8596 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8597 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8598 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8599 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8600 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8601 /* Column indices */ 8602 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8603 maxFPoints = numCPoints; 8604 /* Compress out points not in the section */ 8605 /* TODO: Squeeze out points with 0 dof as well */ 8606 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8607 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8608 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8609 cpoints[q * 2] = cpoints[p]; 8610 cpoints[q * 2 + 1] = cpoints[p + 1]; 8611 ++q; 8612 } 8613 } 8614 numCPoints = q; 8615 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8616 PetscInt fdof; 8617 8618 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8619 if (!dof) continue; 8620 for (f = 0; f < numFields; ++f) { 8621 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8622 coffsets[f + 1] += fdof; 8623 } 8624 numCIndices += dof; 8625 } 8626 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8627 /* Row indices */ 8628 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8629 { 8630 DMPlexTransform tr; 8631 DMPolytopeType *rct; 8632 PetscInt *rsize, *rcone, *rornt, Nt; 8633 8634 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8635 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8636 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8637 numSubcells = rsize[Nt - 1]; 8638 PetscCall(DMPlexTransformDestroy(&tr)); 8639 } 8640 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8641 for (r = 0, q = 0; r < numSubcells; ++r) { 8642 /* TODO Map from coarse to fine cells */ 8643 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8644 /* Compress out points not in the section */ 8645 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8646 for (p = 0; p < numFPoints * 2; p += 2) { 8647 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8648 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8649 if (!dof) continue; 8650 for (s = 0; s < q; ++s) 8651 if (fpoints[p] == ftotpoints[s * 2]) break; 8652 if (s < q) continue; 8653 ftotpoints[q * 2] = fpoints[p]; 8654 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8655 ++q; 8656 } 8657 } 8658 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8659 } 8660 numFPoints = q; 8661 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8662 PetscInt fdof; 8663 8664 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8665 if (!dof) continue; 8666 for (f = 0; f < numFields; ++f) { 8667 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8668 foffsets[f + 1] += fdof; 8669 } 8670 numFIndices += dof; 8671 } 8672 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8673 8674 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8675 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8676 if (numFields) { 8677 const PetscInt **permsF[32] = {NULL}; 8678 const PetscInt **permsC[32] = {NULL}; 8679 8680 for (f = 0; f < numFields; f++) { 8681 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8682 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8683 } 8684 for (p = 0; p < numFPoints; p++) { 8685 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8686 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8687 } 8688 for (p = 0; p < numCPoints; p++) { 8689 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8690 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8691 } 8692 for (f = 0; f < numFields; f++) { 8693 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8694 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8695 } 8696 } else { 8697 const PetscInt **permsF = NULL; 8698 const PetscInt **permsC = NULL; 8699 8700 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8701 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8702 for (p = 0, off = 0; p < numFPoints; p++) { 8703 const PetscInt *perm = permsF ? permsF[p] : NULL; 8704 8705 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8706 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8707 } 8708 for (p = 0, off = 0; p < numCPoints; p++) { 8709 const PetscInt *perm = permsC ? permsC[p] : NULL; 8710 8711 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8712 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8713 } 8714 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8715 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8716 } 8717 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8718 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8719 PetscFunctionReturn(PETSC_SUCCESS); 8720 } 8721 8722 /*@ 8723 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8724 8725 Input Parameter: 8726 . dm - The `DMPLEX` object 8727 8728 Output Parameter: 8729 . cellHeight - The height of a cell 8730 8731 Level: developer 8732 8733 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8734 @*/ 8735 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8736 { 8737 DM_Plex *mesh = (DM_Plex *)dm->data; 8738 8739 PetscFunctionBegin; 8740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8741 PetscAssertPointer(cellHeight, 2); 8742 *cellHeight = mesh->vtkCellHeight; 8743 PetscFunctionReturn(PETSC_SUCCESS); 8744 } 8745 8746 /*@ 8747 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8748 8749 Input Parameters: 8750 + dm - The `DMPLEX` object 8751 - cellHeight - The height of a cell 8752 8753 Level: developer 8754 8755 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8756 @*/ 8757 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8758 { 8759 DM_Plex *mesh = (DM_Plex *)dm->data; 8760 8761 PetscFunctionBegin; 8762 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8763 mesh->vtkCellHeight = cellHeight; 8764 PetscFunctionReturn(PETSC_SUCCESS); 8765 } 8766 8767 /*@ 8768 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8769 8770 Input Parameters: 8771 + dm - The `DMPLEX` object 8772 - ct - The `DMPolytopeType` of the cell 8773 8774 Output Parameters: 8775 + start - The first cell of this type, or `NULL` 8776 - end - The upper bound on this celltype, or `NULL` 8777 8778 Level: advanced 8779 8780 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8781 @*/ 8782 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8783 { 8784 DM_Plex *mesh = (DM_Plex *)dm->data; 8785 DMLabel label; 8786 PetscInt pStart, pEnd; 8787 8788 PetscFunctionBegin; 8789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8790 if (start) { 8791 PetscAssertPointer(start, 3); 8792 *start = 0; 8793 } 8794 if (end) { 8795 PetscAssertPointer(end, 4); 8796 *end = 0; 8797 } 8798 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8799 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8800 if (mesh->tr) { 8801 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8802 } else { 8803 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8804 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8805 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8806 } 8807 PetscFunctionReturn(PETSC_SUCCESS); 8808 } 8809 8810 /*@ 8811 DMPlexGetDepthStratumGlobalSize - Get the global size for a given depth stratum 8812 8813 Input Parameters: 8814 + dm - The `DMPLEX` object 8815 - depth - The depth for the given point stratum 8816 8817 Output Parameter: 8818 . gsize - The global number of points in the stratum 8819 8820 Level: advanced 8821 8822 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8823 @*/ 8824 PetscErrorCode DMPlexGetDepthStratumGlobalSize(DM dm, PetscInt depth, PetscInt *gsize) 8825 { 8826 PetscSF sf; 8827 const PetscInt *leaves; 8828 PetscInt Nl, loc, start, end, lsize = 0; 8829 8830 PetscFunctionBegin; 8831 PetscCall(DMGetPointSF(dm, &sf)); 8832 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 8833 PetscCall(DMPlexGetDepthStratum(dm, depth, &start, &end)); 8834 for (PetscInt p = start; p < end; ++p) { 8835 PetscCall(PetscFindInt(p, Nl, leaves, &loc)); 8836 if (loc < 0) ++lsize; 8837 } 8838 PetscCallMPI(MPI_Allreduce(&lsize, gsize, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 8839 PetscFunctionReturn(PETSC_SUCCESS); 8840 } 8841 8842 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8843 { 8844 PetscSection section, globalSection; 8845 PetscInt *numbers, p; 8846 8847 PetscFunctionBegin; 8848 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8849 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8850 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8851 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8852 PetscCall(PetscSectionSetUp(section)); 8853 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8854 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8855 for (p = pStart; p < pEnd; ++p) { 8856 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8857 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8858 else numbers[p - pStart] += shift; 8859 } 8860 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8861 if (globalSize) { 8862 PetscLayout layout; 8863 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8864 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8865 PetscCall(PetscLayoutDestroy(&layout)); 8866 } 8867 PetscCall(PetscSectionDestroy(§ion)); 8868 PetscCall(PetscSectionDestroy(&globalSection)); 8869 PetscFunctionReturn(PETSC_SUCCESS); 8870 } 8871 8872 /*@ 8873 DMPlexCreateCellNumbering - Get a global cell numbering for all cells on this process 8874 8875 Input Parameters: 8876 + dm - The `DMPLEX` object 8877 - includeAll - Whether to include all cells, or just the simplex and box cells 8878 8879 Output Parameter: 8880 . globalCellNumbers - Global cell numbers for all cells on this process 8881 8882 Level: developer 8883 8884 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()` 8885 @*/ 8886 PetscErrorCode DMPlexCreateCellNumbering(DM dm, PetscBool includeAll, IS *globalCellNumbers) 8887 { 8888 PetscInt cellHeight, cStart, cEnd; 8889 8890 PetscFunctionBegin; 8891 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8892 if (includeAll) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8893 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8894 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8895 PetscFunctionReturn(PETSC_SUCCESS); 8896 } 8897 8898 /*@ 8899 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8900 8901 Input Parameter: 8902 . dm - The `DMPLEX` object 8903 8904 Output Parameter: 8905 . globalCellNumbers - Global cell numbers for all cells on this process 8906 8907 Level: developer 8908 8909 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateCellNumbering()`, `DMPlexGetVertexNumbering()` 8910 @*/ 8911 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8912 { 8913 DM_Plex *mesh = (DM_Plex *)dm->data; 8914 8915 PetscFunctionBegin; 8916 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8917 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8918 *globalCellNumbers = mesh->globalCellNumbers; 8919 PetscFunctionReturn(PETSC_SUCCESS); 8920 } 8921 8922 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8923 { 8924 PetscInt vStart, vEnd; 8925 8926 PetscFunctionBegin; 8927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8928 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8929 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8930 PetscFunctionReturn(PETSC_SUCCESS); 8931 } 8932 8933 /*@ 8934 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8935 8936 Input Parameter: 8937 . dm - The `DMPLEX` object 8938 8939 Output Parameter: 8940 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8941 8942 Level: developer 8943 8944 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8945 @*/ 8946 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8947 { 8948 DM_Plex *mesh = (DM_Plex *)dm->data; 8949 8950 PetscFunctionBegin; 8951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8952 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8953 *globalVertexNumbers = mesh->globalVertexNumbers; 8954 PetscFunctionReturn(PETSC_SUCCESS); 8955 } 8956 8957 /*@ 8958 DMPlexCreatePointNumbering - Create a global numbering for all points. 8959 8960 Collective 8961 8962 Input Parameter: 8963 . dm - The `DMPLEX` object 8964 8965 Output Parameter: 8966 . globalPointNumbers - Global numbers for all points on this process 8967 8968 Level: developer 8969 8970 Notes: 8971 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8972 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8973 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8974 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8975 8976 The partitioned mesh is 8977 ``` 8978 (2)--0--(3)--1--(4) (1)--0--(2) 8979 ``` 8980 and its global numbering is 8981 ``` 8982 (3)--0--(4)--1--(5)--2--(6) 8983 ``` 8984 Then the global numbering is provided as 8985 ``` 8986 [0] Number of indices in set 5 8987 [0] 0 0 8988 [0] 1 1 8989 [0] 2 3 8990 [0] 3 4 8991 [0] 4 -6 8992 [1] Number of indices in set 3 8993 [1] 0 2 8994 [1] 1 5 8995 [1] 2 6 8996 ``` 8997 8998 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8999 @*/ 9000 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 9001 { 9002 IS nums[4]; 9003 PetscInt depths[4], gdepths[4], starts[4]; 9004 PetscInt depth, d, shift = 0; 9005 PetscBool empty = PETSC_FALSE; 9006 PetscMPIInt idepth; 9007 9008 PetscFunctionBegin; 9009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9010 PetscCall(DMPlexGetDepth(dm, &depth)); 9011 // For unstratified meshes use dim instead of depth 9012 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 9013 // If any stratum is empty, we must mark all empty 9014 for (d = 0; d <= depth; ++d) { 9015 PetscInt end; 9016 9017 depths[d] = depth - d; 9018 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 9019 if (!(starts[d] - end)) empty = PETSC_TRUE; 9020 } 9021 if (empty) 9022 for (d = 0; d <= depth; ++d) { 9023 depths[d] = -1; 9024 starts[d] = -1; 9025 } 9026 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 9027 PetscCall(PetscMPIIntCast(depth + 1, &idepth)); 9028 PetscCallMPI(MPIU_Allreduce(depths, gdepths, idepth, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 9029 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]); 9030 // Note here that 'shift' is collective, so that the numbering is stratified by depth 9031 for (d = 0; d <= depth; ++d) { 9032 PetscInt pStart, pEnd, gsize; 9033 9034 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 9035 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 9036 shift += gsize; 9037 } 9038 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 9039 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 9040 PetscFunctionReturn(PETSC_SUCCESS); 9041 } 9042 9043 /*@ 9044 DMPlexCreateEdgeNumbering - Create a global numbering for edges. 9045 9046 Collective 9047 9048 Input Parameter: 9049 . dm - The `DMPLEX` object 9050 9051 Output Parameter: 9052 . globalEdgeNumbers - Global numbers for all edges on this process 9053 9054 Level: developer 9055 9056 Notes: 9057 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). 9058 9059 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()`, `DMPlexGetVertexNumbering()`, `DMPlexCreatePointNumbering()` 9060 @*/ 9061 PetscErrorCode DMPlexCreateEdgeNumbering(DM dm, IS *globalEdgeNumbers) 9062 { 9063 PetscSF sf; 9064 PetscInt eStart, eEnd; 9065 9066 PetscFunctionBegin; 9067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9068 PetscCall(DMGetPointSF(dm, &sf)); 9069 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9070 PetscCall(DMPlexCreateNumbering_Plex(dm, eStart, eEnd, 0, NULL, sf, globalEdgeNumbers)); 9071 PetscFunctionReturn(PETSC_SUCCESS); 9072 } 9073 9074 /*@ 9075 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 9076 9077 Input Parameter: 9078 . dm - The `DMPLEX` object 9079 9080 Output Parameter: 9081 . ranks - The rank field 9082 9083 Options Database Key: 9084 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 9085 9086 Level: intermediate 9087 9088 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9089 @*/ 9090 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 9091 { 9092 DM rdm; 9093 PetscFE fe; 9094 PetscScalar *r; 9095 PetscMPIInt rank; 9096 DMPolytopeType ct; 9097 PetscInt dim, cStart, cEnd, c; 9098 PetscBool simplex; 9099 9100 PetscFunctionBeginUser; 9101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9102 PetscAssertPointer(ranks, 2); 9103 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 9104 PetscCall(DMClone(dm, &rdm)); 9105 PetscCall(DMGetDimension(rdm, &dim)); 9106 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 9107 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9108 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9109 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 9110 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 9111 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9112 PetscCall(PetscFEDestroy(&fe)); 9113 PetscCall(DMCreateDS(rdm)); 9114 PetscCall(DMCreateGlobalVector(rdm, ranks)); 9115 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 9116 PetscCall(VecGetArray(*ranks, &r)); 9117 for (c = cStart; c < cEnd; ++c) { 9118 PetscScalar *lr; 9119 9120 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 9121 if (lr) *lr = rank; 9122 } 9123 PetscCall(VecRestoreArray(*ranks, &r)); 9124 PetscCall(DMDestroy(&rdm)); 9125 PetscFunctionReturn(PETSC_SUCCESS); 9126 } 9127 9128 /*@ 9129 DMPlexCreateLabelField - Create a field whose value is the label value for that point 9130 9131 Input Parameters: 9132 + dm - The `DMPLEX` 9133 - label - The `DMLabel` 9134 9135 Output Parameter: 9136 . val - The label value field 9137 9138 Options Database Key: 9139 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 9140 9141 Level: intermediate 9142 9143 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 9144 @*/ 9145 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 9146 { 9147 DM rdm, plex; 9148 Vec lval; 9149 PetscSection section; 9150 PetscFE fe; 9151 PetscScalar *v; 9152 PetscInt dim, pStart, pEnd, p, cStart; 9153 DMPolytopeType ct; 9154 char name[PETSC_MAX_PATH_LEN]; 9155 const char *lname, *prefix; 9156 9157 PetscFunctionBeginUser; 9158 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9159 PetscAssertPointer(label, 2); 9160 PetscAssertPointer(val, 3); 9161 PetscCall(DMClone(dm, &rdm)); 9162 PetscCall(DMConvert(rdm, DMPLEX, &plex)); 9163 PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, NULL)); 9164 PetscCall(DMPlexGetCellType(plex, cStart, &ct)); 9165 PetscCall(DMDestroy(&plex)); 9166 PetscCall(DMGetDimension(rdm, &dim)); 9167 PetscCall(DMGetOptionsPrefix(dm, &prefix)); 9168 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 9169 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%s_", prefix ? prefix : "", lname)); 9170 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, 1, ct, name, -1, &fe)); 9171 PetscCall(PetscObjectSetName((PetscObject)fe, "")); 9172 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 9173 PetscCall(PetscFEDestroy(&fe)); 9174 PetscCall(DMCreateDS(rdm)); 9175 PetscCall(DMCreateGlobalVector(rdm, val)); 9176 PetscCall(DMCreateLocalVector(rdm, &lval)); 9177 PetscCall(PetscObjectSetName((PetscObject)*val, lname)); 9178 PetscCall(DMGetLocalSection(rdm, §ion)); 9179 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 9180 PetscCall(VecGetArray(lval, &v)); 9181 for (p = pStart; p < pEnd; ++p) { 9182 PetscInt cval, dof, off; 9183 9184 PetscCall(PetscSectionGetDof(section, p, &dof)); 9185 if (!dof) continue; 9186 PetscCall(DMLabelGetValue(label, p, &cval)); 9187 PetscCall(PetscSectionGetOffset(section, p, &off)); 9188 for (PetscInt d = 0; d < dof; d++) v[off + d] = cval; 9189 } 9190 PetscCall(VecRestoreArray(lval, &v)); 9191 PetscCall(DMLocalToGlobal(rdm, lval, INSERT_VALUES, *val)); 9192 PetscCall(VecDestroy(&lval)); 9193 PetscCall(DMDestroy(&rdm)); 9194 PetscFunctionReturn(PETSC_SUCCESS); 9195 } 9196 9197 /*@ 9198 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 9199 9200 Input Parameter: 9201 . dm - The `DMPLEX` object 9202 9203 Level: developer 9204 9205 Notes: 9206 This is a useful diagnostic when creating meshes programmatically. 9207 9208 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9209 9210 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9211 @*/ 9212 PetscErrorCode DMPlexCheckSymmetry(DM dm) 9213 { 9214 PetscSection coneSection, supportSection; 9215 const PetscInt *cone, *support; 9216 PetscInt coneSize, c, supportSize, s; 9217 PetscInt pStart, pEnd, p, pp, csize, ssize; 9218 PetscBool storagecheck = PETSC_TRUE; 9219 9220 PetscFunctionBegin; 9221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9222 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 9223 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 9224 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 9225 /* Check that point p is found in the support of its cone points, and vice versa */ 9226 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9227 for (p = pStart; p < pEnd; ++p) { 9228 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 9229 PetscCall(DMPlexGetCone(dm, p, &cone)); 9230 for (c = 0; c < coneSize; ++c) { 9231 PetscBool dup = PETSC_FALSE; 9232 PetscInt d; 9233 for (d = c - 1; d >= 0; --d) { 9234 if (cone[c] == cone[d]) { 9235 dup = PETSC_TRUE; 9236 break; 9237 } 9238 } 9239 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9240 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9241 for (s = 0; s < supportSize; ++s) { 9242 if (support[s] == p) break; 9243 } 9244 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9245 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9246 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9247 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9248 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9249 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9250 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9251 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]); 9252 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9253 } 9254 } 9255 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9256 if (p != pp) { 9257 storagecheck = PETSC_FALSE; 9258 continue; 9259 } 9260 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9261 PetscCall(DMPlexGetSupport(dm, p, &support)); 9262 for (s = 0; s < supportSize; ++s) { 9263 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9264 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9265 for (c = 0; c < coneSize; ++c) { 9266 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9267 if (cone[c] != pp) { 9268 c = 0; 9269 break; 9270 } 9271 if (cone[c] == p) break; 9272 } 9273 if (c >= coneSize) { 9274 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9275 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9276 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9277 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9278 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9279 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9280 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9281 } 9282 } 9283 } 9284 if (storagecheck) { 9285 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9286 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9287 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9288 } 9289 PetscFunctionReturn(PETSC_SUCCESS); 9290 } 9291 9292 /* 9293 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. 9294 */ 9295 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9296 { 9297 DMPolytopeType cct; 9298 PetscInt ptpoints[4]; 9299 const PetscInt *cone, *ccone, *ptcone; 9300 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9301 9302 PetscFunctionBegin; 9303 *unsplit = 0; 9304 switch (ct) { 9305 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9306 ptpoints[npt++] = c; 9307 break; 9308 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9309 PetscCall(DMPlexGetCone(dm, c, &cone)); 9310 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9311 for (cp = 0; cp < coneSize; ++cp) { 9312 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9313 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9314 } 9315 break; 9316 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9317 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9318 PetscCall(DMPlexGetCone(dm, c, &cone)); 9319 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9320 for (cp = 0; cp < coneSize; ++cp) { 9321 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9322 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9323 for (ccp = 0; ccp < cconeSize; ++ccp) { 9324 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9325 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9326 PetscInt p; 9327 for (p = 0; p < npt; ++p) 9328 if (ptpoints[p] == ccone[ccp]) break; 9329 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9330 } 9331 } 9332 } 9333 break; 9334 default: 9335 break; 9336 } 9337 for (pt = 0; pt < npt; ++pt) { 9338 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9339 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9340 } 9341 PetscFunctionReturn(PETSC_SUCCESS); 9342 } 9343 9344 /*@ 9345 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9346 9347 Input Parameters: 9348 + dm - The `DMPLEX` object 9349 - cellHeight - Normally 0 9350 9351 Level: developer 9352 9353 Notes: 9354 This is a useful diagnostic when creating meshes programmatically. 9355 Currently applicable only to homogeneous simplex or tensor meshes. 9356 9357 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9358 9359 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9360 @*/ 9361 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9362 { 9363 DMPlexInterpolatedFlag interp; 9364 DMPolytopeType ct; 9365 PetscInt vStart, vEnd, cStart, cEnd, c; 9366 9367 PetscFunctionBegin; 9368 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9369 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9370 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9371 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9372 for (c = cStart; c < cEnd; ++c) { 9373 PetscInt *closure = NULL; 9374 PetscInt coneSize, closureSize, cl, Nv = 0; 9375 9376 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9377 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9378 if (interp == DMPLEX_INTERPOLATED_FULL) { 9379 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9380 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)); 9381 } 9382 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9383 for (cl = 0; cl < closureSize * 2; cl += 2) { 9384 const PetscInt p = closure[cl]; 9385 if ((p >= vStart) && (p < vEnd)) ++Nv; 9386 } 9387 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9388 /* Special Case: Tensor faces with identified vertices */ 9389 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9390 PetscInt unsplit; 9391 9392 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9393 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9394 } 9395 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)); 9396 } 9397 PetscFunctionReturn(PETSC_SUCCESS); 9398 } 9399 9400 /*@ 9401 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9402 9403 Collective 9404 9405 Input Parameters: 9406 + dm - The `DMPLEX` object 9407 - cellHeight - Normally 0 9408 9409 Level: developer 9410 9411 Notes: 9412 This is a useful diagnostic when creating meshes programmatically. 9413 This routine is only relevant for meshes that are fully interpolated across all ranks. 9414 It will error out if a partially interpolated mesh is given on some rank. 9415 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9416 9417 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9418 9419 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9420 @*/ 9421 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9422 { 9423 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9424 DMPlexInterpolatedFlag interpEnum; 9425 9426 PetscFunctionBegin; 9427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9428 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9429 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9430 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9431 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9432 PetscFunctionReturn(PETSC_SUCCESS); 9433 } 9434 9435 PetscCall(DMGetDimension(dm, &dim)); 9436 PetscCall(DMPlexGetDepth(dm, &depth)); 9437 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9438 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9439 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9440 for (c = cStart; c < cEnd; ++c) { 9441 const PetscInt *cone, *ornt, *faceSizes, *faces; 9442 const DMPolytopeType *faceTypes; 9443 DMPolytopeType ct; 9444 PetscInt numFaces, coneSize, f; 9445 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9446 9447 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9448 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9449 if (unsplit) continue; 9450 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9451 PetscCall(DMPlexGetCone(dm, c, &cone)); 9452 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9453 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9454 for (cl = 0; cl < closureSize * 2; cl += 2) { 9455 const PetscInt p = closure[cl]; 9456 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9457 } 9458 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9459 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); 9460 for (f = 0; f < numFaces; ++f) { 9461 DMPolytopeType fct; 9462 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9463 9464 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9465 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9466 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9467 const PetscInt p = fclosure[cl]; 9468 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9469 } 9470 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]); 9471 for (v = 0; v < fnumCorners; ++v) { 9472 if (fclosure[v] != faces[fOff + v]) { 9473 PetscInt v1; 9474 9475 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9476 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9477 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9478 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9479 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9480 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]); 9481 } 9482 } 9483 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9484 fOff += faceSizes[f]; 9485 } 9486 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9487 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9488 } 9489 } 9490 PetscFunctionReturn(PETSC_SUCCESS); 9491 } 9492 9493 /*@ 9494 DMPlexCheckGeometry - Check the geometry of mesh cells 9495 9496 Input Parameter: 9497 . dm - The `DMPLEX` object 9498 9499 Level: developer 9500 9501 Notes: 9502 This is a useful diagnostic when creating meshes programmatically. 9503 9504 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9505 9506 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9507 @*/ 9508 PetscErrorCode DMPlexCheckGeometry(DM dm) 9509 { 9510 Vec coordinates; 9511 PetscReal detJ, J[9], refVol = 1.0; 9512 PetscReal vol; 9513 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9514 9515 PetscFunctionBegin; 9516 PetscCall(DMGetDimension(dm, &dim)); 9517 PetscCall(DMGetCoordinateDim(dm, &dE)); 9518 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9519 PetscCall(DMPlexGetDepth(dm, &depth)); 9520 for (d = 0; d < dim; ++d) refVol *= 2.0; 9521 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9522 /* Make sure local coordinates are created, because that step is collective */ 9523 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9524 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9525 for (c = cStart; c < cEnd; ++c) { 9526 DMPolytopeType ct; 9527 PetscInt unsplit; 9528 PetscBool ignoreZeroVol = PETSC_FALSE; 9529 9530 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9531 switch (ct) { 9532 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9533 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9534 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9535 ignoreZeroVol = PETSC_TRUE; 9536 break; 9537 default: 9538 break; 9539 } 9540 switch (ct) { 9541 case DM_POLYTOPE_TRI_PRISM: 9542 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9543 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9544 case DM_POLYTOPE_PYRAMID: 9545 continue; 9546 default: 9547 break; 9548 } 9549 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9550 if (unsplit) continue; 9551 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9552 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); 9553 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9554 /* This should work with periodicity since DG coordinates should be used */ 9555 if (depth > 1) { 9556 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9557 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); 9558 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9559 } 9560 } 9561 PetscFunctionReturn(PETSC_SUCCESS); 9562 } 9563 9564 /*@ 9565 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9566 9567 Collective 9568 9569 Input Parameters: 9570 + dm - The `DMPLEX` object 9571 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9572 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9573 9574 Level: developer 9575 9576 Notes: 9577 This is mainly intended for debugging/testing purposes. 9578 9579 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9580 9581 Extra roots can come from periodic cuts, where additional points appear on the boundary 9582 9583 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9584 @*/ 9585 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9586 { 9587 PetscInt l, nleaves, nroots, overlap; 9588 const PetscInt *locals; 9589 const PetscSFNode *remotes; 9590 PetscBool distributed; 9591 MPI_Comm comm; 9592 PetscMPIInt rank; 9593 9594 PetscFunctionBegin; 9595 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9596 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9597 else pointSF = dm->sf; 9598 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9599 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9600 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9601 { 9602 PetscMPIInt mpiFlag; 9603 9604 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9605 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9606 } 9607 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9608 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9609 if (!distributed) { 9610 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); 9611 PetscFunctionReturn(PETSC_SUCCESS); 9612 } 9613 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); 9614 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9615 9616 /* Check SF graph is compatible with DMPlex chart */ 9617 { 9618 PetscInt pStart, pEnd, maxLeaf; 9619 9620 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9621 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9622 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9623 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9624 } 9625 9626 /* Check Point SF has no local points referenced */ 9627 for (l = 0; l < nleaves; l++) { 9628 PetscMPIInt irank; 9629 9630 PetscCall(PetscMPIIntCast(remotes[l].rank, &irank)); 9631 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); 9632 } 9633 9634 /* Check there are no cells in interface */ 9635 if (!overlap) { 9636 PetscInt cellHeight, cStart, cEnd; 9637 9638 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9639 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9640 for (l = 0; l < nleaves; ++l) { 9641 const PetscInt point = locals ? locals[l] : l; 9642 9643 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9644 } 9645 } 9646 9647 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9648 { 9649 const PetscInt *rootdegree; 9650 9651 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9652 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9653 for (l = 0; l < nleaves; ++l) { 9654 const PetscInt point = locals ? locals[l] : l; 9655 const PetscInt *cone; 9656 PetscInt coneSize, c, idx; 9657 9658 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9659 PetscCall(DMPlexGetCone(dm, point, &cone)); 9660 for (c = 0; c < coneSize; ++c) { 9661 if (!rootdegree[cone[c]]) { 9662 if (locals) { 9663 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9664 } else { 9665 idx = (cone[c] < nleaves) ? cone[c] : -1; 9666 } 9667 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9668 } 9669 } 9670 } 9671 } 9672 PetscFunctionReturn(PETSC_SUCCESS); 9673 } 9674 9675 /*@ 9676 DMPlexCheckOrphanVertices - Check that no vertices are disconnected from the mesh, unless the mesh only consists of disconnected vertices. 9677 9678 Collective 9679 9680 Input Parameter: 9681 . dm - The `DMPLEX` object 9682 9683 Level: developer 9684 9685 Notes: 9686 This is mainly intended for debugging/testing purposes. 9687 9688 Other cell types which are disconnected would be caught by the symmetry and face checks. 9689 9690 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9691 9692 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheck()`, `DMSetFromOptions()` 9693 @*/ 9694 PetscErrorCode DMPlexCheckOrphanVertices(DM dm) 9695 { 9696 PetscInt pStart, pEnd, vStart, vEnd; 9697 9698 PetscFunctionBegin; 9699 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9700 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9701 if (pStart == vStart && pEnd == vEnd) PetscFunctionReturn(PETSC_SUCCESS); 9702 for (PetscInt v = vStart; v < vEnd; ++v) { 9703 PetscInt suppSize; 9704 9705 PetscCall(DMPlexGetSupportSize(dm, v, &suppSize)); 9706 PetscCheck(suppSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is disconnected from the mesh", v); 9707 } 9708 PetscFunctionReturn(PETSC_SUCCESS); 9709 } 9710 9711 /*@ 9712 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9713 9714 Input Parameter: 9715 . dm - The `DMPLEX` object 9716 9717 Level: developer 9718 9719 Notes: 9720 This is a useful diagnostic when creating meshes programmatically. 9721 9722 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9723 9724 Currently does not include `DMPlexCheckCellShape()`. 9725 9726 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9727 @*/ 9728 PetscErrorCode DMPlexCheck(DM dm) 9729 { 9730 PetscInt cellHeight; 9731 9732 PetscFunctionBegin; 9733 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9734 PetscCall(DMPlexCheckSymmetry(dm)); 9735 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9736 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9737 PetscCall(DMPlexCheckGeometry(dm)); 9738 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9739 PetscCall(DMPlexCheckInterfaceCones(dm)); 9740 PetscCall(DMPlexCheckOrphanVertices(dm)); 9741 PetscFunctionReturn(PETSC_SUCCESS); 9742 } 9743 9744 typedef struct cell_stats { 9745 PetscReal min, max, sum, squaresum; 9746 PetscInt count; 9747 } cell_stats_t; 9748 9749 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9750 { 9751 PetscInt i, N = *len; 9752 9753 for (i = 0; i < N; i++) { 9754 cell_stats_t *A = (cell_stats_t *)a; 9755 cell_stats_t *B = (cell_stats_t *)b; 9756 9757 B->min = PetscMin(A->min, B->min); 9758 B->max = PetscMax(A->max, B->max); 9759 B->sum += A->sum; 9760 B->squaresum += A->squaresum; 9761 B->count += A->count; 9762 } 9763 } 9764 9765 /*@ 9766 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9767 9768 Collective 9769 9770 Input Parameters: 9771 + dm - The `DMPLEX` object 9772 . output - If true, statistics will be displayed on `stdout` 9773 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9774 9775 Level: developer 9776 9777 Notes: 9778 This is mainly intended for debugging/testing purposes. 9779 9780 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9781 9782 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9783 @*/ 9784 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9785 { 9786 DM dmCoarse; 9787 cell_stats_t stats, globalStats; 9788 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9789 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9790 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9791 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9792 PetscMPIInt rank, size; 9793 9794 PetscFunctionBegin; 9795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9796 stats.min = PETSC_MAX_REAL; 9797 stats.max = PETSC_MIN_REAL; 9798 stats.sum = stats.squaresum = 0.; 9799 stats.count = 0; 9800 9801 PetscCallMPI(MPI_Comm_size(comm, &size)); 9802 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9803 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9804 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9805 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9806 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9807 for (c = cStart; c < cEnd; c++) { 9808 PetscInt i; 9809 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9810 9811 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9812 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9813 for (i = 0; i < PetscSqr(cdim); ++i) { 9814 frobJ += J[i] * J[i]; 9815 frobInvJ += invJ[i] * invJ[i]; 9816 } 9817 cond2 = frobJ * frobInvJ; 9818 cond = PetscSqrtReal(cond2); 9819 9820 stats.min = PetscMin(stats.min, cond); 9821 stats.max = PetscMax(stats.max, cond); 9822 stats.sum += cond; 9823 stats.squaresum += cond2; 9824 stats.count++; 9825 if (output && cond > limit) { 9826 PetscSection coordSection; 9827 Vec coordsLocal; 9828 PetscScalar *coords = NULL; 9829 PetscInt Nv, d, clSize, cl, *closure = NULL; 9830 9831 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9833 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9834 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9835 for (i = 0; i < Nv / cdim; ++i) { 9836 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9837 for (d = 0; d < cdim; ++d) { 9838 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9839 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9840 } 9841 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9842 } 9843 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9844 for (cl = 0; cl < clSize * 2; cl += 2) { 9845 const PetscInt edge = closure[cl]; 9846 9847 if ((edge >= eStart) && (edge < eEnd)) { 9848 PetscReal len; 9849 9850 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9851 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9852 } 9853 } 9854 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9855 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9856 } 9857 } 9858 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9859 9860 if (size > 1) { 9861 PetscMPIInt blockLengths[2] = {4, 1}; 9862 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9863 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9864 MPI_Op statReduce; 9865 9866 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9867 PetscCallMPI(MPI_Type_commit(&statType)); 9868 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9869 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9870 PetscCallMPI(MPI_Op_free(&statReduce)); 9871 PetscCallMPI(MPI_Type_free(&statType)); 9872 } else { 9873 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9874 } 9875 if (rank == 0) { 9876 count = globalStats.count; 9877 min = globalStats.min; 9878 max = globalStats.max; 9879 mean = globalStats.sum / globalStats.count; 9880 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9881 } 9882 9883 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)); 9884 PetscCall(PetscFree2(J, invJ)); 9885 9886 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9887 if (dmCoarse) { 9888 PetscBool isplex; 9889 9890 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9891 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9892 } 9893 PetscFunctionReturn(PETSC_SUCCESS); 9894 } 9895 9896 /*@ 9897 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9898 orthogonal quality below given tolerance. 9899 9900 Collective 9901 9902 Input Parameters: 9903 + dm - The `DMPLEX` object 9904 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9905 - atol - [0, 1] Absolute tolerance for tagging cells. 9906 9907 Output Parameters: 9908 + OrthQual - `Vec` containing orthogonal quality per cell 9909 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9910 9911 Options Database Keys: 9912 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9913 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9914 9915 Level: intermediate 9916 9917 Notes: 9918 Orthogonal quality is given by the following formula\: 9919 9920 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9921 9922 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 9923 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9924 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9925 calculating the cosine of the angle between these vectors. 9926 9927 Orthogonal quality ranges from 1 (best) to 0 (worst). 9928 9929 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9930 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9931 9932 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9933 9934 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9935 @*/ 9936 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9937 { 9938 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9939 PetscInt *idx; 9940 PetscScalar *oqVals; 9941 const PetscScalar *cellGeomArr, *faceGeomArr; 9942 PetscReal *ci, *fi, *Ai; 9943 MPI_Comm comm; 9944 Vec cellgeom, facegeom; 9945 DM dmFace, dmCell; 9946 IS glob; 9947 ISLocalToGlobalMapping ltog; 9948 PetscViewer vwr; 9949 9950 PetscFunctionBegin; 9951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9952 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9953 PetscAssertPointer(OrthQual, 4); 9954 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9955 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9956 PetscCall(DMGetDimension(dm, &nc)); 9957 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9958 { 9959 DMPlexInterpolatedFlag interpFlag; 9960 9961 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9962 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9963 PetscMPIInt rank; 9964 9965 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9966 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9967 } 9968 } 9969 if (OrthQualLabel) { 9970 PetscAssertPointer(OrthQualLabel, 5); 9971 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9972 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9973 } else { 9974 *OrthQualLabel = NULL; 9975 } 9976 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9977 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9978 PetscCall(DMPlexCreateCellNumbering(dm, PETSC_TRUE, &glob)); 9979 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9980 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9981 PetscCall(VecCreate(comm, OrthQual)); 9982 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9983 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9984 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9985 PetscCall(VecSetUp(*OrthQual)); 9986 PetscCall(ISDestroy(&glob)); 9987 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9988 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9989 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9990 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9991 PetscCall(VecGetDM(cellgeom, &dmCell)); 9992 PetscCall(VecGetDM(facegeom, &dmFace)); 9993 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9994 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9995 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9996 PetscInt cellarr[2], *adj = NULL; 9997 PetscScalar *cArr, *fArr; 9998 PetscReal minvalc = 1.0, minvalf = 1.0; 9999 PetscFVCellGeom *cg; 10000 10001 idx[cellIter] = cell - cStart; 10002 cellarr[0] = cell; 10003 /* Make indexing into cellGeom easier */ 10004 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 10005 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 10006 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 10007 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 10008 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 10009 PetscInt i; 10010 const PetscInt neigh = adj[cellneigh]; 10011 PetscReal normci = 0, normfi = 0, normai = 0; 10012 PetscFVCellGeom *cgneigh; 10013 PetscFVFaceGeom *fg; 10014 10015 /* Don't count ourselves in the neighbor list */ 10016 if (neigh == cell) continue; 10017 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 10018 cellarr[1] = neigh; 10019 { 10020 PetscInt numcovpts; 10021 const PetscInt *covpts; 10022 10023 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10024 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 10025 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 10026 } 10027 10028 /* Compute c_i, f_i and their norms */ 10029 for (i = 0; i < nc; i++) { 10030 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 10031 fi[i] = fg->centroid[i] - cg->centroid[i]; 10032 Ai[i] = fg->normal[i]; 10033 normci += PetscPowReal(ci[i], 2); 10034 normfi += PetscPowReal(fi[i], 2); 10035 normai += PetscPowReal(Ai[i], 2); 10036 } 10037 normci = PetscSqrtReal(normci); 10038 normfi = PetscSqrtReal(normfi); 10039 normai = PetscSqrtReal(normai); 10040 10041 /* Normalize and compute for each face-cell-normal pair */ 10042 for (i = 0; i < nc; i++) { 10043 ci[i] = ci[i] / normci; 10044 fi[i] = fi[i] / normfi; 10045 Ai[i] = Ai[i] / normai; 10046 /* PetscAbs because I don't know if normals are guaranteed to point out */ 10047 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 10048 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 10049 } 10050 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 10051 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 10052 } 10053 PetscCall(PetscFree(adj)); 10054 PetscCall(PetscFree2(cArr, fArr)); 10055 /* Defer to cell if they're equal */ 10056 oqVals[cellIter] = PetscMin(minvalf, minvalc); 10057 if (OrthQualLabel) { 10058 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 10059 } 10060 } 10061 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 10062 PetscCall(VecAssemblyBegin(*OrthQual)); 10063 PetscCall(VecAssemblyEnd(*OrthQual)); 10064 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 10065 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 10066 PetscCall(PetscOptionsCreateViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 10067 if (OrthQualLabel) { 10068 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 10069 } 10070 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 10071 PetscCall(PetscViewerDestroy(&vwr)); 10072 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 10073 PetscFunctionReturn(PETSC_SUCCESS); 10074 } 10075 10076 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 10077 * interpolator construction */ 10078 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 10079 { 10080 PetscSection section, newSection, gsection; 10081 PetscSF sf; 10082 PetscBool hasConstraints, ghasConstraints; 10083 10084 PetscFunctionBegin; 10085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10086 PetscAssertPointer(odm, 2); 10087 PetscCall(DMGetLocalSection(dm, §ion)); 10088 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 10089 PetscCallMPI(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 10090 if (!ghasConstraints) { 10091 PetscCall(PetscObjectReference((PetscObject)dm)); 10092 *odm = dm; 10093 PetscFunctionReturn(PETSC_SUCCESS); 10094 } 10095 PetscCall(DMClone(dm, odm)); 10096 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, *odm)); 10097 PetscCall(DMGetLocalSection(*odm, &newSection)); 10098 PetscCall(DMGetPointSF(*odm, &sf)); 10099 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_TRUE, PETSC_FALSE, &gsection)); 10100 PetscCall(DMSetGlobalSection(*odm, gsection)); 10101 PetscCall(PetscSectionDestroy(&gsection)); 10102 PetscFunctionReturn(PETSC_SUCCESS); 10103 } 10104 10105 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 10106 { 10107 DM dmco, dmfo; 10108 Mat interpo; 10109 Vec rscale; 10110 Vec cglobalo, clocal; 10111 Vec fglobal, fglobalo, flocal; 10112 PetscBool regular; 10113 10114 PetscFunctionBegin; 10115 PetscCall(DMGetFullDM(dmc, &dmco)); 10116 PetscCall(DMGetFullDM(dmf, &dmfo)); 10117 PetscCall(DMSetCoarseDM(dmfo, dmco)); 10118 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 10119 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 10120 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 10121 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 10122 PetscCall(DMCreateLocalVector(dmc, &clocal)); 10123 PetscCall(VecSet(cglobalo, 0.)); 10124 PetscCall(VecSet(clocal, 0.)); 10125 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 10126 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 10127 PetscCall(DMCreateLocalVector(dmf, &flocal)); 10128 PetscCall(VecSet(fglobal, 0.)); 10129 PetscCall(VecSet(fglobalo, 0.)); 10130 PetscCall(VecSet(flocal, 0.)); 10131 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 10132 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 10133 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 10134 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 10135 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 10136 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 10137 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 10138 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 10139 *shift = fglobal; 10140 PetscCall(VecDestroy(&flocal)); 10141 PetscCall(VecDestroy(&fglobalo)); 10142 PetscCall(VecDestroy(&clocal)); 10143 PetscCall(VecDestroy(&cglobalo)); 10144 PetscCall(VecDestroy(&rscale)); 10145 PetscCall(MatDestroy(&interpo)); 10146 PetscCall(DMDestroy(&dmfo)); 10147 PetscCall(DMDestroy(&dmco)); 10148 PetscFunctionReturn(PETSC_SUCCESS); 10149 } 10150 10151 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 10152 { 10153 PetscObject shifto; 10154 Vec shift; 10155 10156 PetscFunctionBegin; 10157 if (!interp) { 10158 Vec rscale; 10159 10160 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 10161 PetscCall(VecDestroy(&rscale)); 10162 } else { 10163 PetscCall(PetscObjectReference((PetscObject)interp)); 10164 } 10165 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 10166 if (!shifto) { 10167 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 10168 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 10169 shifto = (PetscObject)shift; 10170 PetscCall(VecDestroy(&shift)); 10171 } 10172 shift = (Vec)shifto; 10173 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 10174 PetscCall(VecAXPY(fineSol, 1.0, shift)); 10175 PetscCall(MatDestroy(&interp)); 10176 PetscFunctionReturn(PETSC_SUCCESS); 10177 } 10178 10179 /* Pointwise interpolation 10180 Just code FEM for now 10181 u^f = I u^c 10182 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 10183 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 10184 I_{ij} = psi^f_i phi^c_j 10185 */ 10186 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 10187 { 10188 PetscSection gsc, gsf; 10189 PetscInt m, n; 10190 void *ctx; 10191 DM cdm; 10192 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 10193 10194 PetscFunctionBegin; 10195 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10196 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10197 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10198 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10199 10200 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 10201 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 10202 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10203 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 10204 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10205 10206 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10207 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10208 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 10209 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 10210 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 10211 if (scaling) { 10212 /* Use naive scaling */ 10213 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 10214 } 10215 PetscFunctionReturn(PETSC_SUCCESS); 10216 } 10217 10218 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 10219 { 10220 VecScatter ctx; 10221 10222 PetscFunctionBegin; 10223 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 10224 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 10225 PetscCall(VecScatterDestroy(&ctx)); 10226 PetscFunctionReturn(PETSC_SUCCESS); 10227 } 10228 10229 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[]) 10230 { 10231 const PetscInt f = (PetscInt)PetscRealPart(constants[numConstants]); 10232 const PetscInt Nc = uOff[f + 1] - uOff[f]; 10233 for (PetscInt c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 10234 } 10235 10236 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *lmass, Vec *mass) 10237 { 10238 DM dmc; 10239 PetscDS ds; 10240 Vec ones, locmass; 10241 IS cellIS; 10242 PetscFormKey key; 10243 PetscInt depth; 10244 10245 PetscFunctionBegin; 10246 PetscCall(DMClone(dm, &dmc)); 10247 PetscCall(DMCopyDisc(dm, dmc)); 10248 PetscCall(DMGetDS(dmc, &ds)); 10249 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10250 if (mass) PetscCall(DMCreateGlobalVector(dm, mass)); 10251 if (lmass) PetscCall(DMCreateLocalVector(dm, &locmass)); 10252 else PetscCall(DMGetLocalVector(dm, &locmass)); 10253 PetscCall(DMGetLocalVector(dm, &ones)); 10254 PetscCall(DMPlexGetDepth(dm, &depth)); 10255 PetscCall(DMGetStratumIS(dm, "depth", depth, &cellIS)); 10256 PetscCall(VecSet(locmass, 0.0)); 10257 PetscCall(VecSet(ones, 1.0)); 10258 key.label = NULL; 10259 key.value = 0; 10260 key.field = 0; 10261 key.part = 0; 10262 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 10263 PetscCall(ISDestroy(&cellIS)); 10264 if (mass) { 10265 PetscCall(DMLocalToGlobalBegin(dm, locmass, ADD_VALUES, *mass)); 10266 PetscCall(DMLocalToGlobalEnd(dm, locmass, ADD_VALUES, *mass)); 10267 } 10268 PetscCall(DMRestoreLocalVector(dm, &ones)); 10269 if (lmass) *lmass = locmass; 10270 else PetscCall(DMRestoreLocalVector(dm, &locmass)); 10271 PetscCall(DMDestroy(&dmc)); 10272 PetscFunctionReturn(PETSC_SUCCESS); 10273 } 10274 10275 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10276 { 10277 PetscSection gsc, gsf; 10278 PetscInt m, n; 10279 void *ctx; 10280 DM cdm; 10281 PetscBool regular; 10282 10283 PetscFunctionBegin; 10284 if (dmFine == dmCoarse) { 10285 DM dmc; 10286 PetscDS ds; 10287 PetscWeakForm wf; 10288 Vec u; 10289 IS cellIS; 10290 PetscFormKey key; 10291 PetscInt depth; 10292 10293 PetscCall(DMClone(dmFine, &dmc)); 10294 PetscCall(DMCopyDisc(dmFine, dmc)); 10295 PetscCall(DMGetDS(dmc, &ds)); 10296 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10297 PetscCall(PetscWeakFormClear(wf)); 10298 for (PetscInt f = 0; f < dmc->Nf; ++f) PetscCall(PetscDSSetJacobian(ds, f, f, g0_identity_private, NULL, NULL, NULL)); 10299 PetscCall(DMCreateMatrix(dmc, mass)); 10300 PetscCall(DMGetLocalVector(dmc, &u)); 10301 PetscCall(DMPlexGetDepth(dmc, &depth)); 10302 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10303 PetscCall(MatZeroEntries(*mass)); 10304 key.label = NULL; 10305 key.value = 0; 10306 key.field = 0; 10307 key.part = 0; 10308 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10309 PetscCall(ISDestroy(&cellIS)); 10310 PetscCall(DMRestoreLocalVector(dmc, &u)); 10311 PetscCall(DMDestroy(&dmc)); 10312 } else { 10313 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10314 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10315 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10316 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10317 10318 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10319 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10320 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10321 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10322 10323 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10324 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10325 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10326 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10327 } 10328 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10329 PetscFunctionReturn(PETSC_SUCCESS); 10330 } 10331 10332 /*@ 10333 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10334 10335 Input Parameter: 10336 . dm - The `DMPLEX` object 10337 10338 Output Parameter: 10339 . regular - The flag 10340 10341 Level: intermediate 10342 10343 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10344 @*/ 10345 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10346 { 10347 PetscFunctionBegin; 10348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10349 PetscAssertPointer(regular, 2); 10350 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10351 PetscFunctionReturn(PETSC_SUCCESS); 10352 } 10353 10354 /*@ 10355 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10356 10357 Input Parameters: 10358 + dm - The `DMPLEX` object 10359 - regular - The flag 10360 10361 Level: intermediate 10362 10363 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10364 @*/ 10365 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10366 { 10367 PetscFunctionBegin; 10368 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10369 ((DM_Plex *)dm->data)->regularRefinement = regular; 10370 PetscFunctionReturn(PETSC_SUCCESS); 10371 } 10372 10373 /*@ 10374 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10375 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10376 10377 Not Collective 10378 10379 Input Parameter: 10380 . dm - The `DMPLEX` object 10381 10382 Output Parameters: 10383 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10384 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10385 10386 Level: intermediate 10387 10388 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10389 @*/ 10390 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10391 { 10392 DM_Plex *plex = (DM_Plex *)dm->data; 10393 10394 PetscFunctionBegin; 10395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10396 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10397 if (anchorSection) *anchorSection = plex->anchorSection; 10398 if (anchorIS) *anchorIS = plex->anchorIS; 10399 PetscFunctionReturn(PETSC_SUCCESS); 10400 } 10401 10402 /*@ 10403 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10404 10405 Collective 10406 10407 Input Parameters: 10408 + dm - The `DMPLEX` object 10409 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10410 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10411 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10412 10413 Level: intermediate 10414 10415 Notes: 10416 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10417 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10418 combination of other points' degrees of freedom. 10419 10420 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10421 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10422 10423 The reference counts of `anchorSection` and `anchorIS` are incremented. 10424 10425 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10426 @*/ 10427 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10428 { 10429 DM_Plex *plex = (DM_Plex *)dm->data; 10430 PetscMPIInt result; 10431 10432 PetscFunctionBegin; 10433 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10434 if (anchorSection) { 10435 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10436 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10437 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10438 } 10439 if (anchorIS) { 10440 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10441 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10442 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10443 } 10444 10445 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10446 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10447 plex->anchorSection = anchorSection; 10448 10449 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10450 PetscCall(ISDestroy(&plex->anchorIS)); 10451 plex->anchorIS = anchorIS; 10452 10453 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10454 PetscInt size, a, pStart, pEnd; 10455 const PetscInt *anchors; 10456 10457 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10458 PetscCall(ISGetLocalSize(anchorIS, &size)); 10459 PetscCall(ISGetIndices(anchorIS, &anchors)); 10460 for (a = 0; a < size; a++) { 10461 PetscInt p; 10462 10463 p = anchors[a]; 10464 if (p >= pStart && p < pEnd) { 10465 PetscInt dof; 10466 10467 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10468 if (dof) { 10469 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10470 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10471 } 10472 } 10473 } 10474 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10475 } 10476 /* reset the generic constraints */ 10477 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10478 PetscFunctionReturn(PETSC_SUCCESS); 10479 } 10480 10481 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10482 { 10483 PetscSection anchorSection; 10484 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10485 10486 PetscFunctionBegin; 10487 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10488 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10489 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10490 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10491 if (numFields) { 10492 PetscInt f; 10493 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10494 10495 for (f = 0; f < numFields; f++) { 10496 PetscInt numComp; 10497 10498 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10499 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10500 } 10501 } 10502 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10503 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10504 pStart = PetscMax(pStart, sStart); 10505 pEnd = PetscMin(pEnd, sEnd); 10506 pEnd = PetscMax(pStart, pEnd); 10507 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10508 for (p = pStart; p < pEnd; p++) { 10509 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10510 if (dof) { 10511 PetscCall(PetscSectionGetDof(section, p, &dof)); 10512 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10513 for (f = 0; f < numFields; f++) { 10514 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10515 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10516 } 10517 } 10518 } 10519 PetscCall(PetscSectionSetUp(*cSec)); 10520 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10521 PetscFunctionReturn(PETSC_SUCCESS); 10522 } 10523 10524 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10525 { 10526 PetscSection aSec; 10527 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10528 const PetscInt *anchors; 10529 PetscInt numFields, f; 10530 IS aIS; 10531 MatType mtype; 10532 PetscBool iscuda, iskokkos; 10533 10534 PetscFunctionBegin; 10535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10536 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10537 PetscCall(PetscSectionGetStorageSize(section, &n)); 10538 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10539 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10540 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10541 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10542 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10543 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10544 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10545 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10546 else mtype = MATSEQAIJ; 10547 PetscCall(MatSetType(*cMat, mtype)); 10548 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10549 PetscCall(ISGetIndices(aIS, &anchors)); 10550 /* cSec will be a subset of aSec and section */ 10551 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10552 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10553 PetscCall(PetscMalloc1(m + 1, &i)); 10554 i[0] = 0; 10555 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10556 for (p = pStart; p < pEnd; p++) { 10557 PetscInt rDof, rOff, r; 10558 10559 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10560 if (!rDof) continue; 10561 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10562 if (numFields) { 10563 for (f = 0; f < numFields; f++) { 10564 annz = 0; 10565 for (r = 0; r < rDof; r++) { 10566 a = anchors[rOff + r]; 10567 if (a < sStart || a >= sEnd) continue; 10568 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10569 annz += aDof; 10570 } 10571 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10572 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10573 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10574 } 10575 } else { 10576 annz = 0; 10577 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10578 for (q = 0; q < dof; q++) { 10579 a = anchors[rOff + q]; 10580 if (a < sStart || a >= sEnd) continue; 10581 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10582 annz += aDof; 10583 } 10584 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10585 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10586 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10587 } 10588 } 10589 nnz = i[m]; 10590 PetscCall(PetscMalloc1(nnz, &j)); 10591 offset = 0; 10592 for (p = pStart; p < pEnd; p++) { 10593 if (numFields) { 10594 for (f = 0; f < numFields; f++) { 10595 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10596 for (q = 0; q < dof; q++) { 10597 PetscInt rDof, rOff, r; 10598 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10599 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10600 for (r = 0; r < rDof; r++) { 10601 PetscInt s; 10602 10603 a = anchors[rOff + r]; 10604 if (a < sStart || a >= sEnd) continue; 10605 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10606 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10607 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10608 } 10609 } 10610 } 10611 } else { 10612 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10613 for (q = 0; q < dof; q++) { 10614 PetscInt rDof, rOff, r; 10615 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10616 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10617 for (r = 0; r < rDof; r++) { 10618 PetscInt s; 10619 10620 a = anchors[rOff + r]; 10621 if (a < sStart || a >= sEnd) continue; 10622 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10623 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10624 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10625 } 10626 } 10627 } 10628 } 10629 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10630 PetscCall(PetscFree(i)); 10631 PetscCall(PetscFree(j)); 10632 PetscCall(ISRestoreIndices(aIS, &anchors)); 10633 PetscFunctionReturn(PETSC_SUCCESS); 10634 } 10635 10636 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10637 { 10638 DM_Plex *plex = (DM_Plex *)dm->data; 10639 PetscSection anchorSection, section, cSec; 10640 Mat cMat; 10641 10642 PetscFunctionBegin; 10643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10644 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10645 if (anchorSection) { 10646 PetscInt Nf; 10647 10648 PetscCall(DMGetLocalSection(dm, §ion)); 10649 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10650 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10651 PetscCall(DMGetNumFields(dm, &Nf)); 10652 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10653 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10654 PetscCall(PetscSectionDestroy(&cSec)); 10655 PetscCall(MatDestroy(&cMat)); 10656 } 10657 PetscFunctionReturn(PETSC_SUCCESS); 10658 } 10659 10660 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10661 { 10662 IS subis; 10663 PetscSection section, subsection; 10664 10665 PetscFunctionBegin; 10666 PetscCall(DMGetLocalSection(dm, §ion)); 10667 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10668 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10669 /* Create subdomain */ 10670 PetscCall(DMPlexFilter(dm, label, value, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 10671 /* Create submodel */ 10672 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10673 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10674 PetscCall(DMSetLocalSection(*subdm, subsection)); 10675 PetscCall(PetscSectionDestroy(&subsection)); 10676 PetscCall(DMCopyDisc(dm, *subdm)); 10677 /* Create map from submodel to global model */ 10678 if (is) { 10679 PetscSection sectionGlobal, subsectionGlobal; 10680 IS spIS; 10681 const PetscInt *spmap; 10682 PetscInt *subIndices; 10683 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10684 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10685 10686 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10687 PetscCall(ISGetIndices(spIS, &spmap)); 10688 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10689 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10690 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10691 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10692 for (p = pStart; p < pEnd; ++p) { 10693 PetscInt gdof, pSubSize = 0; 10694 10695 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10696 if (gdof > 0) { 10697 for (f = 0; f < Nf; ++f) { 10698 PetscInt fdof, fcdof; 10699 10700 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10701 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10702 pSubSize += fdof - fcdof; 10703 } 10704 subSize += pSubSize; 10705 if (pSubSize) { 10706 if (bs < 0) { 10707 bs = pSubSize; 10708 } else if (bs != pSubSize) { 10709 /* Layout does not admit a pointwise block size */ 10710 bs = 1; 10711 } 10712 } 10713 } 10714 } 10715 /* Must have same blocksize on all procs (some might have no points) */ 10716 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 10717 bsLocal[1] = bs; 10718 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10719 if (bsMinMax[0] != bsMinMax[1]) { 10720 bs = 1; 10721 } else { 10722 bs = bsMinMax[0]; 10723 } 10724 PetscCall(PetscMalloc1(subSize, &subIndices)); 10725 for (p = pStart; p < pEnd; ++p) { 10726 PetscInt gdof, goff; 10727 10728 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10729 if (gdof > 0) { 10730 const PetscInt point = spmap[p]; 10731 10732 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10733 for (f = 0; f < Nf; ++f) { 10734 PetscInt fdof, fcdof, fc, f2, poff = 0; 10735 10736 /* Can get rid of this loop by storing field information in the global section */ 10737 for (f2 = 0; f2 < f; ++f2) { 10738 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10739 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10740 poff += fdof - fcdof; 10741 } 10742 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10743 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10744 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10745 } 10746 } 10747 } 10748 PetscCall(ISRestoreIndices(spIS, &spmap)); 10749 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10750 if (bs > 1) { 10751 /* We need to check that the block size does not come from non-contiguous fields */ 10752 PetscInt i, j, set = 1; 10753 for (i = 0; i < subSize; i += bs) { 10754 for (j = 0; j < bs; ++j) { 10755 if (subIndices[i + j] != subIndices[i] + j) { 10756 set = 0; 10757 break; 10758 } 10759 } 10760 } 10761 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10762 } 10763 /* Attach nullspace */ 10764 for (f = 0; f < Nf; ++f) { 10765 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10766 if ((*subdm)->nullspaceConstructors[f]) break; 10767 } 10768 if (f < Nf) { 10769 MatNullSpace nullSpace; 10770 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10771 10772 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10773 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10774 } 10775 } 10776 PetscFunctionReturn(PETSC_SUCCESS); 10777 } 10778 10779 /*@ 10780 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10781 10782 Input Parameters: 10783 + dm - The `DM` 10784 - dummy - unused argument 10785 10786 Options Database Key: 10787 . -dm_plex_monitor_throughput - Activate the monitor 10788 10789 Level: developer 10790 10791 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10792 @*/ 10793 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10794 { 10795 PetscLogHandler default_handler; 10796 10797 PetscFunctionBegin; 10798 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10799 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10800 if (default_handler) { 10801 PetscLogEvent event; 10802 PetscEventPerfInfo eventInfo; 10803 PetscLogDouble cellRate, flopRate; 10804 PetscInt cStart, cEnd, Nf, N; 10805 const char *name; 10806 10807 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10808 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10809 PetscCall(DMGetNumFields(dm, &Nf)); 10810 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10811 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10812 N = (cEnd - cStart) * Nf * eventInfo.count; 10813 flopRate = eventInfo.flops / eventInfo.time; 10814 cellRate = N / eventInfo.time; 10815 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)); 10816 } else { 10817 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."); 10818 } 10819 PetscFunctionReturn(PETSC_SUCCESS); 10820 } 10821