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 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets, DMPLEX_Uninterpolate; 15 16 PetscBool Plexcite = PETSC_FALSE; 17 const char PlexCitation[] = "@article{LangeMitchellKnepleyGorman2015,\n" 18 "title = {Efficient mesh management in {Firedrake} using {PETSc-DMPlex}},\n" 19 "author = {Michael Lange and Lawrence Mitchell and Matthew G. Knepley and Gerard J. Gorman},\n" 20 "journal = {SIAM Journal on Scientific Computing},\n" 21 "volume = {38},\n" 22 "number = {5},\n" 23 "pages = {S143--S155},\n" 24 "eprint = {http://arxiv.org/abs/1506.07749},\n" 25 "doi = {10.1137/15M1026092},\n" 26 "year = {2016},\n" 27 "petsc_uses={DMPlex},\n}\n"; 28 29 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 30 31 /*@ 32 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 33 34 Input Parameter: 35 . dm - The `DMPLEX` object 36 37 Output Parameter: 38 . simplex - Flag checking for a simplex 39 40 Level: intermediate 41 42 Note: 43 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 44 If the mesh has no cells, this returns `PETSC_FALSE`. 45 46 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 47 @*/ 48 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 49 { 50 DMPolytopeType ct; 51 PetscInt cStart, cEnd; 52 53 PetscFunctionBegin; 54 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 55 if (cEnd <= cStart) { 56 *simplex = PETSC_FALSE; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 60 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@ 65 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 66 67 Input Parameters: 68 + dm - The `DMPLEX` object 69 - height - The cell height in the Plex, 0 is the default 70 71 Output Parameters: 72 + cStart - The first "normal" cell 73 - cEnd - The upper bound on "normal" cells 74 75 Level: developer 76 77 Note: 78 This function requires that tensor cells are ordered last. 79 80 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 81 @*/ 82 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 83 { 84 DMLabel ctLabel; 85 IS valueIS; 86 const PetscInt *ctypes; 87 PetscInt Nct, cS = PETSC_MAX_INT, cE = 0; 88 89 PetscFunctionBegin; 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetValueIS(ctLabel, &valueIS)); 92 PetscCall(ISGetLocalSize(valueIS, &Nct)); 93 PetscCall(ISGetIndices(valueIS, &ctypes)); 94 if (!Nct) cS = cE = 0; 95 for (PetscInt t = 0; t < Nct; ++t) { 96 const DMPolytopeType ct = (DMPolytopeType)ctypes[t]; 97 PetscInt ctS, ctE, ht; 98 99 if (ct == DM_POLYTOPE_UNKNOWN) { 100 // If any cells are not typed, just use all cells 101 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), cStart, cEnd)); 102 break; 103 } 104 if (DMPolytopeTypeIsHybrid(ct) || ct == DM_POLYTOPE_FV_GHOST) continue; 105 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &ctS, &ctE)); 106 if (ctS >= ctE) continue; 107 // Check that a point has the right height 108 PetscCall(DMPlexGetPointHeight(dm, ctS, &ht)); 109 if (ht != height) continue; 110 cS = PetscMin(cS, ctS); 111 cE = PetscMax(cE, ctE); 112 } 113 PetscCall(ISDestroy(&valueIS)); 114 // Reset label for fast lookup 115 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 116 if (cStart) *cStart = cS; 117 if (cEnd) *cEnd = cE; 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 PetscErrorCode DMPlexGetFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **ssStart, PetscInt **ssEnd, PetscViewerVTKFieldType **sft) 122 { 123 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, c, depth, cellHeight, t; 124 PetscInt *sStart, *sEnd; 125 PetscViewerVTKFieldType *ft; 126 PetscInt vcdof[DM_NUM_POLYTOPES + 1], globalvcdof[DM_NUM_POLYTOPES + 1]; 127 DMLabel depthLabel, ctLabel; 128 129 PetscFunctionBegin; 130 131 /* the vcdof and globalvcdof are sized to allow every polytope type and simple vertex at DM_NUM_POLYTOPES */ 132 PetscCall(PetscArrayzero(vcdof, DM_NUM_POLYTOPES + 1)); 133 PetscCall(DMGetCoordinateDim(dm, &cdim)); 134 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 135 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 136 if (field >= 0) { 137 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[DM_NUM_POLYTOPES])); 138 } else { 139 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[DM_NUM_POLYTOPES])); 140 } 141 142 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 143 PetscCall(DMPlexGetDepth(dm, &depth)); 144 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 145 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 146 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 147 const DMPolytopeType ict = (DMPolytopeType)c; 148 PetscInt dep; 149 150 if (ict == DM_POLYTOPE_FV_GHOST) continue; 151 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 152 if (pStart >= 0) { 153 PetscCall(DMLabelGetValue(depthLabel, cStart, &dep)); 154 if (dep != depth - cellHeight) continue; 155 } 156 if (field >= 0) { 157 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[c])); 158 } else { 159 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[c])); 160 } 161 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 162 } 163 164 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, DM_NUM_POLYTOPES + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 165 *types = 0; 166 167 for (c = 0; c < DM_NUM_POLYTOPES + 1; ++c) { 168 if (globalvcdof[c]) ++(*types); 169 } 170 171 PetscCall(PetscMalloc3(*types, &sStart, *types, &sEnd, *types, &ft)); 172 t = 0; 173 if (globalvcdof[DM_NUM_POLYTOPES]) { 174 sStart[t] = vStart; 175 sEnd[t] = vEnd; 176 ft[t] = (globalvcdof[t] == cdim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD; 177 ++t; 178 } 179 180 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 181 if (globalvcdof[c]) { 182 const DMPolytopeType ict = (DMPolytopeType)c; 183 184 PetscCall(DMLabelGetStratumBounds(ctLabel, ict, &cStart, &cEnd)); 185 sStart[t] = cStart; 186 sEnd[t] = cEnd; 187 ft[t] = (globalvcdof[c] == cdim) ? PETSC_VTK_CELL_VECTOR_FIELD : PETSC_VTK_CELL_FIELD; 188 ++t; 189 } 190 } 191 192 if (!(*types)) { 193 if (field >= 0) { 194 const char *fieldname; 195 196 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 197 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 198 } else { 199 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 200 } 201 } 202 203 *ssStart = sStart; 204 *ssEnd = sEnd; 205 *sft = ft; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 PetscErrorCode DMPlexRestoreFieldTypes_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *types, PetscInt **sStart, PetscInt **sEnd, PetscViewerVTKFieldType **ft) 210 { 211 PetscFunctionBegin; 212 PetscCall(PetscFree3(*sStart, *sEnd, *ft)); 213 PetscFunctionReturn(PETSC_SUCCESS); 214 } 215 216 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 217 { 218 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 219 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 220 221 PetscFunctionBegin; 222 *ft = PETSC_VTK_INVALID; 223 PetscCall(DMGetCoordinateDim(dm, &cdim)); 224 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 225 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 226 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 227 if (field >= 0) { 228 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 229 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 230 } else { 231 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 232 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 233 } 234 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 235 if (globalvcdof[0]) { 236 *sStart = vStart; 237 *sEnd = vEnd; 238 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 239 else *ft = PETSC_VTK_POINT_FIELD; 240 } else if (globalvcdof[1]) { 241 *sStart = cStart; 242 *sEnd = cEnd; 243 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 244 else *ft = PETSC_VTK_CELL_FIELD; 245 } else { 246 if (field >= 0) { 247 const char *fieldname; 248 249 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 250 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 251 } else { 252 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 253 } 254 } 255 PetscFunctionReturn(PETSC_SUCCESS); 256 } 257 258 /*@ 259 DMPlexVecView1D - Plot many 1D solutions on the same line graph 260 261 Collective 262 263 Input Parameters: 264 + dm - The `DMPLEX` object 265 . n - The number of vectors 266 . u - The array of local vectors 267 - viewer - The `PetscViewer` 268 269 Level: advanced 270 271 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 272 @*/ 273 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 274 { 275 PetscDS ds; 276 PetscDraw draw = NULL; 277 PetscDrawLG lg; 278 Vec coordinates; 279 const PetscScalar *coords, **sol; 280 PetscReal *vals; 281 PetscInt *Nc; 282 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 283 char **names; 284 285 PetscFunctionBegin; 286 PetscCall(DMGetDS(dm, &ds)); 287 PetscCall(PetscDSGetNumFields(ds, &Nf)); 288 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 289 PetscCall(PetscDSGetComponents(ds, &Nc)); 290 291 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 292 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 293 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 294 295 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 296 for (i = 0, l = 0; i < n; ++i) { 297 const char *vname; 298 299 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 300 for (f = 0; f < Nf; ++f) { 301 PetscObject disc; 302 const char *fname; 303 char tmpname[PETSC_MAX_PATH_LEN]; 304 305 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 306 /* TODO Create names for components */ 307 for (c = 0; c < Nc[f]; ++c, ++l) { 308 PetscCall(PetscObjectGetName(disc, &fname)); 309 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 310 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 311 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 312 PetscCall(PetscStrallocpy(tmpname, &names[l])); 313 } 314 } 315 } 316 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 317 /* Just add P_1 support for now */ 318 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 319 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 320 PetscCall(VecGetArrayRead(coordinates, &coords)); 321 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 322 for (v = vStart; v < vEnd; ++v) { 323 PetscScalar *x, *svals; 324 325 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 326 for (i = 0; i < n; ++i) { 327 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 328 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 329 } 330 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 331 } 332 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 333 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 334 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 335 PetscCall(PetscFree3(sol, names, vals)); 336 337 PetscCall(PetscDrawLGDraw(lg)); 338 PetscCall(PetscDrawLGDestroy(&lg)); 339 PetscFunctionReturn(PETSC_SUCCESS); 340 } 341 342 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 343 { 344 DM dm; 345 346 PetscFunctionBegin; 347 PetscCall(VecGetDM(u, &dm)); 348 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 353 { 354 DM dm; 355 PetscSection s; 356 PetscDraw draw, popup; 357 DM cdm; 358 PetscSection coordSection; 359 Vec coordinates; 360 const PetscScalar *array; 361 PetscReal lbound[3], ubound[3]; 362 PetscReal vbound[2], time; 363 PetscBool flg; 364 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 365 const char *name; 366 char title[PETSC_MAX_PATH_LEN]; 367 368 PetscFunctionBegin; 369 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 370 PetscCall(VecGetDM(v, &dm)); 371 PetscCall(DMGetCoordinateDim(dm, &dim)); 372 PetscCall(DMGetLocalSection(dm, &s)); 373 PetscCall(PetscSectionGetNumFields(s, &Nf)); 374 PetscCall(DMGetCoarsenLevel(dm, &level)); 375 PetscCall(DMGetCoordinateDM(dm, &cdm)); 376 PetscCall(DMGetLocalSection(cdm, &coordSection)); 377 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 378 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 379 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 380 381 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 382 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 383 384 PetscCall(VecGetLocalSize(coordinates, &N)); 385 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 386 PetscCall(PetscDrawClear(draw)); 387 388 /* Could implement something like DMDASelectFields() */ 389 for (f = 0; f < Nf; ++f) { 390 DM fdm = dm; 391 Vec fv = v; 392 IS fis; 393 char prefix[PETSC_MAX_PATH_LEN]; 394 const char *fname; 395 396 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 397 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 398 399 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 400 else prefix[0] = '\0'; 401 if (Nf > 1) { 402 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 403 PetscCall(VecGetSubVector(v, fis, &fv)); 404 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 405 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 406 } 407 for (comp = 0; comp < Nc; ++comp, ++w) { 408 PetscInt nmax = 2; 409 410 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 411 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 412 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 413 PetscCall(PetscDrawSetTitle(draw, title)); 414 415 /* TODO Get max and min only for this component */ 416 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 417 if (!flg) { 418 PetscCall(VecMin(fv, NULL, &vbound[0])); 419 PetscCall(VecMax(fv, NULL, &vbound[1])); 420 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 421 } 422 423 PetscCall(PetscDrawGetPopup(draw, &popup)); 424 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 425 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 426 PetscCall(VecGetArrayRead(fv, &array)); 427 for (c = cStart; c < cEnd; ++c) { 428 PetscScalar *coords = NULL, *a = NULL; 429 const PetscScalar *coords_arr; 430 PetscBool isDG; 431 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 432 433 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 434 if (a) { 435 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 436 color[1] = color[2] = color[3] = color[0]; 437 } else { 438 PetscScalar *vals = NULL; 439 PetscInt numVals, va; 440 441 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 442 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); 443 switch (numVals / Nc) { 444 case 3: /* P1 Triangle */ 445 case 4: /* P1 Quadrangle */ 446 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 447 break; 448 case 6: /* P2 Triangle */ 449 case 8: /* P2 Quadrangle */ 450 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 451 break; 452 default: 453 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 454 } 455 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 456 } 457 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 458 switch (numCoords) { 459 case 6: 460 case 12: /* Localized triangle */ 461 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])); 462 break; 463 case 8: 464 case 16: /* Localized quadrilateral */ 465 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])); 466 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])); 467 break; 468 default: 469 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 470 } 471 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 472 } 473 PetscCall(VecRestoreArrayRead(fv, &array)); 474 PetscCall(PetscDrawFlush(draw)); 475 PetscCall(PetscDrawPause(draw)); 476 PetscCall(PetscDrawSave(draw)); 477 } 478 if (Nf > 1) { 479 PetscCall(VecRestoreSubVector(v, fis, &fv)); 480 PetscCall(ISDestroy(&fis)); 481 PetscCall(DMDestroy(&fdm)); 482 } 483 } 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 488 { 489 DM dm; 490 PetscDraw draw; 491 PetscInt dim; 492 PetscBool isnull; 493 494 PetscFunctionBegin; 495 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 496 PetscCall(PetscDrawIsNull(draw, &isnull)); 497 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 498 499 PetscCall(VecGetDM(v, &dm)); 500 PetscCall(DMGetCoordinateDim(dm, &dim)); 501 switch (dim) { 502 case 1: 503 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 504 break; 505 case 2: 506 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 507 break; 508 default: 509 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 510 } 511 PetscFunctionReturn(PETSC_SUCCESS); 512 } 513 514 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 515 { 516 DM dm; 517 Vec locv; 518 const char *name; 519 PetscSection section; 520 PetscInt pStart, pEnd; 521 PetscInt numFields; 522 PetscViewerVTKFieldType ft; 523 524 PetscFunctionBegin; 525 PetscCall(VecGetDM(v, &dm)); 526 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 527 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 528 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 529 PetscCall(VecCopy(v, locv)); 530 PetscCall(DMGetLocalSection(dm, §ion)); 531 PetscCall(PetscSectionGetNumFields(section, &numFields)); 532 if (!numFields) { 533 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 534 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 535 } else { 536 PetscInt f; 537 538 for (f = 0; f < numFields; f++) { 539 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 540 if (ft == PETSC_VTK_INVALID) continue; 541 PetscCall(PetscObjectReference((PetscObject)locv)); 542 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 543 } 544 PetscCall(VecDestroy(&locv)); 545 } 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 550 { 551 DM dm; 552 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 553 554 PetscFunctionBegin; 555 PetscCall(VecGetDM(v, &dm)); 556 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 557 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 558 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 559 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 560 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 561 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 562 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 563 PetscInt i, numFields; 564 PetscObject fe; 565 PetscBool fem = PETSC_FALSE; 566 Vec locv = v; 567 const char *name; 568 PetscInt step; 569 PetscReal time; 570 571 PetscCall(DMGetNumFields(dm, &numFields)); 572 for (i = 0; i < numFields; i++) { 573 PetscCall(DMGetField(dm, i, NULL, &fe)); 574 if (fe->classid == PETSCFE_CLASSID) { 575 fem = PETSC_TRUE; 576 break; 577 } 578 } 579 if (fem) { 580 PetscObject isZero; 581 582 PetscCall(DMGetLocalVector(dm, &locv)); 583 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 584 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 585 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 586 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 587 PetscCall(VecCopy(v, locv)); 588 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 589 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 590 } 591 if (isvtk) { 592 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 593 } else if (ishdf5) { 594 #if defined(PETSC_HAVE_HDF5) 595 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 596 #else 597 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 598 #endif 599 } else if (isdraw) { 600 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 601 } else if (isglvis) { 602 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 603 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 604 PetscCall(VecView_GLVis(locv, viewer)); 605 } else if (iscgns) { 606 #if defined(PETSC_HAVE_CGNS) 607 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 608 #else 609 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 610 #endif 611 } 612 if (fem) { 613 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 614 PetscCall(DMRestoreLocalVector(dm, &locv)); 615 } 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 PetscFunctionReturn(PETSC_SUCCESS); 624 } 625 626 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 627 { 628 DM dm; 629 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 630 631 PetscFunctionBegin; 632 PetscCall(VecGetDM(v, &dm)); 633 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 634 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (isvtk || isdraw || isglvis || iscgns) { 641 Vec locv; 642 PetscObject isZero; 643 const char *name; 644 645 PetscCall(DMGetLocalVector(dm, &locv)); 646 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 647 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 648 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 649 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 650 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 651 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 652 PetscCall(VecView_Plex_Local(locv, viewer)); 653 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 654 PetscCall(DMRestoreLocalVector(dm, &locv)); 655 } else if (ishdf5) { 656 #if defined(PETSC_HAVE_HDF5) 657 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 658 #else 659 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 660 #endif 661 } else if (isexodusii) { 662 #if defined(PETSC_HAVE_EXODUSII) 663 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 664 #else 665 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 666 #endif 667 } else { 668 PetscBool isseq; 669 670 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 671 if (isseq) PetscCall(VecView_Seq(v, viewer)); 672 else PetscCall(VecView_MPI(v, viewer)); 673 } 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 678 { 679 DM dm; 680 MPI_Comm comm; 681 PetscViewerFormat format; 682 Vec v; 683 PetscBool isvtk, ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 688 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 689 PetscCall(PetscViewerGetFormat(viewer, &format)); 690 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 694 /* this need a better fix */ 695 if (dm->useNatural) { 696 if (dm->sfNatural) { 697 const char *vecname; 698 PetscInt n, nroots; 699 700 PetscCall(VecGetLocalSize(originalv, &n)); 701 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 702 if (n == nroots) { 703 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 704 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 705 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 706 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 707 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 708 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 709 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 710 } else v = originalv; 711 } else v = originalv; 712 713 if (ishdf5) { 714 #if defined(PETSC_HAVE_HDF5) 715 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 716 #else 717 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 718 #endif 719 } else if (isvtk) { 720 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 721 } else { 722 PetscBool isseq; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 725 if (isseq) PetscCall(VecView_Seq(v, viewer)); 726 else PetscCall(VecView_MPI(v, viewer)); 727 } 728 if (v != originalv) PetscCall(VecDestroy(&v)); 729 PetscFunctionReturn(PETSC_SUCCESS); 730 } 731 732 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 733 { 734 DM dm; 735 PetscBool ishdf5; 736 737 PetscFunctionBegin; 738 PetscCall(VecGetDM(v, &dm)); 739 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 740 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 741 if (ishdf5) { 742 DM dmBC; 743 Vec gv; 744 const char *name; 745 746 PetscCall(DMGetOutputDM(dm, &dmBC)); 747 PetscCall(DMGetGlobalVector(dmBC, &gv)); 748 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 749 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 750 PetscCall(VecLoad_Default(gv, viewer)); 751 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 752 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 753 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 754 } else PetscCall(VecLoad_Default(v, viewer)); 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 759 { 760 DM dm; 761 PetscBool ishdf5, isexodusii; 762 763 PetscFunctionBegin; 764 PetscCall(VecGetDM(v, &dm)); 765 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 766 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 768 if (ishdf5) { 769 #if defined(PETSC_HAVE_HDF5) 770 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 771 #else 772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 773 #endif 774 } else if (isexodusii) { 775 #if defined(PETSC_HAVE_EXODUSII) 776 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 777 #else 778 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 779 #endif 780 } else PetscCall(VecLoad_Default(v, viewer)); 781 PetscFunctionReturn(PETSC_SUCCESS); 782 } 783 784 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 785 { 786 DM dm; 787 PetscViewerFormat format; 788 PetscBool ishdf5; 789 790 PetscFunctionBegin; 791 PetscCall(VecGetDM(originalv, &dm)); 792 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 793 PetscCall(PetscViewerGetFormat(viewer, &format)); 794 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 795 if (format == PETSC_VIEWER_NATIVE) { 796 if (dm->useNatural) { 797 if (dm->sfNatural) { 798 if (ishdf5) { 799 #if defined(PETSC_HAVE_HDF5) 800 Vec v; 801 const char *vecname; 802 803 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 804 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 805 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 806 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 807 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 808 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 809 PetscCall(VecDestroy(&v)); 810 #else 811 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 812 #endif 813 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 814 } 815 } else PetscCall(VecLoad_Default(originalv, viewer)); 816 } 817 PetscFunctionReturn(PETSC_SUCCESS); 818 } 819 820 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 821 { 822 PetscSection coordSection; 823 Vec coordinates; 824 DMLabel depthLabel, celltypeLabel; 825 const char *name[4]; 826 const PetscScalar *a; 827 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetDimension(dm, &dim)); 831 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 832 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 833 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 834 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 835 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 836 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 837 PetscCall(VecGetArrayRead(coordinates, &a)); 838 name[0] = "vertex"; 839 name[1] = "edge"; 840 name[dim - 1] = "face"; 841 name[dim] = "cell"; 842 for (c = cStart; c < cEnd; ++c) { 843 PetscInt *closure = NULL; 844 PetscInt closureSize, cl, ct; 845 846 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 847 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 848 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 849 PetscCall(PetscViewerASCIIPushTab(viewer)); 850 for (cl = 0; cl < closureSize * 2; cl += 2) { 851 PetscInt point = closure[cl], depth, dof, off, d, p; 852 853 if ((point < pStart) || (point >= pEnd)) continue; 854 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 855 if (!dof) continue; 856 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 857 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 859 for (p = 0; p < dof / dim; ++p) { 860 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 861 for (d = 0; d < dim; ++d) { 862 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 863 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 864 } 865 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 866 } 867 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 868 } 869 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 870 PetscCall(PetscViewerASCIIPopTab(viewer)); 871 } 872 PetscCall(VecRestoreArrayRead(coordinates, &a)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875 876 typedef enum { 877 CS_CARTESIAN, 878 CS_POLAR, 879 CS_CYLINDRICAL, 880 CS_SPHERICAL 881 } CoordSystem; 882 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 883 884 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 885 { 886 PetscInt i; 887 888 PetscFunctionBegin; 889 if (dim > 3) { 890 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 891 } else { 892 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 893 894 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 895 switch (cs) { 896 case CS_CARTESIAN: 897 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 898 break; 899 case CS_POLAR: 900 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 901 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 902 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 903 break; 904 case CS_CYLINDRICAL: 905 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 906 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 907 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 908 trcoords[2] = coords[2]; 909 break; 910 case CS_SPHERICAL: 911 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 912 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 913 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 914 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 915 break; 916 } 917 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 923 { 924 DM_Plex *mesh = (DM_Plex *)dm->data; 925 DM cdm, cdmCell; 926 PetscSection coordSection, coordSectionCell; 927 Vec coordinates, coordinatesCell; 928 PetscViewerFormat format; 929 930 PetscFunctionBegin; 931 PetscCall(PetscViewerGetFormat(viewer, &format)); 932 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 933 const char *name; 934 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 935 PetscInt pStart, pEnd, p, numLabels, l; 936 PetscMPIInt rank, size; 937 938 PetscCall(DMGetCoordinateDM(dm, &cdm)); 939 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 940 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 941 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 942 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 943 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 944 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 945 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 946 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 947 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 948 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 951 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 952 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 953 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 954 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 955 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 956 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 957 for (p = pStart; p < pEnd; ++p) { 958 PetscInt dof, off, s; 959 960 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 961 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 962 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 963 } 964 PetscCall(PetscViewerFlush(viewer)); 965 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 966 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 967 for (p = pStart; p < pEnd; ++p) { 968 PetscInt dof, off, c; 969 970 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 971 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 972 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])); 973 } 974 PetscCall(PetscViewerFlush(viewer)); 975 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 976 if (coordSection && coordinates) { 977 CoordSystem cs = CS_CARTESIAN; 978 const PetscScalar *array, *arrayCell = NULL; 979 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 980 PetscMPIInt rank; 981 const char *name; 982 983 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 985 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 986 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 987 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 988 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 989 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 990 pStart = PetscMin(pvStart, pcStart); 991 pEnd = PetscMax(pvEnd, pcEnd); 992 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 994 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 995 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 996 997 PetscCall(VecGetArrayRead(coordinates, &array)); 998 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 999 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1000 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 1001 for (p = pStart; p < pEnd; ++p) { 1002 PetscInt dof, off; 1003 1004 if (p >= pvStart && p < pvEnd) { 1005 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 1006 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 1007 if (dof) { 1008 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1009 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 1010 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1011 } 1012 } 1013 if (cdmCell && p >= pcStart && p < pcEnd) { 1014 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 1015 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 1016 if (dof) { 1017 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 1018 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 1019 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 1020 } 1021 } 1022 } 1023 PetscCall(PetscViewerFlush(viewer)); 1024 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1025 PetscCall(VecRestoreArrayRead(coordinates, &array)); 1026 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 1027 } 1028 PetscCall(DMGetNumLabels(dm, &numLabels)); 1029 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1030 for (l = 0; l < numLabels; ++l) { 1031 DMLabel label; 1032 PetscBool isdepth; 1033 const char *name; 1034 1035 PetscCall(DMGetLabelName(dm, l, &name)); 1036 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 1037 if (isdepth) continue; 1038 PetscCall(DMGetLabel(dm, name, &label)); 1039 PetscCall(DMLabelView(label, viewer)); 1040 } 1041 if (size > 1) { 1042 PetscSF sf; 1043 1044 PetscCall(DMGetPointSF(dm, &sf)); 1045 PetscCall(PetscSFView(sf, viewer)); 1046 } 1047 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 1048 PetscCall(PetscViewerFlush(viewer)); 1049 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 1050 const char *name, *color; 1051 const char *defcolors[3] = {"gray", "orange", "green"}; 1052 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 1053 char lname[PETSC_MAX_PATH_LEN]; 1054 PetscReal scale = 2.0; 1055 PetscReal tikzscale = 1.0; 1056 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 1057 double tcoords[3]; 1058 PetscScalar *coords; 1059 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 1060 PetscMPIInt rank, size; 1061 char **names, **colors, **lcolors; 1062 PetscBool flg, lflg; 1063 PetscBT wp = NULL; 1064 PetscInt pEnd, pStart; 1065 1066 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 1068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1069 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 1070 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 1071 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 1072 PetscCall(DMGetDimension(dm, &dim)); 1073 PetscCall(DMPlexGetDepth(dm, &depth)); 1074 PetscCall(DMGetNumLabels(dm, &numLabels)); 1075 numLabels = PetscMax(numLabels, 10); 1076 numColors = 10; 1077 numLColors = 10; 1078 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 1079 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 1080 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 1081 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 1082 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 1083 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 1084 n = 4; 1085 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 1086 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1087 n = 4; 1088 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 1089 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 1090 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 1091 if (!useLabels) numLabels = 0; 1092 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 1093 if (!useColors) { 1094 numColors = 3; 1095 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 1096 } 1097 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 1098 if (!useColors) { 1099 numLColors = 4; 1100 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 1101 } 1102 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 1103 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1104 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1105 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1106 if (depth < dim) plotEdges = PETSC_FALSE; 1107 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1108 1109 /* filter points with labelvalue != labeldefaultvalue */ 1110 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1111 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1112 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1113 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1114 if (lflg) { 1115 DMLabel lbl; 1116 1117 PetscCall(DMGetLabel(dm, lname, &lbl)); 1118 if (lbl) { 1119 PetscInt val, defval; 1120 1121 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1122 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1123 for (c = pStart; c < pEnd; c++) { 1124 PetscInt *closure = NULL; 1125 PetscInt closureSize; 1126 1127 PetscCall(DMLabelGetValue(lbl, c, &val)); 1128 if (val == defval) continue; 1129 1130 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1131 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1132 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1133 } 1134 } 1135 } 1136 1137 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1138 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1139 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1140 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1141 \\documentclass[tikz]{standalone}\n\n\ 1142 \\usepackage{pgflibraryshapes}\n\ 1143 \\usetikzlibrary{backgrounds}\n\ 1144 \\usetikzlibrary{arrows}\n\ 1145 \\begin{document}\n")); 1146 if (size > 1) { 1147 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1148 for (p = 0; p < size; ++p) { 1149 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1151 } 1152 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1153 } 1154 if (drawHasse) { 1155 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1156 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1158 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1159 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1160 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1161 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1162 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1163 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1164 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1165 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1166 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1167 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1168 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1169 } 1170 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1171 1172 /* Plot vertices */ 1173 PetscCall(VecGetArray(coordinates, &coords)); 1174 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1175 for (v = vStart; v < vEnd; ++v) { 1176 PetscInt off, dof, d; 1177 PetscBool isLabeled = PETSC_FALSE; 1178 1179 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1180 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1181 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1182 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1183 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1184 for (d = 0; d < dof; ++d) { 1185 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1186 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1187 } 1188 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1189 if (dim == 3) { 1190 PetscReal tmp = tcoords[1]; 1191 tcoords[1] = tcoords[2]; 1192 tcoords[2] = -tmp; 1193 } 1194 for (d = 0; d < dof; ++d) { 1195 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1196 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1197 } 1198 if (drawHasse) color = colors[0 % numColors]; 1199 else color = colors[rank % numColors]; 1200 for (l = 0; l < numLabels; ++l) { 1201 PetscInt val; 1202 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1203 if (val >= 0) { 1204 color = lcolors[l % numLColors]; 1205 isLabeled = PETSC_TRUE; 1206 break; 1207 } 1208 } 1209 if (drawNumbers[0]) { 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1211 } else if (drawColors[0]) { 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1213 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1214 } 1215 PetscCall(VecRestoreArray(coordinates, &coords)); 1216 PetscCall(PetscViewerFlush(viewer)); 1217 /* Plot edges */ 1218 if (plotEdges) { 1219 PetscCall(VecGetArray(coordinates, &coords)); 1220 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1221 for (e = eStart; e < eEnd; ++e) { 1222 const PetscInt *cone; 1223 PetscInt coneSize, offA, offB, dof, d; 1224 1225 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1226 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1227 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1228 PetscCall(DMPlexGetCone(dm, e, &cone)); 1229 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1230 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1231 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1232 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1233 for (d = 0; d < dof; ++d) { 1234 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1235 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1236 } 1237 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1238 if (dim == 3) { 1239 PetscReal tmp = tcoords[1]; 1240 tcoords[1] = tcoords[2]; 1241 tcoords[2] = -tmp; 1242 } 1243 for (d = 0; d < dof; ++d) { 1244 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1245 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1246 } 1247 if (drawHasse) color = colors[1 % numColors]; 1248 else color = colors[rank % numColors]; 1249 for (l = 0; l < numLabels; ++l) { 1250 PetscInt val; 1251 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1252 if (val >= 0) { 1253 color = lcolors[l % numLColors]; 1254 break; 1255 } 1256 } 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1258 } 1259 PetscCall(VecRestoreArray(coordinates, &coords)); 1260 PetscCall(PetscViewerFlush(viewer)); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1262 } 1263 /* Plot cells */ 1264 if (dim == 3 || !drawNumbers[1]) { 1265 for (e = eStart; e < eEnd; ++e) { 1266 const PetscInt *cone; 1267 1268 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1269 color = colors[rank % numColors]; 1270 for (l = 0; l < numLabels; ++l) { 1271 PetscInt val; 1272 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1273 if (val >= 0) { 1274 color = lcolors[l % numLColors]; 1275 break; 1276 } 1277 } 1278 PetscCall(DMPlexGetCone(dm, e, &cone)); 1279 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1280 } 1281 } else { 1282 DMPolytopeType ct; 1283 1284 /* Drawing a 2D polygon */ 1285 for (c = cStart; c < cEnd; ++c) { 1286 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1287 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1288 if (DMPolytopeTypeIsHybrid(ct)) { 1289 const PetscInt *cone; 1290 PetscInt coneSize, e; 1291 1292 PetscCall(DMPlexGetCone(dm, c, &cone)); 1293 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1294 for (e = 0; e < coneSize; ++e) { 1295 const PetscInt *econe; 1296 1297 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1298 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)); 1299 } 1300 } else { 1301 PetscInt *closure = NULL; 1302 PetscInt closureSize, Nv = 0, v; 1303 1304 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1305 for (p = 0; p < closureSize * 2; p += 2) { 1306 const PetscInt point = closure[p]; 1307 1308 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1309 } 1310 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1311 for (v = 0; v <= Nv; ++v) { 1312 const PetscInt vertex = closure[v % Nv]; 1313 1314 if (v > 0) { 1315 if (plotEdges) { 1316 const PetscInt *edge; 1317 PetscInt endpoints[2], ne; 1318 1319 endpoints[0] = closure[v - 1]; 1320 endpoints[1] = vertex; 1321 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1322 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1323 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1324 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1325 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1326 } 1327 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1328 } 1329 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1330 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1331 } 1332 } 1333 } 1334 for (c = cStart; c < cEnd; ++c) { 1335 double ccoords[3] = {0.0, 0.0, 0.0}; 1336 PetscBool isLabeled = PETSC_FALSE; 1337 PetscScalar *cellCoords = NULL; 1338 const PetscScalar *array; 1339 PetscInt numCoords, cdim, d; 1340 PetscBool isDG; 1341 1342 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1343 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1344 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1345 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1346 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1347 for (p = 0; p < numCoords / cdim; ++p) { 1348 for (d = 0; d < cdim; ++d) { 1349 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1350 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1351 } 1352 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1353 if (cdim == 3) { 1354 PetscReal tmp = tcoords[1]; 1355 tcoords[1] = tcoords[2]; 1356 tcoords[2] = -tmp; 1357 } 1358 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1359 } 1360 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1361 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1362 for (d = 0; d < cdim; ++d) { 1363 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1364 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1365 } 1366 if (drawHasse) color = colors[depth % numColors]; 1367 else color = colors[rank % numColors]; 1368 for (l = 0; l < numLabels; ++l) { 1369 PetscInt val; 1370 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1371 if (val >= 0) { 1372 color = lcolors[l % numLColors]; 1373 isLabeled = PETSC_TRUE; 1374 break; 1375 } 1376 } 1377 if (drawNumbers[dim]) { 1378 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1379 } else if (drawColors[dim]) { 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1381 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1382 } 1383 if (drawHasse) { 1384 color = colors[depth % numColors]; 1385 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1386 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1387 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1388 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1389 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1390 1391 color = colors[1 % numColors]; 1392 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1393 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1394 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1395 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1397 1398 color = colors[0 % numColors]; 1399 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1404 1405 for (p = pStart; p < pEnd; ++p) { 1406 const PetscInt *cone; 1407 PetscInt coneSize, cp; 1408 1409 PetscCall(DMPlexGetCone(dm, p, &cone)); 1410 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1411 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1412 } 1413 } 1414 PetscCall(PetscViewerFlush(viewer)); 1415 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1416 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1417 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1418 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1419 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1420 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1421 PetscCall(PetscFree3(names, colors, lcolors)); 1422 PetscCall(PetscBTDestroy(&wp)); 1423 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1424 Vec cown, acown; 1425 VecScatter sct; 1426 ISLocalToGlobalMapping g2l; 1427 IS gid, acis; 1428 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1429 MPI_Group ggroup, ngroup; 1430 PetscScalar *array, nid; 1431 const PetscInt *idxs; 1432 PetscInt *idxs2, *start, *adjacency, *work; 1433 PetscInt64 lm[3], gm[3]; 1434 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1435 PetscMPIInt d1, d2, rank; 1436 1437 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1438 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1439 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1440 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1441 #endif 1442 if (ncomm != MPI_COMM_NULL) { 1443 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1444 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1445 d1 = 0; 1446 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1447 nid = d2; 1448 PetscCallMPI(MPI_Group_free(&ggroup)); 1449 PetscCallMPI(MPI_Group_free(&ngroup)); 1450 PetscCallMPI(MPI_Comm_free(&ncomm)); 1451 } else nid = 0.0; 1452 1453 /* Get connectivity */ 1454 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1455 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1456 1457 /* filter overlapped local cells */ 1458 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1459 PetscCall(ISGetIndices(gid, &idxs)); 1460 PetscCall(ISGetLocalSize(gid, &cum)); 1461 PetscCall(PetscMalloc1(cum, &idxs2)); 1462 for (c = cStart, cum = 0; c < cEnd; c++) { 1463 if (idxs[c - cStart] < 0) continue; 1464 idxs2[cum++] = idxs[c - cStart]; 1465 } 1466 PetscCall(ISRestoreIndices(gid, &idxs)); 1467 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1468 PetscCall(ISDestroy(&gid)); 1469 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1470 1471 /* support for node-aware cell locality */ 1472 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1473 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1474 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1475 PetscCall(VecGetArray(cown, &array)); 1476 for (c = 0; c < numVertices; c++) array[c] = nid; 1477 PetscCall(VecRestoreArray(cown, &array)); 1478 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1479 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1480 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1481 PetscCall(ISDestroy(&acis)); 1482 PetscCall(VecScatterDestroy(&sct)); 1483 PetscCall(VecDestroy(&cown)); 1484 1485 /* compute edgeCut */ 1486 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1487 PetscCall(PetscMalloc1(cum, &work)); 1488 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1489 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1490 PetscCall(ISDestroy(&gid)); 1491 PetscCall(VecGetArray(acown, &array)); 1492 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1493 PetscInt totl; 1494 1495 totl = start[c + 1] - start[c]; 1496 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1497 for (i = 0; i < totl; i++) { 1498 if (work[i] < 0) { 1499 ect += 1; 1500 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1501 } 1502 } 1503 } 1504 PetscCall(PetscFree(work)); 1505 PetscCall(VecRestoreArray(acown, &array)); 1506 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1507 lm[1] = -numVertices; 1508 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1510 lm[0] = ect; /* edgeCut */ 1511 lm[1] = ectn; /* node-aware edgeCut */ 1512 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1513 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1514 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1515 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1516 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1517 #else 1518 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1519 #endif 1520 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1521 PetscCall(PetscFree(start)); 1522 PetscCall(PetscFree(adjacency)); 1523 PetscCall(VecDestroy(&acown)); 1524 } else { 1525 const char *name; 1526 PetscInt *sizes, *hybsizes, *ghostsizes; 1527 PetscInt locDepth, depth, cellHeight, dim, d; 1528 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1529 PetscInt numLabels, l, maxSize = 17; 1530 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1531 MPI_Comm comm; 1532 PetscMPIInt size, rank; 1533 1534 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1535 PetscCallMPI(MPI_Comm_size(comm, &size)); 1536 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1537 PetscCall(DMGetDimension(dm, &dim)); 1538 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1539 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1540 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1541 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1542 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1543 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1544 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1545 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1546 gcNum = gcEnd - gcStart; 1547 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1548 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1549 for (d = 0; d <= depth; d++) { 1550 PetscInt Nc[2] = {0, 0}, ict; 1551 1552 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1553 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1554 ict = ct0; 1555 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1556 ct0 = (DMPolytopeType)ict; 1557 for (p = pStart; p < pEnd; ++p) { 1558 DMPolytopeType ct; 1559 1560 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1561 if (ct == ct0) ++Nc[0]; 1562 else ++Nc[1]; 1563 } 1564 if (size < maxSize) { 1565 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1566 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1567 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1568 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1569 for (p = 0; p < size; ++p) { 1570 if (rank == 0) { 1571 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1572 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1573 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1574 } 1575 } 1576 } else { 1577 PetscInt locMinMax[2]; 1578 1579 locMinMax[0] = Nc[0] + Nc[1]; 1580 locMinMax[1] = Nc[0] + Nc[1]; 1581 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1582 locMinMax[0] = Nc[1]; 1583 locMinMax[1] = Nc[1]; 1584 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1585 if (d == depth) { 1586 locMinMax[0] = gcNum; 1587 locMinMax[1] = gcNum; 1588 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1589 } 1590 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1591 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1592 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1593 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1594 } 1595 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1596 } 1597 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1598 { 1599 const PetscReal *maxCell; 1600 const PetscReal *L; 1601 PetscBool localized; 1602 1603 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1604 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1605 if (L || localized) { 1606 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1607 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1608 if (L) { 1609 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1610 for (d = 0; d < dim; ++d) { 1611 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1612 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1613 } 1614 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1615 } 1616 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1617 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1618 } 1619 } 1620 PetscCall(DMGetNumLabels(dm, &numLabels)); 1621 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1622 for (l = 0; l < numLabels; ++l) { 1623 DMLabel label; 1624 const char *name; 1625 IS valueIS; 1626 const PetscInt *values; 1627 PetscInt numValues, v; 1628 1629 PetscCall(DMGetLabelName(dm, l, &name)); 1630 PetscCall(DMGetLabel(dm, name, &label)); 1631 PetscCall(DMLabelGetNumValues(label, &numValues)); 1632 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1633 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1634 PetscCall(ISGetIndices(valueIS, &values)); 1635 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1636 for (v = 0; v < numValues; ++v) { 1637 PetscInt size; 1638 1639 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1640 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1641 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1642 } 1643 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1644 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1645 PetscCall(ISRestoreIndices(valueIS, &values)); 1646 PetscCall(ISDestroy(&valueIS)); 1647 } 1648 { 1649 char **labelNames; 1650 PetscInt Nl = numLabels; 1651 PetscBool flg; 1652 1653 PetscCall(PetscMalloc1(Nl, &labelNames)); 1654 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1655 for (l = 0; l < Nl; ++l) { 1656 DMLabel label; 1657 1658 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1659 if (flg) { 1660 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1661 PetscCall(DMLabelView(label, viewer)); 1662 } 1663 PetscCall(PetscFree(labelNames[l])); 1664 } 1665 PetscCall(PetscFree(labelNames)); 1666 } 1667 /* If no fields are specified, people do not want to see adjacency */ 1668 if (dm->Nf) { 1669 PetscInt f; 1670 1671 for (f = 0; f < dm->Nf; ++f) { 1672 const char *name; 1673 1674 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1675 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1676 PetscCall(PetscViewerASCIIPushTab(viewer)); 1677 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1678 if (dm->fields[f].adjacency[0]) { 1679 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1680 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1681 } else { 1682 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1683 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1684 } 1685 PetscCall(PetscViewerASCIIPopTab(viewer)); 1686 } 1687 } 1688 PetscCall(DMGetCoarseDM(dm, &cdm)); 1689 if (cdm) { 1690 PetscCall(PetscViewerASCIIPushTab(viewer)); 1691 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1692 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1693 PetscCall(PetscViewerASCIIPopTab(viewer)); 1694 } 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1700 { 1701 DMPolytopeType ct; 1702 PetscMPIInt rank; 1703 PetscInt cdim; 1704 1705 PetscFunctionBegin; 1706 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1707 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1708 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1709 switch (ct) { 1710 case DM_POLYTOPE_SEGMENT: 1711 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1712 switch (cdim) { 1713 case 1: { 1714 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1715 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1716 1717 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1718 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1719 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1720 } break; 1721 case 2: { 1722 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1723 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1724 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1725 1726 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1727 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)); 1728 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)); 1729 } break; 1730 default: 1731 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1732 } 1733 break; 1734 case DM_POLYTOPE_TRIANGLE: 1735 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)); 1736 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1737 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1738 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1739 break; 1740 case DM_POLYTOPE_QUADRILATERAL: 1741 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)); 1742 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)); 1743 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1744 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1745 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1746 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1747 break; 1748 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1749 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)); 1750 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)); 1751 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1752 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1753 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1754 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1755 break; 1756 case DM_POLYTOPE_FV_GHOST: 1757 break; 1758 default: 1759 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1760 } 1761 PetscFunctionReturn(PETSC_SUCCESS); 1762 } 1763 1764 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1765 { 1766 DMPolytopeType ct; 1767 PetscReal centroid[2] = {0., 0.}; 1768 PetscMPIInt rank; 1769 PetscInt fillColor, v, e, d; 1770 1771 PetscFunctionBegin; 1772 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1773 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1774 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1775 switch (ct) { 1776 case DM_POLYTOPE_TRIANGLE: { 1777 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1778 1779 for (v = 0; v < 3; ++v) { 1780 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1781 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1782 } 1783 for (e = 0; e < 3; ++e) { 1784 refCoords[0] = refVertices[e * 2 + 0]; 1785 refCoords[1] = refVertices[e * 2 + 1]; 1786 for (d = 1; d <= edgeDiv; ++d) { 1787 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1788 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1789 } 1790 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1791 for (d = 0; d < edgeDiv; ++d) { 1792 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)); 1793 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1794 } 1795 } 1796 } break; 1797 default: 1798 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1799 } 1800 PetscFunctionReturn(PETSC_SUCCESS); 1801 } 1802 1803 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1804 { 1805 PetscDraw draw; 1806 DM cdm; 1807 PetscSection coordSection; 1808 Vec coordinates; 1809 PetscReal xyl[3], xyr[3]; 1810 PetscReal *refCoords, *edgeCoords; 1811 PetscBool isnull, drawAffine = PETSC_TRUE; 1812 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1813 1814 PetscFunctionBegin; 1815 PetscCall(DMGetCoordinateDim(dm, &dim)); 1816 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1817 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1818 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1819 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1820 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1821 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1822 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1823 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1824 1825 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1826 PetscCall(PetscDrawIsNull(draw, &isnull)); 1827 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1828 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1829 1830 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1831 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1832 PetscCall(PetscDrawClear(draw)); 1833 1834 for (c = cStart; c < cEnd; ++c) { 1835 PetscScalar *coords = NULL; 1836 const PetscScalar *coords_arr; 1837 PetscInt numCoords; 1838 PetscBool isDG; 1839 1840 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1841 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1842 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1843 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1844 } 1845 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1846 PetscCall(PetscDrawFlush(draw)); 1847 PetscCall(PetscDrawPause(draw)); 1848 PetscCall(PetscDrawSave(draw)); 1849 PetscFunctionReturn(PETSC_SUCCESS); 1850 } 1851 1852 static PetscErrorCode DMPlexCreateHighOrderSurrogate_Internal(DM dm, DM *hdm) 1853 { 1854 DM odm = dm, rdm = dm, cdm; 1855 PetscFE fe; 1856 PetscSpace sp; 1857 PetscClassId id; 1858 PetscInt degree; 1859 PetscBool hoView = PETSC_TRUE; 1860 1861 PetscFunctionBegin; 1862 PetscObjectOptionsBegin((PetscObject)dm); 1863 PetscCall(PetscOptionsBool("-dm_plex_high_order_view", "Subsample to view meshes with high order coordinates", "DMPlexCreateHighOrderSurrogate_Internal", hoView, &hoView, NULL)); 1864 PetscOptionsEnd(); 1865 PetscCall(PetscObjectReference((PetscObject)dm)); 1866 *hdm = dm; 1867 if (!hoView) PetscFunctionReturn(PETSC_SUCCESS); 1868 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1869 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1870 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1871 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1872 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1873 PetscCall(PetscSpaceGetDegree(sp, °ree, NULL)); 1874 for (PetscInt r = 0, rd = PetscCeilReal(((PetscReal)degree) / 2.); r < (PetscInt)PetscCeilReal(PetscLog2Real(degree)); ++r, rd = PetscCeilReal(((PetscReal)rd) / 2.)) { 1875 DM cdm, rcdm; 1876 Mat In; 1877 Vec cl, rcl; 1878 1879 PetscCall(DMRefine(odm, PetscObjectComm((PetscObject)odm), &rdm)); 1880 if (rd > 1) PetscCall(DMPlexCreateCoordinateSpace(rdm, rd, PETSC_FALSE, NULL)); 1881 PetscCall(PetscObjectSetName((PetscObject)rdm, "Refined Mesh with Linear Coordinates")); 1882 PetscCall(DMGetCoordinateDM(odm, &cdm)); 1883 PetscCall(DMGetCoordinateDM(rdm, &rcdm)); 1884 PetscCall(DMGetCoordinatesLocal(odm, &cl)); 1885 PetscCall(DMGetCoordinatesLocal(rdm, &rcl)); 1886 PetscCall(DMSetCoarseDM(rcdm, cdm)); 1887 PetscCall(DMCreateInterpolation(cdm, rcdm, &In, NULL)); 1888 PetscCall(MatMult(In, cl, rcl)); 1889 PetscCall(MatDestroy(&In)); 1890 PetscCall(DMSetCoordinatesLocal(rdm, rcl)); 1891 PetscCall(DMDestroy(&odm)); 1892 odm = rdm; 1893 } 1894 *hdm = rdm; 1895 PetscFunctionReturn(PETSC_SUCCESS); 1896 } 1897 1898 #if defined(PETSC_HAVE_EXODUSII) 1899 #include <exodusII.h> 1900 #include <petscviewerexodusii.h> 1901 #endif 1902 1903 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1904 { 1905 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1906 char name[PETSC_MAX_PATH_LEN]; 1907 1908 PetscFunctionBegin; 1909 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1910 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1911 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1912 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1913 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1914 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1916 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1917 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1918 if (iascii) { 1919 PetscViewerFormat format; 1920 PetscCall(PetscViewerGetFormat(viewer, &format)); 1921 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1922 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1923 } else if (ishdf5) { 1924 #if defined(PETSC_HAVE_HDF5) 1925 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1926 #else 1927 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1928 #endif 1929 } else if (isvtk) { 1930 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1931 } else if (isdraw) { 1932 DM hdm; 1933 1934 PetscCall(DMPlexCreateHighOrderSurrogate_Internal(dm, &hdm)); 1935 PetscCall(DMPlexView_Draw(hdm, viewer)); 1936 PetscCall(DMDestroy(&hdm)); 1937 } else if (isglvis) { 1938 PetscCall(DMPlexView_GLVis(dm, viewer)); 1939 #if defined(PETSC_HAVE_EXODUSII) 1940 } else if (isexodus) { 1941 /* 1942 exodusII requires that all sets be part of exactly one cell set. 1943 If the dm does not have a "Cell Sets" label defined, we create one 1944 with ID 1, containing all cells. 1945 Note that if the Cell Sets label is defined but does not cover all cells, 1946 we may still have a problem. This should probably be checked here or in the viewer; 1947 */ 1948 PetscInt numCS; 1949 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1950 if (!numCS) { 1951 PetscInt cStart, cEnd, c; 1952 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1953 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1954 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1955 } 1956 PetscCall(DMView_PlexExodusII(dm, viewer)); 1957 #endif 1958 #if defined(PETSC_HAVE_CGNS) 1959 } else if (iscgns) { 1960 PetscCall(DMView_PlexCGNS(dm, viewer)); 1961 #endif 1962 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1963 /* Optionally view the partition */ 1964 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1965 if (flg) { 1966 Vec ranks; 1967 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1968 PetscCall(VecView(ranks, viewer)); 1969 PetscCall(VecDestroy(&ranks)); 1970 } 1971 /* Optionally view a label */ 1972 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1973 if (flg) { 1974 DMLabel label; 1975 Vec val; 1976 1977 PetscCall(DMGetLabel(dm, name, &label)); 1978 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1979 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1980 PetscCall(VecView(val, viewer)); 1981 PetscCall(VecDestroy(&val)); 1982 } 1983 PetscFunctionReturn(PETSC_SUCCESS); 1984 } 1985 1986 /*@ 1987 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1988 1989 Collective 1990 1991 Input Parameters: 1992 + dm - The `DM` whose topology is to be saved 1993 - viewer - The `PetscViewer` to save it in 1994 1995 Level: advanced 1996 1997 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1998 @*/ 1999 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 2000 { 2001 PetscBool ishdf5; 2002 2003 PetscFunctionBegin; 2004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2005 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2006 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2007 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2008 if (ishdf5) { 2009 #if defined(PETSC_HAVE_HDF5) 2010 PetscViewerFormat format; 2011 PetscCall(PetscViewerGetFormat(viewer, &format)); 2012 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2013 IS globalPointNumbering; 2014 2015 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2016 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2017 PetscCall(ISDestroy(&globalPointNumbering)); 2018 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2019 #else 2020 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2021 #endif 2022 } 2023 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 2024 PetscFunctionReturn(PETSC_SUCCESS); 2025 } 2026 2027 /*@ 2028 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 2029 2030 Collective 2031 2032 Input Parameters: 2033 + dm - The `DM` whose coordinates are to be saved 2034 - viewer - The `PetscViewer` for saving 2035 2036 Level: advanced 2037 2038 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 2039 @*/ 2040 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2048 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2049 if (ishdf5) { 2050 #if defined(PETSC_HAVE_HDF5) 2051 PetscViewerFormat format; 2052 PetscCall(PetscViewerGetFormat(viewer, &format)); 2053 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2054 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 2055 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 2056 #else 2057 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2058 #endif 2059 } 2060 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 2061 PetscFunctionReturn(PETSC_SUCCESS); 2062 } 2063 2064 /*@ 2065 DMPlexLabelsView - Saves `DMPLEX` labels into a file 2066 2067 Collective 2068 2069 Input Parameters: 2070 + dm - The `DM` whose labels are to be saved 2071 - viewer - The `PetscViewer` for saving 2072 2073 Level: advanced 2074 2075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 2076 @*/ 2077 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 2078 { 2079 PetscBool ishdf5; 2080 2081 PetscFunctionBegin; 2082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2083 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2084 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2085 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2086 if (ishdf5) { 2087 #if defined(PETSC_HAVE_HDF5) 2088 IS globalPointNumbering; 2089 PetscViewerFormat format; 2090 2091 PetscCall(PetscViewerGetFormat(viewer, &format)); 2092 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2093 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 2094 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 2095 PetscCall(ISDestroy(&globalPointNumbering)); 2096 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2097 #else 2098 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2099 #endif 2100 } 2101 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 2102 PetscFunctionReturn(PETSC_SUCCESS); 2103 } 2104 2105 /*@ 2106 DMPlexSectionView - Saves a section associated with a `DMPLEX` 2107 2108 Collective 2109 2110 Input Parameters: 2111 + dm - The `DM` that contains the topology on which the section to be saved is defined 2112 . viewer - The `PetscViewer` for saving 2113 - sectiondm - The `DM` that contains the section to be saved 2114 2115 Level: advanced 2116 2117 Notes: 2118 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. 2119 2120 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 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. 2121 2122 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 2123 @*/ 2124 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 2125 { 2126 PetscBool ishdf5; 2127 2128 PetscFunctionBegin; 2129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2130 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2131 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2132 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2133 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 2134 if (ishdf5) { 2135 #if defined(PETSC_HAVE_HDF5) 2136 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 2137 #else 2138 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2139 #endif 2140 } 2141 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 2142 PetscFunctionReturn(PETSC_SUCCESS); 2143 } 2144 2145 /*@ 2146 DMPlexGlobalVectorView - Saves a global vector 2147 2148 Collective 2149 2150 Input Parameters: 2151 + dm - The `DM` that represents the topology 2152 . viewer - The `PetscViewer` to save data with 2153 . sectiondm - The `DM` that contains the global section on which vec is defined 2154 - vec - The global vector to be saved 2155 2156 Level: advanced 2157 2158 Notes: 2159 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 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. 2160 2161 Calling sequence: 2162 .vb 2163 DMCreate(PETSC_COMM_WORLD, &dm); 2164 DMSetType(dm, DMPLEX); 2165 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2166 DMClone(dm, §iondm); 2167 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2168 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2169 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2170 PetscSectionSetChart(section, pStart, pEnd); 2171 PetscSectionSetUp(section); 2172 DMSetLocalSection(sectiondm, section); 2173 PetscSectionDestroy(§ion); 2174 DMGetGlobalVector(sectiondm, &vec); 2175 PetscObjectSetName((PetscObject)vec, "vec_name"); 2176 DMPlexTopologyView(dm, viewer); 2177 DMPlexSectionView(dm, viewer, sectiondm); 2178 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2179 DMRestoreGlobalVector(sectiondm, &vec); 2180 DMDestroy(§iondm); 2181 DMDestroy(&dm); 2182 .ve 2183 2184 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2185 @*/ 2186 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2187 { 2188 PetscBool ishdf5; 2189 2190 PetscFunctionBegin; 2191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2192 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2193 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2194 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2195 /* Check consistency */ 2196 { 2197 PetscSection section; 2198 PetscBool includesConstraints; 2199 PetscInt m, m1; 2200 2201 PetscCall(VecGetLocalSize(vec, &m1)); 2202 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2203 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2204 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2205 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2206 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2207 } 2208 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2209 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2210 if (ishdf5) { 2211 #if defined(PETSC_HAVE_HDF5) 2212 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2213 #else 2214 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2215 #endif 2216 } 2217 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2218 PetscFunctionReturn(PETSC_SUCCESS); 2219 } 2220 2221 /*@ 2222 DMPlexLocalVectorView - Saves a local vector 2223 2224 Collective 2225 2226 Input Parameters: 2227 + dm - The `DM` that represents the topology 2228 . viewer - The `PetscViewer` to save data with 2229 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2230 - vec - The local vector to be saved 2231 2232 Level: advanced 2233 2234 Note: 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 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 Calling sequence: 2238 .vb 2239 DMCreate(PETSC_COMM_WORLD, &dm); 2240 DMSetType(dm, DMPLEX); 2241 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2242 DMClone(dm, §iondm); 2243 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2244 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2245 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2246 PetscSectionSetChart(section, pStart, pEnd); 2247 PetscSectionSetUp(section); 2248 DMSetLocalSection(sectiondm, section); 2249 DMGetLocalVector(sectiondm, &vec); 2250 PetscObjectSetName((PetscObject)vec, "vec_name"); 2251 DMPlexTopologyView(dm, viewer); 2252 DMPlexSectionView(dm, viewer, sectiondm); 2253 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2254 DMRestoreLocalVector(sectiondm, &vec); 2255 DMDestroy(§iondm); 2256 DMDestroy(&dm); 2257 .ve 2258 2259 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2260 @*/ 2261 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2262 { 2263 PetscBool ishdf5; 2264 2265 PetscFunctionBegin; 2266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2267 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2268 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2269 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2270 /* Check consistency */ 2271 { 2272 PetscSection section; 2273 PetscBool includesConstraints; 2274 PetscInt m, m1; 2275 2276 PetscCall(VecGetLocalSize(vec, &m1)); 2277 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2278 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2279 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2280 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2281 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2282 } 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2284 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2285 if (ishdf5) { 2286 #if defined(PETSC_HAVE_HDF5) 2287 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2288 #else 2289 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2290 #endif 2291 } 2292 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2293 PetscFunctionReturn(PETSC_SUCCESS); 2294 } 2295 2296 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2297 { 2298 PetscBool ishdf5; 2299 2300 PetscFunctionBegin; 2301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2302 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2303 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2304 if (ishdf5) { 2305 #if defined(PETSC_HAVE_HDF5) 2306 PetscViewerFormat format; 2307 PetscCall(PetscViewerGetFormat(viewer, &format)); 2308 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2309 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2310 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2311 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2312 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2313 PetscFunctionReturn(PETSC_SUCCESS); 2314 #else 2315 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2316 #endif 2317 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2318 } 2319 2320 /*@ 2321 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2322 2323 Collective 2324 2325 Input Parameters: 2326 + dm - The `DM` into which the topology is loaded 2327 - viewer - The `PetscViewer` for the saved topology 2328 2329 Output Parameter: 2330 . 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; `NULL` if unneeded 2331 2332 Level: advanced 2333 2334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2335 `PetscViewer`, `PetscSF` 2336 @*/ 2337 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2338 { 2339 PetscBool ishdf5; 2340 2341 PetscFunctionBegin; 2342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2344 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2345 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2346 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2347 if (ishdf5) { 2348 #if defined(PETSC_HAVE_HDF5) 2349 PetscViewerFormat format; 2350 PetscCall(PetscViewerGetFormat(viewer, &format)); 2351 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2352 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2353 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2354 #else 2355 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2356 #endif 2357 } 2358 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2359 PetscFunctionReturn(PETSC_SUCCESS); 2360 } 2361 2362 /*@ 2363 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2364 2365 Collective 2366 2367 Input Parameters: 2368 + dm - The `DM` into which the coordinates are loaded 2369 . viewer - The `PetscViewer` for the saved coordinates 2370 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2371 2372 Level: advanced 2373 2374 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2375 `PetscSF`, `PetscViewer` 2376 @*/ 2377 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2378 { 2379 PetscBool ishdf5; 2380 2381 PetscFunctionBegin; 2382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2383 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2384 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2385 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2386 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2387 if (ishdf5) { 2388 #if defined(PETSC_HAVE_HDF5) 2389 PetscViewerFormat format; 2390 PetscCall(PetscViewerGetFormat(viewer, &format)); 2391 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2392 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2393 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2394 #else 2395 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2396 #endif 2397 } 2398 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2399 PetscFunctionReturn(PETSC_SUCCESS); 2400 } 2401 2402 /*@ 2403 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2404 2405 Collective 2406 2407 Input Parameters: 2408 + dm - The `DM` into which the labels are loaded 2409 . viewer - The `PetscViewer` for the saved labels 2410 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2411 2412 Level: advanced 2413 2414 Note: 2415 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2416 2417 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2418 `PetscSF`, `PetscViewer` 2419 @*/ 2420 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2421 { 2422 PetscBool ishdf5; 2423 2424 PetscFunctionBegin; 2425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2426 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2427 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2428 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2429 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2430 if (ishdf5) { 2431 #if defined(PETSC_HAVE_HDF5) 2432 PetscViewerFormat format; 2433 2434 PetscCall(PetscViewerGetFormat(viewer, &format)); 2435 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2436 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2437 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2438 #else 2439 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2440 #endif 2441 } 2442 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2443 PetscFunctionReturn(PETSC_SUCCESS); 2444 } 2445 2446 /*@ 2447 DMPlexSectionLoad - Loads section into a `DMPLEX` 2448 2449 Collective 2450 2451 Input Parameters: 2452 + dm - The `DM` that represents the topology 2453 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2454 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2455 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2456 2457 Output Parameters: 2458 + 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) 2459 - 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) 2460 2461 Level: advanced 2462 2463 Notes: 2464 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. 2465 2466 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 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. 2467 2468 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. 2469 2470 Example using 2 processes: 2471 .vb 2472 NX (number of points on dm): 4 2473 sectionA : the on-disk section 2474 vecA : a vector associated with sectionA 2475 sectionB : sectiondm's local section constructed in this function 2476 vecB (local) : a vector associated with sectiondm's local section 2477 vecB (global) : a vector associated with sectiondm's global section 2478 2479 rank 0 rank 1 2480 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2481 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2482 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2483 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2484 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2485 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2486 sectionB->atlasDof : 1 0 1 | 1 3 2487 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2488 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2489 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2490 .ve 2491 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2492 2493 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2494 @*/ 2495 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2496 { 2497 PetscBool ishdf5; 2498 2499 PetscFunctionBegin; 2500 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2501 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2502 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2503 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2504 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2505 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2506 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2507 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2508 if (ishdf5) { 2509 #if defined(PETSC_HAVE_HDF5) 2510 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2511 #else 2512 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2513 #endif 2514 } 2515 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2516 PetscFunctionReturn(PETSC_SUCCESS); 2517 } 2518 2519 /*@ 2520 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2521 2522 Collective 2523 2524 Input Parameters: 2525 + dm - The `DM` that represents the topology 2526 . viewer - The `PetscViewer` that represents the on-disk vector data 2527 . sectiondm - The `DM` that contains the global section on which vec is defined 2528 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2529 - vec - The global vector to set values of 2530 2531 Level: advanced 2532 2533 Notes: 2534 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 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. 2535 2536 Calling sequence: 2537 .vb 2538 DMCreate(PETSC_COMM_WORLD, &dm); 2539 DMSetType(dm, DMPLEX); 2540 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2541 DMPlexTopologyLoad(dm, viewer, &sfX); 2542 DMClone(dm, §iondm); 2543 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2544 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2545 DMGetGlobalVector(sectiondm, &vec); 2546 PetscObjectSetName((PetscObject)vec, "vec_name"); 2547 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2548 DMRestoreGlobalVector(sectiondm, &vec); 2549 PetscSFDestroy(&gsf); 2550 PetscSFDestroy(&sfX); 2551 DMDestroy(§iondm); 2552 DMDestroy(&dm); 2553 .ve 2554 2555 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2556 `PetscSF`, `PetscViewer` 2557 @*/ 2558 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2559 { 2560 PetscBool ishdf5; 2561 2562 PetscFunctionBegin; 2563 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2564 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2565 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2566 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2567 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2568 /* Check consistency */ 2569 { 2570 PetscSection section; 2571 PetscBool includesConstraints; 2572 PetscInt m, m1; 2573 2574 PetscCall(VecGetLocalSize(vec, &m1)); 2575 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2576 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2577 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2578 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2579 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2580 } 2581 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2582 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2583 if (ishdf5) { 2584 #if defined(PETSC_HAVE_HDF5) 2585 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2586 #else 2587 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2588 #endif 2589 } 2590 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2591 PetscFunctionReturn(PETSC_SUCCESS); 2592 } 2593 2594 /*@ 2595 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2596 2597 Collective 2598 2599 Input Parameters: 2600 + dm - The `DM` that represents the topology 2601 . viewer - The `PetscViewer` that represents the on-disk vector data 2602 . sectiondm - The `DM` that contains the local section on which vec is defined 2603 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2604 - vec - The local vector to set values of 2605 2606 Level: advanced 2607 2608 Notes: 2609 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2610 2611 Calling sequence: 2612 .vb 2613 DMCreate(PETSC_COMM_WORLD, &dm); 2614 DMSetType(dm, DMPLEX); 2615 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2616 DMPlexTopologyLoad(dm, viewer, &sfX); 2617 DMClone(dm, §iondm); 2618 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2619 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2620 DMGetLocalVector(sectiondm, &vec); 2621 PetscObjectSetName((PetscObject)vec, "vec_name"); 2622 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2623 DMRestoreLocalVector(sectiondm, &vec); 2624 PetscSFDestroy(&lsf); 2625 PetscSFDestroy(&sfX); 2626 DMDestroy(§iondm); 2627 DMDestroy(&dm); 2628 .ve 2629 2630 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2631 `PetscSF`, `PetscViewer` 2632 @*/ 2633 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2634 { 2635 PetscBool ishdf5; 2636 2637 PetscFunctionBegin; 2638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2639 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2640 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2641 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2642 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2643 /* Check consistency */ 2644 { 2645 PetscSection section; 2646 PetscBool includesConstraints; 2647 PetscInt m, m1; 2648 2649 PetscCall(VecGetLocalSize(vec, &m1)); 2650 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2651 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2652 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2653 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2654 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2655 } 2656 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2657 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2658 if (ishdf5) { 2659 #if defined(PETSC_HAVE_HDF5) 2660 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2661 #else 2662 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2663 #endif 2664 } 2665 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2666 PetscFunctionReturn(PETSC_SUCCESS); 2667 } 2668 2669 PetscErrorCode DMDestroy_Plex(DM dm) 2670 { 2671 DM_Plex *mesh = (DM_Plex *)dm->data; 2672 2673 PetscFunctionBegin; 2674 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2675 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2676 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2677 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2678 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", NULL)); 2679 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2680 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2681 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2682 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2683 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2684 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2685 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSectionGetDefault_C", NULL)); 2686 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSectionSetDefault_C", NULL)); 2687 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2688 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2689 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetUseCeed_C", NULL)); 2690 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetUseCeed_C", NULL)); 2691 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2692 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2693 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2694 PetscCall(PetscFree(mesh->cones)); 2695 PetscCall(PetscFree(mesh->coneOrientations)); 2696 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2697 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2698 PetscCall(PetscFree(mesh->supports)); 2699 PetscCall(PetscFree(mesh->cellTypes)); 2700 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2701 PetscCall(PetscFree(mesh->tetgenOpts)); 2702 PetscCall(PetscFree(mesh->triangleOpts)); 2703 PetscCall(PetscFree(mesh->transformType)); 2704 PetscCall(PetscFree(mesh->distributionName)); 2705 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2706 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2707 PetscCall(ISDestroy(&mesh->subpointIS)); 2708 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2709 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2710 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2711 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2712 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2713 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2714 PetscCall(ISDestroy(&mesh->anchorIS)); 2715 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2716 PetscCall(PetscFree(mesh->parents)); 2717 PetscCall(PetscFree(mesh->childIDs)); 2718 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2719 PetscCall(PetscFree(mesh->children)); 2720 PetscCall(DMDestroy(&mesh->referenceTree)); 2721 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2722 PetscCall(PetscFree(mesh->neighbors)); 2723 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2724 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2725 PetscCall(PetscFree(mesh)); 2726 PetscFunctionReturn(PETSC_SUCCESS); 2727 } 2728 2729 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2730 { 2731 PetscSection sectionGlobal, sectionLocal; 2732 PetscInt bs = -1, mbs; 2733 PetscInt localSize, localStart = 0; 2734 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2735 MatType mtype; 2736 ISLocalToGlobalMapping ltog; 2737 2738 PetscFunctionBegin; 2739 PetscCall(MatInitializePackage()); 2740 mtype = dm->mattype; 2741 PetscCall(DMGetLocalSection(dm, §ionLocal)); 2742 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2743 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2744 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2745 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2746 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2747 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2748 PetscCall(MatSetType(*J, mtype)); 2749 PetscCall(MatSetFromOptions(*J)); 2750 PetscCall(MatGetBlockSize(*J, &mbs)); 2751 if (mbs > 1) bs = mbs; 2752 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2753 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2754 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2755 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2756 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2757 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2758 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2759 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2760 if (!isShell) { 2761 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2762 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2763 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2764 2765 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2766 2767 PetscCall(PetscCalloc1(localSize, &pblocks)); 2768 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2769 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2770 for (p = pStart; p < pEnd; ++p) { 2771 switch (dm->blocking_type) { 2772 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2773 PetscInt bdof, offset; 2774 2775 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2776 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2777 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2778 for (PetscInt i = 0; i < dof - cdof; ++i) pblocks[offset - localStart + i] = dof - cdof; 2779 // Signal block concatenation 2780 if (dof - cdof && sectionLocal->blockStarts && !PetscBTLookup(sectionLocal->blockStarts, p)) pblocks[offset - localStart] = -(dof - cdof); 2781 dof = dof < 0 ? -(dof + 1) : dof; 2782 bdof = cdof && (dof - cdof) ? 1 : dof; 2783 if (dof) { 2784 if (bs < 0) { 2785 bs = bdof; 2786 } else if (bs != bdof) { 2787 bs = 1; 2788 } 2789 } 2790 } break; 2791 case DM_BLOCKING_FIELD_NODE: { 2792 for (PetscInt field = 0; field < num_fields; field++) { 2793 PetscInt num_comp, bdof, offset; 2794 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2795 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2796 if (dof < 0) continue; 2797 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2798 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2799 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); 2800 PetscInt num_nodes = dof / num_comp; 2801 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2802 // Handle possibly constant block size (unlikely) 2803 bdof = cdof && (dof - cdof) ? 1 : dof; 2804 if (dof) { 2805 if (bs < 0) { 2806 bs = bdof; 2807 } else if (bs != bdof) { 2808 bs = 1; 2809 } 2810 } 2811 } 2812 } break; 2813 } 2814 } 2815 /* Must have same blocksize on all procs (some might have no points) */ 2816 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2817 bsLocal[1] = bs; 2818 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2819 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2820 else bs = bsMinMax[0]; 2821 bs = PetscMax(1, bs); 2822 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2823 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2824 PetscCall(MatSetBlockSize(*J, bs)); 2825 PetscCall(MatSetUp(*J)); 2826 } else { 2827 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2828 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2829 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2830 } 2831 { // Consolidate blocks 2832 PetscInt nblocks = 0; 2833 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2834 if (pblocks[i] == 0) continue; 2835 // Negative block size indicates the blocks should be concatenated 2836 if (pblocks[i] < 0) { 2837 pblocks[i] = -pblocks[i]; 2838 pblocks[nblocks - 1] += pblocks[i]; 2839 } else { 2840 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2841 } 2842 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2843 } 2844 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2845 } 2846 PetscCall(PetscFree(pblocks)); 2847 } 2848 PetscCall(MatSetDM(*J, dm)); 2849 PetscFunctionReturn(PETSC_SUCCESS); 2850 } 2851 2852 /*@ 2853 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2854 2855 Not Collective 2856 2857 Input Parameter: 2858 . dm - The `DMPLEX` 2859 2860 Output Parameter: 2861 . subsection - The subdomain section 2862 2863 Level: developer 2864 2865 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2866 @*/ 2867 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2868 { 2869 DM_Plex *mesh = (DM_Plex *)dm->data; 2870 2871 PetscFunctionBegin; 2872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2873 if (!mesh->subdomainSection) { 2874 PetscSection section; 2875 PetscSF sf; 2876 2877 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2878 PetscCall(DMGetLocalSection(dm, §ion)); 2879 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2880 PetscCall(PetscSFDestroy(&sf)); 2881 } 2882 *subsection = mesh->subdomainSection; 2883 PetscFunctionReturn(PETSC_SUCCESS); 2884 } 2885 2886 /*@ 2887 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2888 2889 Not Collective 2890 2891 Input Parameter: 2892 . dm - The `DMPLEX` 2893 2894 Output Parameters: 2895 + pStart - The first mesh point 2896 - pEnd - The upper bound for mesh points 2897 2898 Level: beginner 2899 2900 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2901 @*/ 2902 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2903 { 2904 DM_Plex *mesh = (DM_Plex *)dm->data; 2905 2906 PetscFunctionBegin; 2907 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2908 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2909 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2910 PetscFunctionReturn(PETSC_SUCCESS); 2911 } 2912 2913 /*@ 2914 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2915 2916 Not Collective 2917 2918 Input Parameters: 2919 + dm - The `DMPLEX` 2920 . pStart - The first mesh point 2921 - pEnd - The upper bound for mesh points 2922 2923 Level: beginner 2924 2925 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2926 @*/ 2927 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2928 { 2929 DM_Plex *mesh = (DM_Plex *)dm->data; 2930 2931 PetscFunctionBegin; 2932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2933 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2934 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2935 PetscCall(PetscFree(mesh->cellTypes)); 2936 PetscFunctionReturn(PETSC_SUCCESS); 2937 } 2938 2939 /*@ 2940 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2941 2942 Not Collective 2943 2944 Input Parameters: 2945 + dm - The `DMPLEX` 2946 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2947 2948 Output Parameter: 2949 . size - The cone size for point `p` 2950 2951 Level: beginner 2952 2953 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2954 @*/ 2955 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2956 { 2957 DM_Plex *mesh = (DM_Plex *)dm->data; 2958 2959 PetscFunctionBegin; 2960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2961 PetscAssertPointer(size, 3); 2962 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2963 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2964 PetscFunctionReturn(PETSC_SUCCESS); 2965 } 2966 2967 /*@ 2968 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2969 2970 Not Collective 2971 2972 Input Parameters: 2973 + dm - The `DMPLEX` 2974 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2975 - size - The cone size for point `p` 2976 2977 Level: beginner 2978 2979 Note: 2980 This should be called after `DMPlexSetChart()`. 2981 2982 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2983 @*/ 2984 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2985 { 2986 DM_Plex *mesh = (DM_Plex *)dm->data; 2987 2988 PetscFunctionBegin; 2989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2990 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2991 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2992 PetscFunctionReturn(PETSC_SUCCESS); 2993 } 2994 2995 /*@C 2996 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2997 2998 Not Collective 2999 3000 Input Parameters: 3001 + dm - The `DMPLEX` 3002 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3003 3004 Output Parameter: 3005 . cone - An array of points which are on the in-edges for point `p` 3006 3007 Level: beginner 3008 3009 Fortran Notes: 3010 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3011 `DMPlexRestoreCone()` is not needed/available in C. 3012 3013 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 3014 @*/ 3015 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 3016 { 3017 DM_Plex *mesh = (DM_Plex *)dm->data; 3018 PetscInt off; 3019 3020 PetscFunctionBegin; 3021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3022 PetscAssertPointer(cone, 3); 3023 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3024 *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3025 PetscFunctionReturn(PETSC_SUCCESS); 3026 } 3027 3028 /*@C 3029 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 3030 3031 Not Collective 3032 3033 Input Parameters: 3034 + dm - The `DMPLEX` 3035 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3036 3037 Output Parameters: 3038 + pConesSection - `PetscSection` describing the layout of `pCones` 3039 - pCones - An array of points which are on the in-edges for the point set `p` 3040 3041 Level: intermediate 3042 3043 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 3044 @*/ 3045 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 3046 { 3047 PetscSection cs, newcs; 3048 PetscInt *cones; 3049 PetscInt *newarr = NULL; 3050 PetscInt n; 3051 3052 PetscFunctionBegin; 3053 PetscCall(DMPlexGetCones(dm, &cones)); 3054 PetscCall(DMPlexGetConeSection(dm, &cs)); 3055 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 3056 if (pConesSection) *pConesSection = newcs; 3057 if (pCones) { 3058 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 3059 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 3060 } 3061 PetscFunctionReturn(PETSC_SUCCESS); 3062 } 3063 3064 /*@ 3065 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 3066 3067 Not Collective 3068 3069 Input Parameters: 3070 + dm - The `DMPLEX` 3071 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3072 3073 Output Parameter: 3074 . expandedPoints - An array of vertices recursively expanded from input points 3075 3076 Level: advanced 3077 3078 Notes: 3079 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 3080 3081 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 3082 3083 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 3084 `DMPlexGetDepth()`, `IS` 3085 @*/ 3086 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 3087 { 3088 IS *expandedPointsAll; 3089 PetscInt depth; 3090 3091 PetscFunctionBegin; 3092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3093 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3094 PetscAssertPointer(expandedPoints, 3); 3095 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3096 *expandedPoints = expandedPointsAll[0]; 3097 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 3098 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 3099 PetscFunctionReturn(PETSC_SUCCESS); 3100 } 3101 3102 /*@ 3103 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 3104 3105 Not Collective 3106 3107 Input Parameters: 3108 + dm - The `DMPLEX` 3109 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3110 3111 Output Parameters: 3112 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3113 . expandedPoints - (optional) An array of index sets with recursively expanded cones 3114 - sections - (optional) An array of sections which describe mappings from points to their cone points 3115 3116 Level: advanced 3117 3118 Notes: 3119 Like `DMPlexGetConeTuple()` but recursive. 3120 3121 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. 3122 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 3123 3124 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\: 3125 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 3126 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 3127 3128 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3129 `DMPlexGetDepth()`, `PetscSection`, `IS` 3130 @*/ 3131 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3132 { 3133 const PetscInt *arr0 = NULL, *cone = NULL; 3134 PetscInt *arr = NULL, *newarr = NULL; 3135 PetscInt d, depth_, i, n, newn, cn, co, start, end; 3136 IS *expandedPoints_; 3137 PetscSection *sections_; 3138 3139 PetscFunctionBegin; 3140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3141 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 3142 if (depth) PetscAssertPointer(depth, 3); 3143 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 3144 if (sections) PetscAssertPointer(sections, 5); 3145 PetscCall(ISGetLocalSize(points, &n)); 3146 PetscCall(ISGetIndices(points, &arr0)); 3147 PetscCall(DMPlexGetDepth(dm, &depth_)); 3148 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 3149 PetscCall(PetscCalloc1(depth_, §ions_)); 3150 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 3151 for (d = depth_ - 1; d >= 0; d--) { 3152 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 3153 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 3154 for (i = 0; i < n; i++) { 3155 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 3156 if (arr[i] >= start && arr[i] < end) { 3157 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 3158 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3159 } else { 3160 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3161 } 3162 } 3163 PetscCall(PetscSectionSetUp(sections_[d])); 3164 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3165 PetscCall(PetscMalloc1(newn, &newarr)); 3166 for (i = 0; i < n; i++) { 3167 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3168 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3169 if (cn > 1) { 3170 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3171 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3172 } else { 3173 newarr[co] = arr[i]; 3174 } 3175 } 3176 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3177 arr = newarr; 3178 n = newn; 3179 } 3180 PetscCall(ISRestoreIndices(points, &arr0)); 3181 *depth = depth_; 3182 if (expandedPoints) *expandedPoints = expandedPoints_; 3183 else { 3184 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3185 PetscCall(PetscFree(expandedPoints_)); 3186 } 3187 if (sections) *sections = sections_; 3188 else { 3189 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3190 PetscCall(PetscFree(sections_)); 3191 } 3192 PetscFunctionReturn(PETSC_SUCCESS); 3193 } 3194 3195 /*@ 3196 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3197 3198 Not Collective 3199 3200 Input Parameters: 3201 + dm - The `DMPLEX` 3202 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3203 3204 Output Parameters: 3205 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3206 . expandedPoints - (optional) An array of recursively expanded cones 3207 - sections - (optional) An array of sections which describe mappings from points to their cone points 3208 3209 Level: advanced 3210 3211 Note: 3212 See `DMPlexGetConeRecursive()` 3213 3214 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3215 `DMPlexGetDepth()`, `IS`, `PetscSection` 3216 @*/ 3217 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3218 { 3219 PetscInt d, depth_; 3220 3221 PetscFunctionBegin; 3222 PetscCall(DMPlexGetDepth(dm, &depth_)); 3223 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3224 if (depth) *depth = 0; 3225 if (expandedPoints) { 3226 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3227 PetscCall(PetscFree(*expandedPoints)); 3228 } 3229 if (sections) { 3230 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3231 PetscCall(PetscFree(*sections)); 3232 } 3233 PetscFunctionReturn(PETSC_SUCCESS); 3234 } 3235 3236 /*@ 3237 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 3238 3239 Not Collective 3240 3241 Input Parameters: 3242 + dm - The `DMPLEX` 3243 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3244 - cone - An array of points which are on the in-edges for point `p` 3245 3246 Level: beginner 3247 3248 Note: 3249 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3250 3251 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3252 @*/ 3253 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3254 { 3255 DM_Plex *mesh = (DM_Plex *)dm->data; 3256 PetscInt dof, off, c; 3257 3258 PetscFunctionBegin; 3259 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3260 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3261 if (dof) PetscAssertPointer(cone, 3); 3262 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3263 if (PetscDefined(USE_DEBUG)) { 3264 PetscInt pStart, pEnd; 3265 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3266 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); 3267 for (c = 0; c < dof; ++c) { 3268 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); 3269 mesh->cones[off + c] = cone[c]; 3270 } 3271 } else { 3272 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3273 } 3274 PetscFunctionReturn(PETSC_SUCCESS); 3275 } 3276 3277 /*@C 3278 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3279 3280 Not Collective 3281 3282 Input Parameters: 3283 + dm - The `DMPLEX` 3284 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3285 3286 Output Parameter: 3287 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3288 integer giving the prescription for cone traversal. 3289 3290 Level: beginner 3291 3292 Note: 3293 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3294 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3295 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3296 with the identity. 3297 3298 Fortran Notes: 3299 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3300 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3301 3302 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3303 @*/ 3304 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3305 { 3306 DM_Plex *mesh = (DM_Plex *)dm->data; 3307 PetscInt off; 3308 3309 PetscFunctionBegin; 3310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3311 if (PetscDefined(USE_DEBUG)) { 3312 PetscInt dof; 3313 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3314 if (dof) PetscAssertPointer(coneOrientation, 3); 3315 } 3316 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3317 3318 *coneOrientation = &mesh->coneOrientations[off]; 3319 PetscFunctionReturn(PETSC_SUCCESS); 3320 } 3321 3322 /*@ 3323 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3324 3325 Not Collective 3326 3327 Input Parameters: 3328 + dm - The `DMPLEX` 3329 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3330 - coneOrientation - An array of orientations 3331 3332 Level: beginner 3333 3334 Notes: 3335 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3336 3337 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3338 3339 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3340 @*/ 3341 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3342 { 3343 DM_Plex *mesh = (DM_Plex *)dm->data; 3344 PetscInt pStart, pEnd; 3345 PetscInt dof, off, c; 3346 3347 PetscFunctionBegin; 3348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3349 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3350 if (dof) PetscAssertPointer(coneOrientation, 3); 3351 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3352 if (PetscDefined(USE_DEBUG)) { 3353 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3354 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); 3355 for (c = 0; c < dof; ++c) { 3356 PetscInt cdof, o = coneOrientation[c]; 3357 3358 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3359 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); 3360 mesh->coneOrientations[off + c] = o; 3361 } 3362 } else { 3363 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3364 } 3365 PetscFunctionReturn(PETSC_SUCCESS); 3366 } 3367 3368 /*@ 3369 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3370 3371 Not Collective 3372 3373 Input Parameters: 3374 + dm - The `DMPLEX` 3375 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3376 . conePos - The local index in the cone where the point should be put 3377 - conePoint - The mesh point to insert 3378 3379 Level: beginner 3380 3381 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3382 @*/ 3383 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3384 { 3385 DM_Plex *mesh = (DM_Plex *)dm->data; 3386 PetscInt pStart, pEnd; 3387 PetscInt dof, off; 3388 3389 PetscFunctionBegin; 3390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3391 if (PetscDefined(USE_DEBUG)) { 3392 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3393 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); 3394 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); 3395 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3396 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); 3397 } 3398 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3399 mesh->cones[off + conePos] = conePoint; 3400 PetscFunctionReturn(PETSC_SUCCESS); 3401 } 3402 3403 /*@ 3404 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3405 3406 Not Collective 3407 3408 Input Parameters: 3409 + dm - The `DMPLEX` 3410 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3411 . conePos - The local index in the cone where the point should be put 3412 - coneOrientation - The point orientation to insert 3413 3414 Level: beginner 3415 3416 Note: 3417 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3418 3419 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3420 @*/ 3421 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3422 { 3423 DM_Plex *mesh = (DM_Plex *)dm->data; 3424 PetscInt pStart, pEnd; 3425 PetscInt dof, off; 3426 3427 PetscFunctionBegin; 3428 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3429 if (PetscDefined(USE_DEBUG)) { 3430 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3431 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); 3432 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3433 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); 3434 } 3435 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3436 mesh->coneOrientations[off + conePos] = coneOrientation; 3437 PetscFunctionReturn(PETSC_SUCCESS); 3438 } 3439 3440 /*@C 3441 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3442 3443 Not collective 3444 3445 Input Parameters: 3446 + dm - The DMPlex 3447 - p - The point, which must lie in the chart set with DMPlexSetChart() 3448 3449 Output Parameters: 3450 + cone - An array of points which are on the in-edges for point `p` 3451 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3452 integer giving the prescription for cone traversal. 3453 3454 Level: beginner 3455 3456 Notes: 3457 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3458 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3459 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3460 with the identity. 3461 3462 Fortran Notes: 3463 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3464 `DMPlexRestoreCone()` is not needed/available in C. 3465 3466 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3467 @*/ 3468 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3469 { 3470 DM_Plex *mesh = (DM_Plex *)dm->data; 3471 3472 PetscFunctionBegin; 3473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3474 if (mesh->tr) { 3475 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3476 } else { 3477 PetscInt off; 3478 if (PetscDefined(USE_DEBUG)) { 3479 PetscInt dof; 3480 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3481 if (dof) { 3482 if (cone) PetscAssertPointer(cone, 3); 3483 if (ornt) PetscAssertPointer(ornt, 4); 3484 } 3485 } 3486 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3487 if (cone) *cone = PetscSafePointerPlusOffset(mesh->cones, off); 3488 if (ornt) *ornt = PetscSafePointerPlusOffset(mesh->coneOrientations, off); 3489 } 3490 PetscFunctionReturn(PETSC_SUCCESS); 3491 } 3492 3493 /*@C 3494 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3495 3496 Not Collective 3497 3498 Input Parameters: 3499 + dm - The DMPlex 3500 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3501 . cone - An array of points which are on the in-edges for point p 3502 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3503 integer giving the prescription for cone traversal. 3504 3505 Level: beginner 3506 3507 Notes: 3508 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3509 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3510 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3511 with the identity. 3512 3513 Fortran Notes: 3514 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3515 `DMPlexRestoreCone()` is not needed/available in C. 3516 3517 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3518 @*/ 3519 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3520 { 3521 DM_Plex *mesh = (DM_Plex *)dm->data; 3522 3523 PetscFunctionBegin; 3524 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3525 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3526 PetscFunctionReturn(PETSC_SUCCESS); 3527 } 3528 3529 /*@ 3530 DMPlexGetSupportSize - Return the number of out-edges for this point 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 3538 Output Parameter: 3539 . size - The support size for point `p` 3540 3541 Level: beginner 3542 3543 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3544 @*/ 3545 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3546 { 3547 DM_Plex *mesh = (DM_Plex *)dm->data; 3548 3549 PetscFunctionBegin; 3550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3551 PetscAssertPointer(size, 3); 3552 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3553 PetscFunctionReturn(PETSC_SUCCESS); 3554 } 3555 3556 /*@ 3557 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3558 3559 Not Collective 3560 3561 Input Parameters: 3562 + dm - The `DMPLEX` 3563 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3564 - size - The support size for point `p` 3565 3566 Level: beginner 3567 3568 Note: 3569 This should be called after `DMPlexSetChart()`. 3570 3571 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3572 @*/ 3573 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3574 { 3575 DM_Plex *mesh = (DM_Plex *)dm->data; 3576 3577 PetscFunctionBegin; 3578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3579 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3580 PetscFunctionReturn(PETSC_SUCCESS); 3581 } 3582 3583 /*@C 3584 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3585 3586 Not Collective 3587 3588 Input Parameters: 3589 + dm - The `DMPLEX` 3590 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3591 3592 Output Parameter: 3593 . support - An array of points which are on the out-edges for point `p` 3594 3595 Level: beginner 3596 3597 Fortran Notes: 3598 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3599 `DMPlexRestoreSupport()` is not needed/available in C. 3600 3601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3602 @*/ 3603 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3604 { 3605 DM_Plex *mesh = (DM_Plex *)dm->data; 3606 PetscInt off; 3607 3608 PetscFunctionBegin; 3609 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3610 PetscAssertPointer(support, 3); 3611 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3612 *support = PetscSafePointerPlusOffset(mesh->supports, off); 3613 PetscFunctionReturn(PETSC_SUCCESS); 3614 } 3615 3616 /*@ 3617 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3618 3619 Not Collective 3620 3621 Input Parameters: 3622 + dm - The `DMPLEX` 3623 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3624 - support - An array of points which are on the out-edges for point `p` 3625 3626 Level: beginner 3627 3628 Note: 3629 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3630 3631 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3632 @*/ 3633 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3634 { 3635 DM_Plex *mesh = (DM_Plex *)dm->data; 3636 PetscInt pStart, pEnd; 3637 PetscInt dof, off, c; 3638 3639 PetscFunctionBegin; 3640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3641 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3642 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3643 if (dof) PetscAssertPointer(support, 3); 3644 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3645 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); 3646 for (c = 0; c < dof; ++c) { 3647 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); 3648 mesh->supports[off + c] = support[c]; 3649 } 3650 PetscFunctionReturn(PETSC_SUCCESS); 3651 } 3652 3653 /*@ 3654 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3655 3656 Not Collective 3657 3658 Input Parameters: 3659 + dm - The `DMPLEX` 3660 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3661 . supportPos - The local index in the cone where the point should be put 3662 - supportPoint - The mesh point to insert 3663 3664 Level: beginner 3665 3666 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3667 @*/ 3668 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3669 { 3670 DM_Plex *mesh = (DM_Plex *)dm->data; 3671 PetscInt pStart, pEnd; 3672 PetscInt dof, off; 3673 3674 PetscFunctionBegin; 3675 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3676 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3677 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3678 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3679 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); 3680 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); 3681 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); 3682 mesh->supports[off + supportPos] = supportPoint; 3683 PetscFunctionReturn(PETSC_SUCCESS); 3684 } 3685 3686 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3687 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3688 { 3689 switch (ct) { 3690 case DM_POLYTOPE_SEGMENT: 3691 if (o == -1) return -2; 3692 break; 3693 case DM_POLYTOPE_TRIANGLE: 3694 if (o == -3) return -1; 3695 if (o == -2) return -3; 3696 if (o == -1) return -2; 3697 break; 3698 case DM_POLYTOPE_QUADRILATERAL: 3699 if (o == -4) return -2; 3700 if (o == -3) return -1; 3701 if (o == -2) return -4; 3702 if (o == -1) return -3; 3703 break; 3704 default: 3705 return o; 3706 } 3707 return o; 3708 } 3709 3710 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3711 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3712 { 3713 switch (ct) { 3714 case DM_POLYTOPE_SEGMENT: 3715 if ((o == -2) || (o == 1)) return -1; 3716 if (o == -1) return 0; 3717 break; 3718 case DM_POLYTOPE_TRIANGLE: 3719 if (o == -3) return -2; 3720 if (o == -2) return -1; 3721 if (o == -1) return -3; 3722 break; 3723 case DM_POLYTOPE_QUADRILATERAL: 3724 if (o == -4) return -2; 3725 if (o == -3) return -1; 3726 if (o == -2) return -4; 3727 if (o == -1) return -3; 3728 break; 3729 default: 3730 return o; 3731 } 3732 return o; 3733 } 3734 3735 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3736 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3737 { 3738 PetscInt pStart, pEnd, p; 3739 3740 PetscFunctionBegin; 3741 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3742 for (p = pStart; p < pEnd; ++p) { 3743 const PetscInt *cone, *ornt; 3744 PetscInt coneSize, c; 3745 3746 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3747 PetscCall(DMPlexGetCone(dm, p, &cone)); 3748 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3749 for (c = 0; c < coneSize; ++c) { 3750 DMPolytopeType ct; 3751 const PetscInt o = ornt[c]; 3752 3753 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3754 switch (ct) { 3755 case DM_POLYTOPE_SEGMENT: 3756 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3757 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3758 break; 3759 case DM_POLYTOPE_TRIANGLE: 3760 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3761 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3762 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3763 break; 3764 case DM_POLYTOPE_QUADRILATERAL: 3765 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3766 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3767 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3768 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3769 break; 3770 default: 3771 break; 3772 } 3773 } 3774 } 3775 PetscFunctionReturn(PETSC_SUCCESS); 3776 } 3777 3778 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3779 { 3780 DM_Plex *mesh = (DM_Plex *)dm->data; 3781 3782 PetscFunctionBeginHot; 3783 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3784 if (useCone) { 3785 PetscCall(DMPlexGetConeSize(dm, p, size)); 3786 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3787 } else { 3788 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3789 PetscCall(DMPlexGetSupport(dm, p, arr)); 3790 } 3791 } else { 3792 if (useCone) { 3793 const PetscSection s = mesh->coneSection; 3794 const PetscInt ps = p - s->pStart; 3795 const PetscInt off = s->atlasOff[ps]; 3796 3797 *size = s->atlasDof[ps]; 3798 *arr = mesh->cones + off; 3799 *ornt = mesh->coneOrientations + off; 3800 } else { 3801 const PetscSection s = mesh->supportSection; 3802 const PetscInt ps = p - s->pStart; 3803 const PetscInt off = s->atlasOff[ps]; 3804 3805 *size = s->atlasDof[ps]; 3806 *arr = mesh->supports + off; 3807 } 3808 } 3809 PetscFunctionReturn(PETSC_SUCCESS); 3810 } 3811 3812 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3813 { 3814 DM_Plex *mesh = (DM_Plex *)dm->data; 3815 3816 PetscFunctionBeginHot; 3817 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3818 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3819 } 3820 PetscFunctionReturn(PETSC_SUCCESS); 3821 } 3822 3823 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3824 { 3825 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3826 PetscInt *closure; 3827 const PetscInt *tmp = NULL, *tmpO = NULL; 3828 PetscInt off = 0, tmpSize, t; 3829 3830 PetscFunctionBeginHot; 3831 if (ornt) { 3832 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3833 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; 3834 } 3835 if (*points) { 3836 closure = *points; 3837 } else { 3838 PetscInt maxConeSize, maxSupportSize; 3839 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3840 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3841 } 3842 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3843 if (ct == DM_POLYTOPE_UNKNOWN) { 3844 closure[off++] = p; 3845 closure[off++] = 0; 3846 for (t = 0; t < tmpSize; ++t) { 3847 closure[off++] = tmp[t]; 3848 closure[off++] = tmpO ? tmpO[t] : 0; 3849 } 3850 } else { 3851 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, ornt); 3852 3853 /* We assume that cells with a valid type have faces with a valid type */ 3854 closure[off++] = p; 3855 closure[off++] = ornt; 3856 for (t = 0; t < tmpSize; ++t) { 3857 DMPolytopeType ft; 3858 3859 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3860 closure[off++] = tmp[arr[t]]; 3861 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3862 } 3863 } 3864 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3865 if (numPoints) *numPoints = tmpSize + 1; 3866 if (points) *points = closure; 3867 PetscFunctionReturn(PETSC_SUCCESS); 3868 } 3869 3870 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3871 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3872 { 3873 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 3874 const PetscInt *cone, *ornt; 3875 PetscInt *pts, *closure = NULL; 3876 DMPolytopeType ft; 3877 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3878 PetscInt dim, coneSize, c, d, clSize, cl; 3879 3880 PetscFunctionBeginHot; 3881 PetscCall(DMGetDimension(dm, &dim)); 3882 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3883 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3884 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3885 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3886 maxSize = PetscMax(coneSeries, supportSeries); 3887 if (*points) { 3888 pts = *points; 3889 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3890 c = 0; 3891 pts[c++] = point; 3892 pts[c++] = o; 3893 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3894 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3895 for (cl = 0; cl < clSize * 2; cl += 2) { 3896 pts[c++] = closure[cl]; 3897 pts[c++] = closure[cl + 1]; 3898 } 3899 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3900 for (cl = 0; cl < clSize * 2; cl += 2) { 3901 pts[c++] = closure[cl]; 3902 pts[c++] = closure[cl + 1]; 3903 } 3904 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3905 for (d = 2; d < coneSize; ++d) { 3906 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3907 pts[c++] = cone[arr[d * 2 + 0]]; 3908 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3909 } 3910 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3911 if (dim >= 3) { 3912 for (d = 2; d < coneSize; ++d) { 3913 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3914 const PetscInt *fcone, *fornt; 3915 PetscInt fconeSize, fc, i; 3916 3917 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3918 const PetscInt *farr = DMPolytopeTypeGetArrangement(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3919 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3920 for (fc = 0; fc < fconeSize; ++fc) { 3921 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3922 const PetscInt co = farr[fc * 2 + 1]; 3923 3924 for (i = 0; i < c; i += 2) 3925 if (pts[i] == cp) break; 3926 if (i == c) { 3927 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3928 pts[c++] = cp; 3929 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3930 } 3931 } 3932 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3933 } 3934 } 3935 *numPoints = c / 2; 3936 *points = pts; 3937 PetscFunctionReturn(PETSC_SUCCESS); 3938 } 3939 3940 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3941 { 3942 DMPolytopeType ct; 3943 PetscInt *closure, *fifo; 3944 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3945 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3946 PetscInt depth, maxSize; 3947 3948 PetscFunctionBeginHot; 3949 PetscCall(DMPlexGetDepth(dm, &depth)); 3950 if (depth == 1) { 3951 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3952 PetscFunctionReturn(PETSC_SUCCESS); 3953 } 3954 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3955 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; 3956 if (DMPolytopeTypeIsHybrid(ct) && ct != DM_POLYTOPE_POINT_PRISM_TENSOR) { 3957 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3958 PetscFunctionReturn(PETSC_SUCCESS); 3959 } 3960 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3961 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3962 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3963 maxSize = PetscMax(coneSeries, supportSeries); 3964 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3965 if (*points) { 3966 closure = *points; 3967 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3968 closure[closureSize++] = p; 3969 closure[closureSize++] = ornt; 3970 fifo[fifoSize++] = p; 3971 fifo[fifoSize++] = ornt; 3972 fifo[fifoSize++] = ct; 3973 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3974 while (fifoSize - fifoStart) { 3975 const PetscInt q = fifo[fifoStart++]; 3976 const PetscInt o = fifo[fifoStart++]; 3977 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3978 const PetscInt *qarr = DMPolytopeTypeGetArrangement(qt, o); 3979 const PetscInt *tmp, *tmpO = NULL; 3980 PetscInt tmpSize, t; 3981 3982 if (PetscDefined(USE_DEBUG)) { 3983 PetscInt nO = DMPolytopeTypeGetNumArrangements(qt) / 2; 3984 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); 3985 } 3986 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3987 for (t = 0; t < tmpSize; ++t) { 3988 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3989 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3990 const PetscInt cp = tmp[ip]; 3991 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3992 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3993 PetscInt c; 3994 3995 /* Check for duplicate */ 3996 for (c = 0; c < closureSize; c += 2) { 3997 if (closure[c] == cp) break; 3998 } 3999 if (c == closureSize) { 4000 closure[closureSize++] = cp; 4001 closure[closureSize++] = co; 4002 fifo[fifoSize++] = cp; 4003 fifo[fifoSize++] = co; 4004 fifo[fifoSize++] = ct; 4005 } 4006 } 4007 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 4008 } 4009 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 4010 if (numPoints) *numPoints = closureSize / 2; 4011 if (points) *points = closure; 4012 PetscFunctionReturn(PETSC_SUCCESS); 4013 } 4014 4015 /*@C 4016 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 4017 4018 Not Collective 4019 4020 Input Parameters: 4021 + dm - The `DMPLEX` 4022 . p - The mesh point 4023 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 4024 4025 Input/Output Parameter: 4026 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 4027 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 4028 4029 Output Parameter: 4030 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4031 4032 Level: beginner 4033 4034 Note: 4035 If using internal storage (points is `NULL` on input), each call overwrites the last output. 4036 4037 Fortran Notes: 4038 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 4039 4040 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4041 @*/ 4042 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4043 { 4044 PetscFunctionBeginHot; 4045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4046 if (numPoints) PetscAssertPointer(numPoints, 4); 4047 if (points) PetscAssertPointer(points, 5); 4048 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 4049 PetscFunctionReturn(PETSC_SUCCESS); 4050 } 4051 4052 /*@C 4053 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 4054 4055 Not Collective 4056 4057 Input Parameters: 4058 + dm - The `DMPLEX` 4059 . p - The mesh point 4060 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 4061 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 4062 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 4063 4064 Level: beginner 4065 4066 Note: 4067 If not using internal storage (points is not `NULL` on input), this call is unnecessary 4068 4069 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 4070 @*/ 4071 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 4072 { 4073 PetscFunctionBeginHot; 4074 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4075 if (numPoints) *numPoints = 0; 4076 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 4077 PetscFunctionReturn(PETSC_SUCCESS); 4078 } 4079 4080 /*@ 4081 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 4082 4083 Not Collective 4084 4085 Input Parameter: 4086 . dm - The `DMPLEX` 4087 4088 Output Parameters: 4089 + maxConeSize - The maximum number of in-edges 4090 - maxSupportSize - The maximum number of out-edges 4091 4092 Level: beginner 4093 4094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 4095 @*/ 4096 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 4097 { 4098 DM_Plex *mesh = (DM_Plex *)dm->data; 4099 4100 PetscFunctionBegin; 4101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4102 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 4103 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 4104 PetscFunctionReturn(PETSC_SUCCESS); 4105 } 4106 4107 PetscErrorCode DMSetUp_Plex(DM dm) 4108 { 4109 DM_Plex *mesh = (DM_Plex *)dm->data; 4110 PetscInt size, maxSupportSize; 4111 4112 PetscFunctionBegin; 4113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4114 PetscCall(PetscSectionSetUp(mesh->coneSection)); 4115 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 4116 PetscCall(PetscMalloc1(size, &mesh->cones)); 4117 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 4118 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4119 if (maxSupportSize) { 4120 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4121 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 4122 PetscCall(PetscMalloc1(size, &mesh->supports)); 4123 } 4124 PetscFunctionReturn(PETSC_SUCCESS); 4125 } 4126 4127 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 4128 { 4129 PetscFunctionBegin; 4130 if (subdm) PetscCall(DMClone(dm, subdm)); 4131 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 4132 if (subdm) (*subdm)->useNatural = dm->useNatural; 4133 if (dm->useNatural && dm->sfMigration) { 4134 PetscSF sfNatural; 4135 4136 (*subdm)->sfMigration = dm->sfMigration; 4137 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 4138 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 4139 (*subdm)->sfNatural = sfNatural; 4140 } 4141 PetscFunctionReturn(PETSC_SUCCESS); 4142 } 4143 4144 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 4145 { 4146 PetscInt i = 0; 4147 4148 PetscFunctionBegin; 4149 PetscCall(DMClone(dms[0], superdm)); 4150 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 4151 (*superdm)->useNatural = PETSC_FALSE; 4152 for (i = 0; i < len; i++) { 4153 if (dms[i]->useNatural && dms[i]->sfMigration) { 4154 PetscSF sfNatural; 4155 4156 (*superdm)->sfMigration = dms[i]->sfMigration; 4157 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 4158 (*superdm)->useNatural = PETSC_TRUE; 4159 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 4160 (*superdm)->sfNatural = sfNatural; 4161 break; 4162 } 4163 } 4164 PetscFunctionReturn(PETSC_SUCCESS); 4165 } 4166 4167 /*@ 4168 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 4169 4170 Not Collective 4171 4172 Input Parameter: 4173 . dm - The `DMPLEX` 4174 4175 Level: beginner 4176 4177 Note: 4178 This should be called after all calls to `DMPlexSetCone()` 4179 4180 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4181 @*/ 4182 PetscErrorCode DMPlexSymmetrize(DM dm) 4183 { 4184 DM_Plex *mesh = (DM_Plex *)dm->data; 4185 PetscInt *offsets; 4186 PetscInt supportSize; 4187 PetscInt pStart, pEnd, p; 4188 4189 PetscFunctionBegin; 4190 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4191 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4192 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4193 /* Calculate support sizes */ 4194 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4195 for (p = pStart; p < pEnd; ++p) { 4196 PetscInt dof, off, c; 4197 4198 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4199 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4200 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4201 } 4202 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4203 /* Calculate supports */ 4204 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4205 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4206 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4207 for (p = pStart; p < pEnd; ++p) { 4208 PetscInt dof, off, c; 4209 4210 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4211 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4212 for (c = off; c < off + dof; ++c) { 4213 const PetscInt q = mesh->cones[c]; 4214 PetscInt offS; 4215 4216 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4217 4218 mesh->supports[offS + offsets[q]] = p; 4219 ++offsets[q]; 4220 } 4221 } 4222 PetscCall(PetscFree(offsets)); 4223 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4224 PetscFunctionReturn(PETSC_SUCCESS); 4225 } 4226 4227 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4228 { 4229 IS stratumIS; 4230 4231 PetscFunctionBegin; 4232 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4233 if (PetscDefined(USE_DEBUG)) { 4234 PetscInt qStart, qEnd, numLevels, level; 4235 PetscBool overlap = PETSC_FALSE; 4236 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4237 for (level = 0; level < numLevels; level++) { 4238 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4239 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4240 overlap = PETSC_TRUE; 4241 break; 4242 } 4243 } 4244 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); 4245 } 4246 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4247 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4248 PetscCall(ISDestroy(&stratumIS)); 4249 PetscFunctionReturn(PETSC_SUCCESS); 4250 } 4251 4252 static PetscErrorCode DMPlexStratify_CellType_Private(DM dm, DMLabel label) 4253 { 4254 PetscInt *pMin, *pMax; 4255 PetscInt pStart, pEnd; 4256 PetscInt dmin = PETSC_MAX_INT, dmax = PETSC_MIN_INT; 4257 4258 PetscFunctionBegin; 4259 { 4260 DMLabel label2; 4261 4262 PetscCall(DMPlexGetCellTypeLabel(dm, &label2)); 4263 PetscCall(PetscObjectViewFromOptions((PetscObject)label2, NULL, "-ct_view")); 4264 } 4265 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4266 for (PetscInt p = pStart; p < pEnd; ++p) { 4267 DMPolytopeType ct; 4268 4269 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4270 dmin = PetscMin(DMPolytopeTypeGetDim(ct), dmin); 4271 dmax = PetscMax(DMPolytopeTypeGetDim(ct), dmax); 4272 } 4273 PetscCall(PetscMalloc2(dmax + 1, &pMin, dmax + 1, &pMax)); 4274 for (PetscInt d = dmin; d <= dmax; ++d) { 4275 pMin[d] = PETSC_MAX_INT; 4276 pMax[d] = PETSC_MIN_INT; 4277 } 4278 for (PetscInt p = pStart; p < pEnd; ++p) { 4279 DMPolytopeType ct; 4280 PetscInt d; 4281 4282 PetscCall(DMPlexGetCellType(dm, p, &ct)); 4283 d = DMPolytopeTypeGetDim(ct); 4284 pMin[d] = PetscMin(p, pMin[d]); 4285 pMax[d] = PetscMax(p, pMax[d]); 4286 } 4287 for (PetscInt d = dmin; d <= dmax; ++d) { 4288 if (pMin[d] > pMax[d]) continue; 4289 PetscCall(DMPlexCreateDepthStratum(dm, label, d, pMin[d], pMax[d] + 1)); 4290 } 4291 PetscCall(PetscFree2(pMin, pMax)); 4292 PetscFunctionReturn(PETSC_SUCCESS); 4293 } 4294 4295 static PetscErrorCode DMPlexStratify_Topological_Private(DM dm, DMLabel label) 4296 { 4297 PetscInt pStart, pEnd; 4298 PetscInt numRoots = 0, numLeaves = 0; 4299 4300 PetscFunctionBegin; 4301 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4302 { 4303 /* Initialize roots and count leaves */ 4304 PetscInt sMin = PETSC_MAX_INT; 4305 PetscInt sMax = PETSC_MIN_INT; 4306 PetscInt coneSize, supportSize; 4307 4308 for (PetscInt p = pStart; p < pEnd; ++p) { 4309 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4310 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4311 if (!coneSize && supportSize) { 4312 sMin = PetscMin(p, sMin); 4313 sMax = PetscMax(p, sMax); 4314 ++numRoots; 4315 } else if (!supportSize && coneSize) { 4316 ++numLeaves; 4317 } else if (!supportSize && !coneSize) { 4318 /* Isolated points */ 4319 sMin = PetscMin(p, sMin); 4320 sMax = PetscMax(p, sMax); 4321 } 4322 } 4323 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4324 } 4325 4326 if (numRoots + numLeaves == (pEnd - pStart)) { 4327 PetscInt sMin = PETSC_MAX_INT; 4328 PetscInt sMax = PETSC_MIN_INT; 4329 PetscInt coneSize, supportSize; 4330 4331 for (PetscInt p = pStart; p < pEnd; ++p) { 4332 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4333 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4334 if (!supportSize && coneSize) { 4335 sMin = PetscMin(p, sMin); 4336 sMax = PetscMax(p, sMax); 4337 } 4338 } 4339 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4340 } else { 4341 PetscInt level = 0; 4342 PetscInt qStart, qEnd; 4343 4344 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4345 while (qEnd > qStart) { 4346 PetscInt sMin = PETSC_MAX_INT; 4347 PetscInt sMax = PETSC_MIN_INT; 4348 4349 for (PetscInt q = qStart; q < qEnd; ++q) { 4350 const PetscInt *support; 4351 PetscInt supportSize; 4352 4353 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4354 PetscCall(DMPlexGetSupport(dm, q, &support)); 4355 for (PetscInt s = 0; s < supportSize; ++s) { 4356 sMin = PetscMin(support[s], sMin); 4357 sMax = PetscMax(support[s], sMax); 4358 } 4359 } 4360 PetscCall(DMLabelGetNumValues(label, &level)); 4361 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4362 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4363 } 4364 } 4365 PetscFunctionReturn(PETSC_SUCCESS); 4366 } 4367 4368 /*@ 4369 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4370 4371 Collective 4372 4373 Input Parameter: 4374 . dm - The `DMPLEX` 4375 4376 Level: beginner 4377 4378 Notes: 4379 The strata group all points of the same grade, and this function calculates the strata. This 4380 grade can be seen as the height (or depth) of the point in the DAG. 4381 4382 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4383 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4384 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4385 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4386 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4387 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4388 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4389 4390 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4391 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4392 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 4393 to interpolate only that one (e0), so that 4394 .vb 4395 cone(c0) = {e0, v2} 4396 cone(e0) = {v0, v1} 4397 .ve 4398 If `DMPlexStratify()` is run on this mesh, it will give depths 4399 .vb 4400 depth 0 = {v0, v1, v2} 4401 depth 1 = {e0, c0} 4402 .ve 4403 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4404 4405 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4406 4407 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4408 @*/ 4409 PetscErrorCode DMPlexStratify(DM dm) 4410 { 4411 DM_Plex *mesh = (DM_Plex *)dm->data; 4412 DMLabel label; 4413 PetscBool flg = PETSC_FALSE; 4414 4415 PetscFunctionBegin; 4416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4417 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4418 4419 // Create depth label 4420 PetscCall(DMCreateLabel(dm, "depth")); 4421 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4422 4423 PetscCall(PetscOptionsGetBool(NULL, dm->hdr.prefix, "-dm_plex_stratify_celltype", &flg, NULL)); 4424 if (flg) PetscCall(DMPlexStratify_CellType_Private(dm, label)); 4425 else PetscCall(DMPlexStratify_Topological_Private(dm, label)); 4426 4427 { /* just in case there is an empty process */ 4428 PetscInt numValues, maxValues = 0, v; 4429 4430 PetscCall(DMLabelGetNumValues(label, &numValues)); 4431 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4432 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4433 } 4434 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4435 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4436 PetscFunctionReturn(PETSC_SUCCESS); 4437 } 4438 4439 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4440 { 4441 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4442 PetscInt dim, depth, pheight, coneSize; 4443 4444 PetscFunctionBeginHot; 4445 PetscCall(DMGetDimension(dm, &dim)); 4446 PetscCall(DMPlexGetDepth(dm, &depth)); 4447 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4448 pheight = depth - pdepth; 4449 if (depth <= 1) { 4450 switch (pdepth) { 4451 case 0: 4452 ct = DM_POLYTOPE_POINT; 4453 break; 4454 case 1: 4455 switch (coneSize) { 4456 case 2: 4457 ct = DM_POLYTOPE_SEGMENT; 4458 break; 4459 case 3: 4460 ct = DM_POLYTOPE_TRIANGLE; 4461 break; 4462 case 4: 4463 switch (dim) { 4464 case 2: 4465 ct = DM_POLYTOPE_QUADRILATERAL; 4466 break; 4467 case 3: 4468 ct = DM_POLYTOPE_TETRAHEDRON; 4469 break; 4470 default: 4471 break; 4472 } 4473 break; 4474 case 5: 4475 ct = DM_POLYTOPE_PYRAMID; 4476 break; 4477 case 6: 4478 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4479 break; 4480 case 8: 4481 ct = DM_POLYTOPE_HEXAHEDRON; 4482 break; 4483 default: 4484 break; 4485 } 4486 } 4487 } else { 4488 if (pdepth == 0) { 4489 ct = DM_POLYTOPE_POINT; 4490 } else if (pheight == 0) { 4491 switch (dim) { 4492 case 1: 4493 switch (coneSize) { 4494 case 2: 4495 ct = DM_POLYTOPE_SEGMENT; 4496 break; 4497 default: 4498 break; 4499 } 4500 break; 4501 case 2: 4502 switch (coneSize) { 4503 case 3: 4504 ct = DM_POLYTOPE_TRIANGLE; 4505 break; 4506 case 4: 4507 ct = DM_POLYTOPE_QUADRILATERAL; 4508 break; 4509 default: 4510 break; 4511 } 4512 break; 4513 case 3: 4514 switch (coneSize) { 4515 case 4: 4516 ct = DM_POLYTOPE_TETRAHEDRON; 4517 break; 4518 case 5: { 4519 const PetscInt *cone; 4520 PetscInt faceConeSize; 4521 4522 PetscCall(DMPlexGetCone(dm, p, &cone)); 4523 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4524 switch (faceConeSize) { 4525 case 3: 4526 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4527 break; 4528 case 4: 4529 ct = DM_POLYTOPE_PYRAMID; 4530 break; 4531 } 4532 } break; 4533 case 6: 4534 ct = DM_POLYTOPE_HEXAHEDRON; 4535 break; 4536 default: 4537 break; 4538 } 4539 break; 4540 default: 4541 break; 4542 } 4543 } else if (pheight > 0) { 4544 switch (coneSize) { 4545 case 2: 4546 ct = DM_POLYTOPE_SEGMENT; 4547 break; 4548 case 3: 4549 ct = DM_POLYTOPE_TRIANGLE; 4550 break; 4551 case 4: 4552 ct = DM_POLYTOPE_QUADRILATERAL; 4553 break; 4554 default: 4555 break; 4556 } 4557 } 4558 } 4559 *pt = ct; 4560 PetscFunctionReturn(PETSC_SUCCESS); 4561 } 4562 4563 /*@ 4564 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4565 4566 Collective 4567 4568 Input Parameter: 4569 . dm - The `DMPLEX` 4570 4571 Level: developer 4572 4573 Note: 4574 This function is normally called automatically when a cell type is requested. It creates an 4575 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4576 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4577 4578 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4579 4580 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4581 @*/ 4582 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4583 { 4584 DM_Plex *mesh; 4585 DMLabel ctLabel; 4586 PetscInt pStart, pEnd, p; 4587 4588 PetscFunctionBegin; 4589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4590 mesh = (DM_Plex *)dm->data; 4591 PetscCall(DMCreateLabel(dm, "celltype")); 4592 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4593 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4594 PetscCall(PetscFree(mesh->cellTypes)); 4595 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4596 for (p = pStart; p < pEnd; ++p) { 4597 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4598 PetscInt pdepth; 4599 4600 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4601 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4602 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4603 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4604 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4605 } 4606 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4607 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4608 PetscFunctionReturn(PETSC_SUCCESS); 4609 } 4610 4611 /*@C 4612 DMPlexGetJoin - Get an array for the join of the set of points 4613 4614 Not Collective 4615 4616 Input Parameters: 4617 + dm - The `DMPLEX` object 4618 . numPoints - The number of input points for the join 4619 - points - The input points 4620 4621 Output Parameters: 4622 + numCoveredPoints - The number of points in the join 4623 - coveredPoints - The points in the join 4624 4625 Level: intermediate 4626 4627 Note: 4628 Currently, this is restricted to a single level join 4629 4630 Fortran Notes: 4631 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4632 4633 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4634 @*/ 4635 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4636 { 4637 DM_Plex *mesh = (DM_Plex *)dm->data; 4638 PetscInt *join[2]; 4639 PetscInt joinSize, i = 0; 4640 PetscInt dof, off, p, c, m; 4641 PetscInt maxSupportSize; 4642 4643 PetscFunctionBegin; 4644 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4645 PetscAssertPointer(points, 3); 4646 PetscAssertPointer(numCoveredPoints, 4); 4647 PetscAssertPointer(coveredPoints, 5); 4648 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4649 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4650 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4651 /* Copy in support of first point */ 4652 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4653 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4654 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4655 /* Check each successive support */ 4656 for (p = 1; p < numPoints; ++p) { 4657 PetscInt newJoinSize = 0; 4658 4659 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4660 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4661 for (c = 0; c < dof; ++c) { 4662 const PetscInt point = mesh->supports[off + c]; 4663 4664 for (m = 0; m < joinSize; ++m) { 4665 if (point == join[i][m]) { 4666 join[1 - i][newJoinSize++] = point; 4667 break; 4668 } 4669 } 4670 } 4671 joinSize = newJoinSize; 4672 i = 1 - i; 4673 } 4674 *numCoveredPoints = joinSize; 4675 *coveredPoints = join[i]; 4676 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4677 PetscFunctionReturn(PETSC_SUCCESS); 4678 } 4679 4680 /*@C 4681 DMPlexRestoreJoin - Restore an array for the join of the set of points 4682 4683 Not Collective 4684 4685 Input Parameters: 4686 + dm - The `DMPLEX` object 4687 . numPoints - The number of input points for the join 4688 - points - The input points 4689 4690 Output Parameters: 4691 + numCoveredPoints - The number of points in the join 4692 - coveredPoints - The points in the join 4693 4694 Level: intermediate 4695 4696 Fortran Notes: 4697 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4698 4699 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4700 @*/ 4701 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4702 { 4703 PetscFunctionBegin; 4704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4705 if (points) PetscAssertPointer(points, 3); 4706 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4707 PetscAssertPointer(coveredPoints, 5); 4708 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4709 if (numCoveredPoints) *numCoveredPoints = 0; 4710 PetscFunctionReturn(PETSC_SUCCESS); 4711 } 4712 4713 /*@C 4714 DMPlexGetFullJoin - Get an array for the join of the set of points 4715 4716 Not Collective 4717 4718 Input Parameters: 4719 + dm - The `DMPLEX` object 4720 . numPoints - The number of input points for the join 4721 - points - The input points 4722 4723 Output Parameters: 4724 + numCoveredPoints - The number of points in the join 4725 - coveredPoints - The points in the join 4726 4727 Level: intermediate 4728 4729 Fortran Notes: 4730 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4731 4732 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4733 @*/ 4734 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4735 { 4736 PetscInt *offsets, **closures; 4737 PetscInt *join[2]; 4738 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4739 PetscInt p, d, c, m, ms; 4740 4741 PetscFunctionBegin; 4742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4743 PetscAssertPointer(points, 3); 4744 PetscAssertPointer(numCoveredPoints, 4); 4745 PetscAssertPointer(coveredPoints, 5); 4746 4747 PetscCall(DMPlexGetDepth(dm, &depth)); 4748 PetscCall(PetscCalloc1(numPoints, &closures)); 4749 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4750 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4751 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4752 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4753 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4754 4755 for (p = 0; p < numPoints; ++p) { 4756 PetscInt closureSize; 4757 4758 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4759 4760 offsets[p * (depth + 2) + 0] = 0; 4761 for (d = 0; d < depth + 1; ++d) { 4762 PetscInt pStart, pEnd, i; 4763 4764 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4765 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4766 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4767 offsets[p * (depth + 2) + d + 1] = i; 4768 break; 4769 } 4770 } 4771 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4772 } 4773 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); 4774 } 4775 for (d = 0; d < depth + 1; ++d) { 4776 PetscInt dof; 4777 4778 /* Copy in support of first point */ 4779 dof = offsets[d + 1] - offsets[d]; 4780 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4781 /* Check each successive cone */ 4782 for (p = 1; p < numPoints && joinSize; ++p) { 4783 PetscInt newJoinSize = 0; 4784 4785 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4786 for (c = 0; c < dof; ++c) { 4787 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4788 4789 for (m = 0; m < joinSize; ++m) { 4790 if (point == join[i][m]) { 4791 join[1 - i][newJoinSize++] = point; 4792 break; 4793 } 4794 } 4795 } 4796 joinSize = newJoinSize; 4797 i = 1 - i; 4798 } 4799 if (joinSize) break; 4800 } 4801 *numCoveredPoints = joinSize; 4802 *coveredPoints = join[i]; 4803 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4804 PetscCall(PetscFree(closures)); 4805 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4806 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4807 PetscFunctionReturn(PETSC_SUCCESS); 4808 } 4809 4810 /*@C 4811 DMPlexGetMeet - Get an array for the meet of the set of points 4812 4813 Not Collective 4814 4815 Input Parameters: 4816 + dm - The `DMPLEX` object 4817 . numPoints - The number of input points for the meet 4818 - points - The input points 4819 4820 Output Parameters: 4821 + numCoveringPoints - The number of points in the meet 4822 - coveringPoints - The points in the meet 4823 4824 Level: intermediate 4825 4826 Note: 4827 Currently, this is restricted to a single level meet 4828 4829 Fortran Notes: 4830 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4831 4832 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4833 @*/ 4834 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4835 { 4836 DM_Plex *mesh = (DM_Plex *)dm->data; 4837 PetscInt *meet[2]; 4838 PetscInt meetSize, i = 0; 4839 PetscInt dof, off, p, c, m; 4840 PetscInt maxConeSize; 4841 4842 PetscFunctionBegin; 4843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4844 PetscAssertPointer(points, 3); 4845 PetscAssertPointer(numCoveringPoints, 4); 4846 PetscAssertPointer(coveringPoints, 5); 4847 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4848 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4849 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4850 /* Copy in cone of first point */ 4851 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4852 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4853 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4854 /* Check each successive cone */ 4855 for (p = 1; p < numPoints; ++p) { 4856 PetscInt newMeetSize = 0; 4857 4858 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4859 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4860 for (c = 0; c < dof; ++c) { 4861 const PetscInt point = mesh->cones[off + c]; 4862 4863 for (m = 0; m < meetSize; ++m) { 4864 if (point == meet[i][m]) { 4865 meet[1 - i][newMeetSize++] = point; 4866 break; 4867 } 4868 } 4869 } 4870 meetSize = newMeetSize; 4871 i = 1 - i; 4872 } 4873 *numCoveringPoints = meetSize; 4874 *coveringPoints = meet[i]; 4875 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4876 PetscFunctionReturn(PETSC_SUCCESS); 4877 } 4878 4879 /*@C 4880 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4881 4882 Not Collective 4883 4884 Input Parameters: 4885 + dm - The `DMPLEX` object 4886 . numPoints - The number of input points for the meet 4887 - points - The input points 4888 4889 Output Parameters: 4890 + numCoveredPoints - The number of points in the meet 4891 - coveredPoints - The points in the meet 4892 4893 Level: intermediate 4894 4895 Fortran Notes: 4896 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4897 4898 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4899 @*/ 4900 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4901 { 4902 PetscFunctionBegin; 4903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4904 if (points) PetscAssertPointer(points, 3); 4905 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4906 PetscAssertPointer(coveredPoints, 5); 4907 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4908 if (numCoveredPoints) *numCoveredPoints = 0; 4909 PetscFunctionReturn(PETSC_SUCCESS); 4910 } 4911 4912 /*@C 4913 DMPlexGetFullMeet - Get an array for the meet of the set of points 4914 4915 Not Collective 4916 4917 Input Parameters: 4918 + dm - The `DMPLEX` object 4919 . numPoints - The number of input points for the meet 4920 - points - The input points 4921 4922 Output Parameters: 4923 + numCoveredPoints - The number of points in the meet 4924 - coveredPoints - The points in the meet 4925 4926 Level: intermediate 4927 4928 Fortran Notes: 4929 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4930 4931 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4932 @*/ 4933 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4934 { 4935 PetscInt *offsets, **closures; 4936 PetscInt *meet[2]; 4937 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4938 PetscInt p, h, c, m, mc; 4939 4940 PetscFunctionBegin; 4941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4942 PetscAssertPointer(points, 3); 4943 PetscAssertPointer(numCoveredPoints, 4); 4944 PetscAssertPointer(coveredPoints, 5); 4945 4946 PetscCall(DMPlexGetDepth(dm, &height)); 4947 PetscCall(PetscMalloc1(numPoints, &closures)); 4948 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4949 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4950 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4951 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4952 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4953 4954 for (p = 0; p < numPoints; ++p) { 4955 PetscInt closureSize; 4956 4957 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4958 4959 offsets[p * (height + 2) + 0] = 0; 4960 for (h = 0; h < height + 1; ++h) { 4961 PetscInt pStart, pEnd, i; 4962 4963 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4964 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4965 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4966 offsets[p * (height + 2) + h + 1] = i; 4967 break; 4968 } 4969 } 4970 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4971 } 4972 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); 4973 } 4974 for (h = 0; h < height + 1; ++h) { 4975 PetscInt dof; 4976 4977 /* Copy in cone of first point */ 4978 dof = offsets[h + 1] - offsets[h]; 4979 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4980 /* Check each successive cone */ 4981 for (p = 1; p < numPoints && meetSize; ++p) { 4982 PetscInt newMeetSize = 0; 4983 4984 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4985 for (c = 0; c < dof; ++c) { 4986 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4987 4988 for (m = 0; m < meetSize; ++m) { 4989 if (point == meet[i][m]) { 4990 meet[1 - i][newMeetSize++] = point; 4991 break; 4992 } 4993 } 4994 } 4995 meetSize = newMeetSize; 4996 i = 1 - i; 4997 } 4998 if (meetSize) break; 4999 } 5000 *numCoveredPoints = meetSize; 5001 *coveredPoints = meet[i]; 5002 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 5003 PetscCall(PetscFree(closures)); 5004 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 5005 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 5006 PetscFunctionReturn(PETSC_SUCCESS); 5007 } 5008 5009 /*@C 5010 DMPlexEqual - Determine if two `DM` have the same topology 5011 5012 Not Collective 5013 5014 Input Parameters: 5015 + dmA - A `DMPLEX` object 5016 - dmB - A `DMPLEX` object 5017 5018 Output Parameter: 5019 . equal - `PETSC_TRUE` if the topologies are identical 5020 5021 Level: intermediate 5022 5023 Note: 5024 We are not solving graph isomorphism, so we do not permute. 5025 5026 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5027 @*/ 5028 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 5029 { 5030 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 5031 5032 PetscFunctionBegin; 5033 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 5034 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 5035 PetscAssertPointer(equal, 3); 5036 5037 *equal = PETSC_FALSE; 5038 PetscCall(DMPlexGetDepth(dmA, &depth)); 5039 PetscCall(DMPlexGetDepth(dmB, &depthB)); 5040 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 5041 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 5042 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 5043 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 5044 for (p = pStart; p < pEnd; ++p) { 5045 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 5046 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 5047 5048 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 5049 PetscCall(DMPlexGetCone(dmA, p, &cone)); 5050 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 5051 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 5052 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 5053 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 5054 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5055 for (c = 0; c < coneSize; ++c) { 5056 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5057 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 5058 } 5059 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 5060 PetscCall(DMPlexGetSupport(dmA, p, &support)); 5061 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 5062 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 5063 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 5064 for (s = 0; s < supportSize; ++s) { 5065 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 5066 } 5067 } 5068 *equal = PETSC_TRUE; 5069 PetscFunctionReturn(PETSC_SUCCESS); 5070 } 5071 5072 /*@C 5073 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 5074 5075 Not Collective 5076 5077 Input Parameters: 5078 + dm - The `DMPLEX` 5079 . cellDim - The cell dimension 5080 - numCorners - The number of vertices on a cell 5081 5082 Output Parameter: 5083 . numFaceVertices - The number of vertices on a face 5084 5085 Level: developer 5086 5087 Note: 5088 Of course this can only work for a restricted set of symmetric shapes 5089 5090 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 5091 @*/ 5092 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 5093 { 5094 MPI_Comm comm; 5095 5096 PetscFunctionBegin; 5097 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5098 PetscAssertPointer(numFaceVertices, 4); 5099 switch (cellDim) { 5100 case 0: 5101 *numFaceVertices = 0; 5102 break; 5103 case 1: 5104 *numFaceVertices = 1; 5105 break; 5106 case 2: 5107 switch (numCorners) { 5108 case 3: /* triangle */ 5109 *numFaceVertices = 2; /* Edge has 2 vertices */ 5110 break; 5111 case 4: /* quadrilateral */ 5112 *numFaceVertices = 2; /* Edge has 2 vertices */ 5113 break; 5114 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 5115 *numFaceVertices = 3; /* Edge has 3 vertices */ 5116 break; 5117 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 5118 *numFaceVertices = 3; /* Edge has 3 vertices */ 5119 break; 5120 default: 5121 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5122 } 5123 break; 5124 case 3: 5125 switch (numCorners) { 5126 case 4: /* tetradehdron */ 5127 *numFaceVertices = 3; /* Face has 3 vertices */ 5128 break; 5129 case 6: /* tet cohesive cells */ 5130 *numFaceVertices = 4; /* Face has 4 vertices */ 5131 break; 5132 case 8: /* hexahedron */ 5133 *numFaceVertices = 4; /* Face has 4 vertices */ 5134 break; 5135 case 9: /* tet cohesive Lagrange cells */ 5136 *numFaceVertices = 6; /* Face has 6 vertices */ 5137 break; 5138 case 10: /* quadratic tetrahedron */ 5139 *numFaceVertices = 6; /* Face has 6 vertices */ 5140 break; 5141 case 12: /* hex cohesive Lagrange cells */ 5142 *numFaceVertices = 6; /* Face has 6 vertices */ 5143 break; 5144 case 18: /* quadratic tet cohesive Lagrange cells */ 5145 *numFaceVertices = 6; /* Face has 6 vertices */ 5146 break; 5147 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 5148 *numFaceVertices = 9; /* Face has 9 vertices */ 5149 break; 5150 default: 5151 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 5152 } 5153 break; 5154 default: 5155 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 5156 } 5157 PetscFunctionReturn(PETSC_SUCCESS); 5158 } 5159 5160 /*@ 5161 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 5162 5163 Not Collective 5164 5165 Input Parameter: 5166 . dm - The `DMPLEX` object 5167 5168 Output Parameter: 5169 . depthLabel - The `DMLabel` recording point depth 5170 5171 Level: developer 5172 5173 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 5174 @*/ 5175 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 5176 { 5177 PetscFunctionBegin; 5178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5179 PetscAssertPointer(depthLabel, 2); 5180 *depthLabel = dm->depthLabel; 5181 PetscFunctionReturn(PETSC_SUCCESS); 5182 } 5183 5184 /*@ 5185 DMPlexGetDepth - Get the depth of the DAG representing this mesh 5186 5187 Not Collective 5188 5189 Input Parameter: 5190 . dm - The `DMPLEX` object 5191 5192 Output Parameter: 5193 . depth - The number of strata (breadth first levels) in the DAG 5194 5195 Level: developer 5196 5197 Notes: 5198 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 5199 5200 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 5201 5202 An empty mesh gives -1. 5203 5204 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 5205 @*/ 5206 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 5207 { 5208 DM_Plex *mesh = (DM_Plex *)dm->data; 5209 DMLabel label; 5210 PetscInt d = 0; 5211 5212 PetscFunctionBegin; 5213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5214 PetscAssertPointer(depth, 2); 5215 if (mesh->tr) { 5216 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 5217 } else { 5218 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5219 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 5220 *depth = d - 1; 5221 } 5222 PetscFunctionReturn(PETSC_SUCCESS); 5223 } 5224 5225 /*@ 5226 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5227 5228 Not Collective 5229 5230 Input Parameters: 5231 + dm - The `DMPLEX` object 5232 - depth - The requested depth 5233 5234 Output Parameters: 5235 + start - The first point at this `depth` 5236 - end - One beyond the last point at this `depth` 5237 5238 Level: developer 5239 5240 Notes: 5241 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5242 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5243 higher dimension, e.g., "edges". 5244 5245 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5246 @*/ 5247 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5248 { 5249 DM_Plex *mesh = (DM_Plex *)dm->data; 5250 DMLabel label; 5251 PetscInt pStart, pEnd; 5252 5253 PetscFunctionBegin; 5254 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5255 if (start) { 5256 PetscAssertPointer(start, 3); 5257 *start = 0; 5258 } 5259 if (end) { 5260 PetscAssertPointer(end, 4); 5261 *end = 0; 5262 } 5263 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5264 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5265 if (depth < 0) { 5266 if (start) *start = pStart; 5267 if (end) *end = pEnd; 5268 PetscFunctionReturn(PETSC_SUCCESS); 5269 } 5270 if (mesh->tr) { 5271 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5272 } else { 5273 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5274 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5275 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5276 } 5277 PetscFunctionReturn(PETSC_SUCCESS); 5278 } 5279 5280 /*@ 5281 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5282 5283 Not Collective 5284 5285 Input Parameters: 5286 + dm - The `DMPLEX` object 5287 - height - The requested height 5288 5289 Output Parameters: 5290 + start - The first point at this `height` 5291 - end - One beyond the last point at this `height` 5292 5293 Level: developer 5294 5295 Notes: 5296 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5297 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5298 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5299 5300 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5301 @*/ 5302 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5303 { 5304 DMLabel label; 5305 PetscInt depth, pStart, pEnd; 5306 5307 PetscFunctionBegin; 5308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5309 if (start) { 5310 PetscAssertPointer(start, 3); 5311 *start = 0; 5312 } 5313 if (end) { 5314 PetscAssertPointer(end, 4); 5315 *end = 0; 5316 } 5317 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5318 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5319 if (height < 0) { 5320 if (start) *start = pStart; 5321 if (end) *end = pEnd; 5322 PetscFunctionReturn(PETSC_SUCCESS); 5323 } 5324 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5325 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5326 else PetscCall(DMGetDimension(dm, &depth)); 5327 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5328 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5329 PetscFunctionReturn(PETSC_SUCCESS); 5330 } 5331 5332 /*@ 5333 DMPlexGetPointDepth - Get the `depth` of a given point 5334 5335 Not Collective 5336 5337 Input Parameters: 5338 + dm - The `DMPLEX` object 5339 - point - The point 5340 5341 Output Parameter: 5342 . depth - The depth of the `point` 5343 5344 Level: intermediate 5345 5346 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5347 @*/ 5348 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5349 { 5350 PetscFunctionBegin; 5351 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5352 PetscAssertPointer(depth, 3); 5353 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5354 PetscFunctionReturn(PETSC_SUCCESS); 5355 } 5356 5357 /*@ 5358 DMPlexGetPointHeight - Get the `height` of a given point 5359 5360 Not Collective 5361 5362 Input Parameters: 5363 + dm - The `DMPLEX` object 5364 - point - The point 5365 5366 Output Parameter: 5367 . height - The height of the `point` 5368 5369 Level: intermediate 5370 5371 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5372 @*/ 5373 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5374 { 5375 PetscInt n, pDepth; 5376 5377 PetscFunctionBegin; 5378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5379 PetscAssertPointer(height, 3); 5380 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5381 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5382 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5383 PetscFunctionReturn(PETSC_SUCCESS); 5384 } 5385 5386 /*@ 5387 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5388 5389 Not Collective 5390 5391 Input Parameter: 5392 . dm - The `DMPLEX` object 5393 5394 Output Parameter: 5395 . celltypeLabel - The `DMLabel` recording cell polytope type 5396 5397 Level: developer 5398 5399 Note: 5400 This function will trigger automatica computation of cell types. This can be disabled by calling 5401 `DMCreateLabel`(dm, "celltype") beforehand. 5402 5403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5404 @*/ 5405 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5406 { 5407 PetscFunctionBegin; 5408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5409 PetscAssertPointer(celltypeLabel, 2); 5410 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5411 *celltypeLabel = dm->celltypeLabel; 5412 PetscFunctionReturn(PETSC_SUCCESS); 5413 } 5414 5415 /*@ 5416 DMPlexGetCellType - Get the polytope type of a given cell 5417 5418 Not Collective 5419 5420 Input Parameters: 5421 + dm - The `DMPLEX` object 5422 - cell - The cell 5423 5424 Output Parameter: 5425 . celltype - The polytope type of the cell 5426 5427 Level: intermediate 5428 5429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5430 @*/ 5431 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5432 { 5433 DM_Plex *mesh = (DM_Plex *)dm->data; 5434 DMLabel label; 5435 PetscInt ct; 5436 5437 PetscFunctionBegin; 5438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5439 PetscAssertPointer(celltype, 3); 5440 if (mesh->tr) { 5441 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5442 } else { 5443 PetscInt pStart, pEnd; 5444 5445 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5446 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5447 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5448 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5449 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5450 for (PetscInt p = pStart; p < pEnd; p++) { 5451 PetscCall(DMLabelGetValue(label, p, &ct)); 5452 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5453 } 5454 } 5455 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5456 if (PetscDefined(USE_DEBUG)) { 5457 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5458 PetscCall(DMLabelGetValue(label, cell, &ct)); 5459 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5460 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5461 } 5462 } 5463 PetscFunctionReturn(PETSC_SUCCESS); 5464 } 5465 5466 /*@ 5467 DMPlexSetCellType - Set the polytope type of a given cell 5468 5469 Not Collective 5470 5471 Input Parameters: 5472 + dm - The `DMPLEX` object 5473 . cell - The cell 5474 - celltype - The polytope type of the cell 5475 5476 Level: advanced 5477 5478 Note: 5479 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5480 is executed. This function will override the computed type. However, if automatic classification will not succeed 5481 and a user wants to manually specify all types, the classification must be disabled by calling 5482 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5483 5484 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5485 @*/ 5486 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5487 { 5488 DM_Plex *mesh = (DM_Plex *)dm->data; 5489 DMLabel label; 5490 PetscInt pStart, pEnd; 5491 5492 PetscFunctionBegin; 5493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5494 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5495 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5496 PetscCall(DMLabelSetValue(label, cell, celltype)); 5497 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5498 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5499 PetscFunctionReturn(PETSC_SUCCESS); 5500 } 5501 5502 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5503 { 5504 PetscSection section, s; 5505 Mat m; 5506 PetscInt maxHeight; 5507 const char *prefix; 5508 5509 PetscFunctionBegin; 5510 PetscCall(DMClone(dm, cdm)); 5511 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5512 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5513 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5514 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5515 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5516 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5517 PetscCall(DMSetLocalSection(*cdm, section)); 5518 PetscCall(PetscSectionDestroy(§ion)); 5519 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5520 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5521 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5522 PetscCall(PetscSectionDestroy(&s)); 5523 PetscCall(MatDestroy(&m)); 5524 5525 PetscCall(DMSetNumFields(*cdm, 1)); 5526 PetscCall(DMCreateDS(*cdm)); 5527 (*cdm)->cloneOpts = PETSC_TRUE; 5528 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5529 PetscFunctionReturn(PETSC_SUCCESS); 5530 } 5531 5532 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5533 { 5534 Vec coordsLocal, cellCoordsLocal; 5535 DM coordsDM, cellCoordsDM; 5536 5537 PetscFunctionBegin; 5538 *field = NULL; 5539 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5540 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5541 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5542 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5543 if (coordsLocal && coordsDM) { 5544 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5545 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5546 } 5547 PetscFunctionReturn(PETSC_SUCCESS); 5548 } 5549 5550 /*@C 5551 DMPlexGetConeSection - Return a section which describes the layout of cone data 5552 5553 Not Collective 5554 5555 Input Parameter: 5556 . dm - The `DMPLEX` object 5557 5558 Output Parameter: 5559 . section - The `PetscSection` object 5560 5561 Level: developer 5562 5563 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5564 @*/ 5565 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5566 { 5567 DM_Plex *mesh = (DM_Plex *)dm->data; 5568 5569 PetscFunctionBegin; 5570 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5571 if (section) *section = mesh->coneSection; 5572 PetscFunctionReturn(PETSC_SUCCESS); 5573 } 5574 5575 /*@C 5576 DMPlexGetSupportSection - Return a section which describes the layout of support data 5577 5578 Not Collective 5579 5580 Input Parameter: 5581 . dm - The `DMPLEX` object 5582 5583 Output Parameter: 5584 . section - The `PetscSection` object 5585 5586 Level: developer 5587 5588 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5589 @*/ 5590 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5591 { 5592 DM_Plex *mesh = (DM_Plex *)dm->data; 5593 5594 PetscFunctionBegin; 5595 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5596 if (section) *section = mesh->supportSection; 5597 PetscFunctionReturn(PETSC_SUCCESS); 5598 } 5599 5600 /*@C 5601 DMPlexGetCones - Return cone data 5602 5603 Not Collective 5604 5605 Input Parameter: 5606 . dm - The `DMPLEX` object 5607 5608 Output Parameter: 5609 . cones - The cone for each point 5610 5611 Level: developer 5612 5613 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5614 @*/ 5615 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5616 { 5617 DM_Plex *mesh = (DM_Plex *)dm->data; 5618 5619 PetscFunctionBegin; 5620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5621 if (cones) *cones = mesh->cones; 5622 PetscFunctionReturn(PETSC_SUCCESS); 5623 } 5624 5625 /*@C 5626 DMPlexGetConeOrientations - Return cone orientation data 5627 5628 Not Collective 5629 5630 Input Parameter: 5631 . dm - The `DMPLEX` object 5632 5633 Output Parameter: 5634 . coneOrientations - The array of cone orientations for all points 5635 5636 Level: developer 5637 5638 Notes: 5639 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5640 5641 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5642 5643 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5644 @*/ 5645 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5646 { 5647 DM_Plex *mesh = (DM_Plex *)dm->data; 5648 5649 PetscFunctionBegin; 5650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5651 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5652 PetscFunctionReturn(PETSC_SUCCESS); 5653 } 5654 5655 /******************************** FEM Support **********************************/ 5656 5657 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 5658 { 5659 PetscInt depth; 5660 5661 PetscFunctionBegin; 5662 PetscCall(DMPlexGetDepth(plex, &depth)); 5663 PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 5664 if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 5665 PetscFunctionReturn(PETSC_SUCCESS); 5666 } 5667 5668 PetscErrorCode DMPlexGetAllFaces_Internal(DM plex, IS *faceIS) 5669 { 5670 PetscInt depth; 5671 5672 PetscFunctionBegin; 5673 PetscCall(DMPlexGetDepth(plex, &depth)); 5674 PetscCall(DMGetStratumIS(plex, "dim", depth - 1, faceIS)); 5675 if (!*faceIS) PetscCall(DMGetStratumIS(plex, "depth", depth - 1, faceIS)); 5676 PetscFunctionReturn(PETSC_SUCCESS); 5677 } 5678 5679 /* 5680 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5681 representing a line in the section. 5682 */ 5683 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(DM dm, PetscSection section, PetscInt field, PetscInt line, PetscInt *Nc, PetscInt *k, PetscBool *continuous, PetscBool *tensor) 5684 { 5685 PetscObject obj; 5686 PetscClassId id; 5687 PetscFE fe = NULL; 5688 5689 PetscFunctionBeginHot; 5690 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5691 PetscCall(DMGetField(dm, field, NULL, &obj)); 5692 PetscCall(PetscObjectGetClassId(obj, &id)); 5693 if (id == PETSCFE_CLASSID) fe = (PetscFE)obj; 5694 5695 if (!fe) { 5696 /* Assume the full interpolated mesh is in the chart; lines in particular */ 5697 /* An order k SEM disc has k-1 dofs on an edge */ 5698 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5699 *k = *k / *Nc + 1; 5700 } else { 5701 PetscInt dual_space_size, dim; 5702 PetscDualSpace dsp; 5703 5704 PetscCall(DMGetDimension(dm, &dim)); 5705 PetscCall(PetscFEGetDualSpace(fe, &dsp)); 5706 PetscCall(PetscDualSpaceGetDimension(dsp, &dual_space_size)); 5707 *k = (PetscInt)PetscCeilReal(PetscPowReal(dual_space_size / *Nc, 1.0 / dim)) - 1; 5708 PetscCall(PetscDualSpaceLagrangeGetContinuity(dsp, continuous)); 5709 PetscCall(PetscDualSpaceLagrangeGetTensor(dsp, tensor)); 5710 } 5711 PetscFunctionReturn(PETSC_SUCCESS); 5712 } 5713 5714 static PetscErrorCode GetFieldSize_Private(PetscInt dim, PetscInt k, PetscBool tensor, PetscInt *dof) 5715 { 5716 PetscFunctionBeginHot; 5717 if (tensor) { 5718 *dof = PetscPowInt(k + 1, dim); 5719 } else { 5720 switch (dim) { 5721 case 1: 5722 *dof = k + 1; 5723 break; 5724 case 2: 5725 *dof = ((k + 1) * (k + 2)) / 2; 5726 break; 5727 case 3: 5728 *dof = ((k + 1) * (k + 2) * (k + 3)) / 6; 5729 break; 5730 default: 5731 *dof = 0; 5732 } 5733 } 5734 PetscFunctionReturn(PETSC_SUCCESS); 5735 } 5736 5737 /*@ 5738 5739 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5740 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5741 section provided (or the section of the `DM`). 5742 5743 Input Parameters: 5744 + dm - The `DM` 5745 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5746 - section - The `PetscSection` to reorder, or `NULL` for the default section 5747 5748 Example: 5749 A typical interpolated single-quad mesh might order points as 5750 .vb 5751 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5752 5753 v4 -- e6 -- v3 5754 | | 5755 e7 c0 e8 5756 | | 5757 v1 -- e5 -- v2 5758 .ve 5759 5760 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5761 dofs in the order of points, e.g., 5762 .vb 5763 c0 -> [0,1,2,3] 5764 v1 -> [4] 5765 ... 5766 e5 -> [8, 9] 5767 .ve 5768 5769 which corresponds to the dofs 5770 .vb 5771 6 10 11 7 5772 13 2 3 15 5773 12 0 1 14 5774 4 8 9 5 5775 .ve 5776 5777 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5778 .vb 5779 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5780 .ve 5781 5782 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5783 .vb 5784 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5785 .ve 5786 5787 Level: developer 5788 5789 Notes: 5790 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5791 degree of the basis. 5792 5793 This is required to run with libCEED. 5794 5795 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5796 @*/ 5797 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5798 { 5799 DMLabel label; 5800 PetscInt dim, depth = -1, eStart = -1, Nf; 5801 PetscBool continuous = PETSC_TRUE, tensor = PETSC_TRUE; 5802 5803 PetscFunctionBegin; 5804 PetscCall(DMGetDimension(dm, &dim)); 5805 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5806 if (point < 0) { 5807 PetscInt sStart, sEnd; 5808 5809 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5810 point = sEnd - sStart ? sStart : point; 5811 } 5812 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5813 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5814 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5815 if (depth == 1) { 5816 eStart = point; 5817 } else if (depth == dim) { 5818 const PetscInt *cone; 5819 5820 PetscCall(DMPlexGetCone(dm, point, &cone)); 5821 if (dim == 2) eStart = cone[0]; 5822 else if (dim == 3) { 5823 const PetscInt *cone2; 5824 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5825 eStart = cone2[0]; 5826 } 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); 5827 } 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); 5828 5829 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5830 for (PetscInt d = 1; d <= dim; d++) { 5831 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5832 PetscInt *perm; 5833 5834 for (f = 0; f < Nf; ++f) { 5835 PetscInt dof; 5836 5837 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5838 PetscCheck(dim == 1 || tensor || !continuous, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Continuous field %" PetscInt_FMT " must have a tensor product discretization", f); 5839 if (!continuous && d < dim) continue; 5840 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5841 size += dof * Nc; 5842 } 5843 PetscCall(PetscMalloc1(size, &perm)); 5844 for (f = 0; f < Nf; ++f) { 5845 switch (d) { 5846 case 1: 5847 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5848 if (!continuous && d < dim) continue; 5849 /* 5850 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5851 We want [ vtx0; edge of length k-1; vtx1 ] 5852 */ 5853 if (continuous) { 5854 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5855 for (i = 0; i < k - 1; i++) 5856 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5857 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5858 foffset = offset; 5859 } else { 5860 PetscInt dof; 5861 5862 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5863 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5864 foffset = offset; 5865 } 5866 break; 5867 case 2: 5868 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5869 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5870 if (!continuous && d < dim) continue; 5871 /* The SEM order is 5872 5873 v_lb, {e_b}, v_rb, 5874 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5875 v_lt, reverse {e_t}, v_rt 5876 */ 5877 if (continuous) { 5878 const PetscInt of = 0; 5879 const PetscInt oeb = of + PetscSqr(k - 1); 5880 const PetscInt oer = oeb + (k - 1); 5881 const PetscInt oet = oer + (k - 1); 5882 const PetscInt oel = oet + (k - 1); 5883 const PetscInt ovlb = oel + (k - 1); 5884 const PetscInt ovrb = ovlb + 1; 5885 const PetscInt ovrt = ovrb + 1; 5886 const PetscInt ovlt = ovrt + 1; 5887 PetscInt o; 5888 5889 /* bottom */ 5890 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5891 for (o = oeb; o < oer; ++o) 5892 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5893 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5894 /* middle */ 5895 for (i = 0; i < k - 1; ++i) { 5896 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5897 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5898 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5899 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5900 } 5901 /* top */ 5902 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5903 for (o = oel - 1; o >= oet; --o) 5904 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5905 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5906 foffset = offset; 5907 } else { 5908 PetscInt dof; 5909 5910 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 5911 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 5912 foffset = offset; 5913 } 5914 break; 5915 case 3: 5916 /* The original hex closure is 5917 5918 {c, 5919 f_b, f_t, f_f, f_b, f_r, f_l, 5920 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5921 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5922 */ 5923 PetscCall(PetscSectionFieldGetTensorDegree_Private(dm, section, f, eStart, &Nc, &k, &continuous, &tensor)); 5924 if (!continuous && d < dim) continue; 5925 /* The SEM order is 5926 Bottom Slice 5927 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5928 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5929 v_blb, {e_bb}, v_brb, 5930 5931 Middle Slice (j) 5932 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5933 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5934 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5935 5936 Top Slice 5937 v_tlf, {e_tf}, v_trf, 5938 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5939 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5940 */ 5941 if (continuous) { 5942 const PetscInt oc = 0; 5943 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5944 const PetscInt oft = ofb + PetscSqr(k - 1); 5945 const PetscInt off = oft + PetscSqr(k - 1); 5946 const PetscInt ofk = off + PetscSqr(k - 1); 5947 const PetscInt ofr = ofk + PetscSqr(k - 1); 5948 const PetscInt ofl = ofr + PetscSqr(k - 1); 5949 const PetscInt oebl = ofl + PetscSqr(k - 1); 5950 const PetscInt oebb = oebl + (k - 1); 5951 const PetscInt oebr = oebb + (k - 1); 5952 const PetscInt oebf = oebr + (k - 1); 5953 const PetscInt oetf = oebf + (k - 1); 5954 const PetscInt oetr = oetf + (k - 1); 5955 const PetscInt oetb = oetr + (k - 1); 5956 const PetscInt oetl = oetb + (k - 1); 5957 const PetscInt oerf = oetl + (k - 1); 5958 const PetscInt oelf = oerf + (k - 1); 5959 const PetscInt oelb = oelf + (k - 1); 5960 const PetscInt oerb = oelb + (k - 1); 5961 const PetscInt ovblf = oerb + (k - 1); 5962 const PetscInt ovblb = ovblf + 1; 5963 const PetscInt ovbrb = ovblb + 1; 5964 const PetscInt ovbrf = ovbrb + 1; 5965 const PetscInt ovtlf = ovbrf + 1; 5966 const PetscInt ovtrf = ovtlf + 1; 5967 const PetscInt ovtrb = ovtrf + 1; 5968 const PetscInt ovtlb = ovtrb + 1; 5969 PetscInt o, n; 5970 5971 /* Bottom Slice */ 5972 /* bottom */ 5973 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5974 for (o = oetf - 1; o >= oebf; --o) 5975 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5976 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5977 /* middle */ 5978 for (i = 0; i < k - 1; ++i) { 5979 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5980 for (n = 0; n < k - 1; ++n) { 5981 o = ofb + n * (k - 1) + i; 5982 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5983 } 5984 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5985 } 5986 /* top */ 5987 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5988 for (o = oebb; o < oebr; ++o) 5989 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5990 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5991 5992 /* Middle Slice */ 5993 for (j = 0; j < k - 1; ++j) { 5994 /* bottom */ 5995 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5996 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5997 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5998 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5999 /* middle */ 6000 for (i = 0; i < k - 1; ++i) { 6001 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 6002 for (n = 0; n < k - 1; ++n) 6003 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 6004 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 6005 } 6006 /* top */ 6007 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 6008 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 6009 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6010 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 6011 } 6012 6013 /* Top Slice */ 6014 /* bottom */ 6015 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 6016 for (o = oetf; o < oetr; ++o) 6017 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6018 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 6019 /* middle */ 6020 for (i = 0; i < k - 1; ++i) { 6021 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 6022 for (n = 0; n < k - 1; ++n) 6023 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 6024 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 6025 } 6026 /* top */ 6027 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 6028 for (o = oetl - 1; o >= oetb; --o) 6029 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 6030 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 6031 6032 foffset = offset; 6033 } else { 6034 PetscInt dof; 6035 6036 PetscCall(GetFieldSize_Private(d, k, tensor, &dof)); 6037 for (i = 0; i < dof * Nc; ++i, ++offset) perm[offset] = i + foffset; 6038 foffset = offset; 6039 } 6040 break; 6041 default: 6042 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 6043 } 6044 } 6045 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 6046 /* Check permutation */ 6047 { 6048 PetscInt *check; 6049 6050 PetscCall(PetscMalloc1(size, &check)); 6051 for (i = 0; i < size; ++i) { 6052 check[i] = -1; 6053 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 6054 } 6055 for (i = 0; i < size; ++i) check[perm[i]] = i; 6056 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 6057 PetscCall(PetscFree(check)); 6058 } 6059 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 6060 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 6061 PetscInt *loc_perm; 6062 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 6063 for (PetscInt i = 0; i < size; i++) { 6064 loc_perm[i] = perm[i]; 6065 loc_perm[size + i] = size + perm[i]; 6066 } 6067 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 6068 } 6069 } 6070 PetscFunctionReturn(PETSC_SUCCESS); 6071 } 6072 6073 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 6074 { 6075 PetscDS prob; 6076 PetscInt depth, Nf, h; 6077 DMLabel label; 6078 6079 PetscFunctionBeginHot; 6080 PetscCall(DMGetDS(dm, &prob)); 6081 Nf = prob->Nf; 6082 label = dm->depthLabel; 6083 *dspace = NULL; 6084 if (field < Nf) { 6085 PetscObject disc = prob->disc[field]; 6086 6087 if (disc->classid == PETSCFE_CLASSID) { 6088 PetscDualSpace dsp; 6089 6090 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 6091 PetscCall(DMLabelGetNumValues(label, &depth)); 6092 PetscCall(DMLabelGetValue(label, point, &h)); 6093 h = depth - 1 - h; 6094 if (h) { 6095 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 6096 } else { 6097 *dspace = dsp; 6098 } 6099 } 6100 } 6101 PetscFunctionReturn(PETSC_SUCCESS); 6102 } 6103 6104 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6105 { 6106 PetscScalar *array; 6107 const PetscScalar *vArray; 6108 const PetscInt *cone, *coneO; 6109 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 6110 6111 PetscFunctionBeginHot; 6112 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6113 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6114 PetscCall(DMPlexGetCone(dm, point, &cone)); 6115 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6116 if (!values || !*values) { 6117 if ((point >= pStart) && (point < pEnd)) { 6118 PetscInt dof; 6119 6120 PetscCall(PetscSectionGetDof(section, point, &dof)); 6121 size += dof; 6122 } 6123 for (p = 0; p < numPoints; ++p) { 6124 const PetscInt cp = cone[p]; 6125 PetscInt dof; 6126 6127 if ((cp < pStart) || (cp >= pEnd)) continue; 6128 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6129 size += dof; 6130 } 6131 if (!values) { 6132 if (csize) *csize = size; 6133 PetscFunctionReturn(PETSC_SUCCESS); 6134 } 6135 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 6136 } else { 6137 array = *values; 6138 } 6139 size = 0; 6140 PetscCall(VecGetArrayRead(v, &vArray)); 6141 if ((point >= pStart) && (point < pEnd)) { 6142 PetscInt dof, off, d; 6143 const PetscScalar *varr; 6144 6145 PetscCall(PetscSectionGetDof(section, point, &dof)); 6146 PetscCall(PetscSectionGetOffset(section, point, &off)); 6147 varr = PetscSafePointerPlusOffset(vArray, off); 6148 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6149 size += dof; 6150 } 6151 for (p = 0; p < numPoints; ++p) { 6152 const PetscInt cp = cone[p]; 6153 PetscInt o = coneO[p]; 6154 PetscInt dof, off, d; 6155 const PetscScalar *varr; 6156 6157 if ((cp < pStart) || (cp >= pEnd)) continue; 6158 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6159 PetscCall(PetscSectionGetOffset(section, cp, &off)); 6160 varr = PetscSafePointerPlusOffset(vArray, off); 6161 if (o >= 0) { 6162 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 6163 } else { 6164 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 6165 } 6166 size += dof; 6167 } 6168 PetscCall(VecRestoreArrayRead(v, &vArray)); 6169 if (!*values) { 6170 if (csize) *csize = size; 6171 *values = array; 6172 } else { 6173 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6174 *csize = size; 6175 } 6176 PetscFunctionReturn(PETSC_SUCCESS); 6177 } 6178 6179 /* Compress out points not in the section */ 6180 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 6181 { 6182 const PetscInt np = *numPoints; 6183 PetscInt pStart, pEnd, p, q; 6184 6185 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6186 for (p = 0, q = 0; p < np; ++p) { 6187 const PetscInt r = points[p * 2]; 6188 if ((r >= pStart) && (r < pEnd)) { 6189 points[q * 2] = r; 6190 points[q * 2 + 1] = points[p * 2 + 1]; 6191 ++q; 6192 } 6193 } 6194 *numPoints = q; 6195 return PETSC_SUCCESS; 6196 } 6197 6198 /* Compressed closure does not apply closure permutation */ 6199 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6200 { 6201 const PetscInt *cla = NULL; 6202 PetscInt np, *pts = NULL; 6203 6204 PetscFunctionBeginHot; 6205 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 6206 if (!ornt && *clPoints) { 6207 PetscInt dof, off; 6208 6209 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 6210 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 6211 PetscCall(ISGetIndices(*clPoints, &cla)); 6212 np = dof / 2; 6213 pts = PetscSafePointerPlusOffset((PetscInt *)cla, off); 6214 } else { 6215 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 6216 PetscCall(CompressPoints_Private(section, &np, pts)); 6217 } 6218 *numPoints = np; 6219 *points = pts; 6220 *clp = cla; 6221 PetscFunctionReturn(PETSC_SUCCESS); 6222 } 6223 6224 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 6225 { 6226 PetscFunctionBeginHot; 6227 if (!*clPoints) { 6228 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 6229 } else { 6230 PetscCall(ISRestoreIndices(*clPoints, clp)); 6231 } 6232 *numPoints = 0; 6233 *points = NULL; 6234 *clSec = NULL; 6235 *clPoints = NULL; 6236 *clp = NULL; 6237 PetscFunctionReturn(PETSC_SUCCESS); 6238 } 6239 6240 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 6241 { 6242 PetscInt offset = 0, p; 6243 const PetscInt **perms = NULL; 6244 const PetscScalar **flips = NULL; 6245 6246 PetscFunctionBeginHot; 6247 *size = 0; 6248 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6249 for (p = 0; p < numPoints; p++) { 6250 const PetscInt point = points[2 * p]; 6251 const PetscInt *perm = perms ? perms[p] : NULL; 6252 const PetscScalar *flip = flips ? flips[p] : NULL; 6253 PetscInt dof, off, d; 6254 const PetscScalar *varr; 6255 6256 PetscCall(PetscSectionGetDof(section, point, &dof)); 6257 PetscCall(PetscSectionGetOffset(section, point, &off)); 6258 varr = PetscSafePointerPlusOffset(vArray, off); 6259 if (clperm) { 6260 if (perm) { 6261 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 6262 } else { 6263 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 6264 } 6265 if (flip) { 6266 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 6267 } 6268 } else { 6269 if (perm) { 6270 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 6271 } else { 6272 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 6273 } 6274 if (flip) { 6275 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 6276 } 6277 } 6278 offset += dof; 6279 } 6280 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6281 *size = offset; 6282 PetscFunctionReturn(PETSC_SUCCESS); 6283 } 6284 6285 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[]) 6286 { 6287 PetscInt offset = 0, f; 6288 6289 PetscFunctionBeginHot; 6290 *size = 0; 6291 for (f = 0; f < numFields; ++f) { 6292 PetscInt p; 6293 const PetscInt **perms = NULL; 6294 const PetscScalar **flips = NULL; 6295 6296 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6297 for (p = 0; p < numPoints; p++) { 6298 const PetscInt point = points[2 * p]; 6299 PetscInt fdof, foff, b; 6300 const PetscScalar *varr; 6301 const PetscInt *perm = perms ? perms[p] : NULL; 6302 const PetscScalar *flip = flips ? flips[p] : NULL; 6303 6304 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6305 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6306 varr = &vArray[foff]; 6307 if (clperm) { 6308 if (perm) { 6309 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6310 } else { 6311 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6312 } 6313 if (flip) { 6314 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6315 } 6316 } else { 6317 if (perm) { 6318 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6319 } else { 6320 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6321 } 6322 if (flip) { 6323 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6324 } 6325 } 6326 offset += fdof; 6327 } 6328 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6329 } 6330 *size = offset; 6331 PetscFunctionReturn(PETSC_SUCCESS); 6332 } 6333 6334 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, PetscBool useClPerm, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6335 { 6336 PetscSection clSection; 6337 IS clPoints; 6338 PetscInt *points = NULL; 6339 const PetscInt *clp, *perm = NULL; 6340 PetscInt depth, numFields, numPoints, asize; 6341 6342 PetscFunctionBeginHot; 6343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6344 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6345 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6346 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 6347 PetscCall(DMPlexGetDepth(dm, &depth)); 6348 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6349 if (depth == 1 && numFields < 2) { 6350 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6351 PetscFunctionReturn(PETSC_SUCCESS); 6352 } 6353 /* Get points */ 6354 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6355 /* Get sizes */ 6356 asize = 0; 6357 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6358 PetscInt dof; 6359 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6360 asize += dof; 6361 } 6362 if (values) { 6363 const PetscScalar *vArray; 6364 PetscInt size; 6365 6366 if (*values) { 6367 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); 6368 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6369 if (useClPerm) PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6370 PetscCall(VecGetArrayRead(v, &vArray)); 6371 /* Get values */ 6372 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6373 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6374 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6375 /* Cleanup array */ 6376 PetscCall(VecRestoreArrayRead(v, &vArray)); 6377 } 6378 if (csize) *csize = asize; 6379 /* Cleanup points */ 6380 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6381 PetscFunctionReturn(PETSC_SUCCESS); 6382 } 6383 6384 /*@C 6385 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6386 6387 Not collective 6388 6389 Input Parameters: 6390 + dm - The `DM` 6391 . section - The section describing the layout in `v`, or `NULL` to use the default section 6392 . v - The local vector 6393 - point - The point in the `DM` 6394 6395 Input/Output Parameters: 6396 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6397 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6398 if the user provided `NULL`, it is a borrowed array and should not be freed 6399 6400 Level: intermediate 6401 6402 Notes: 6403 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6404 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6405 assembly function, and a user may already have allocated storage for this operation. 6406 6407 A typical use could be 6408 .vb 6409 values = NULL; 6410 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6411 for (cl = 0; cl < clSize; ++cl) { 6412 <Compute on closure> 6413 } 6414 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6415 .ve 6416 or 6417 .vb 6418 PetscMalloc1(clMaxSize, &values); 6419 for (p = pStart; p < pEnd; ++p) { 6420 clSize = clMaxSize; 6421 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6422 for (cl = 0; cl < clSize; ++cl) { 6423 <Compute on closure> 6424 } 6425 } 6426 PetscFree(values); 6427 .ve 6428 6429 Fortran Notes: 6430 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6431 6432 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6433 @*/ 6434 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6435 { 6436 PetscFunctionBeginHot; 6437 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, PETSC_TRUE, v, point, 0, csize, values)); 6438 PetscFunctionReturn(PETSC_SUCCESS); 6439 } 6440 6441 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6442 { 6443 DMLabel depthLabel; 6444 PetscSection clSection; 6445 IS clPoints; 6446 PetscScalar *array; 6447 const PetscScalar *vArray; 6448 PetscInt *points = NULL; 6449 const PetscInt *clp, *perm = NULL; 6450 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6451 6452 PetscFunctionBeginHot; 6453 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6454 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6455 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6456 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6457 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6458 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6459 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6460 if (mdepth == 1 && numFields < 2) { 6461 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6462 PetscFunctionReturn(PETSC_SUCCESS); 6463 } 6464 /* Get points */ 6465 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6466 for (clsize = 0, p = 0; p < Np; p++) { 6467 PetscInt dof; 6468 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6469 clsize += dof; 6470 } 6471 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6472 /* Filter points */ 6473 for (p = 0; p < numPoints * 2; p += 2) { 6474 PetscInt dep; 6475 6476 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6477 if (dep != depth) continue; 6478 points[Np * 2 + 0] = points[p]; 6479 points[Np * 2 + 1] = points[p + 1]; 6480 ++Np; 6481 } 6482 /* Get array */ 6483 if (!values || !*values) { 6484 PetscInt asize = 0, dof; 6485 6486 for (p = 0; p < Np * 2; p += 2) { 6487 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6488 asize += dof; 6489 } 6490 if (!values) { 6491 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6492 if (csize) *csize = asize; 6493 PetscFunctionReturn(PETSC_SUCCESS); 6494 } 6495 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6496 } else { 6497 array = *values; 6498 } 6499 PetscCall(VecGetArrayRead(v, &vArray)); 6500 /* Get values */ 6501 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6502 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6503 /* Cleanup points */ 6504 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6505 /* Cleanup array */ 6506 PetscCall(VecRestoreArrayRead(v, &vArray)); 6507 if (!*values) { 6508 if (csize) *csize = size; 6509 *values = array; 6510 } else { 6511 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6512 *csize = size; 6513 } 6514 PetscFunctionReturn(PETSC_SUCCESS); 6515 } 6516 6517 /*@C 6518 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6519 6520 Not collective 6521 6522 Input Parameters: 6523 + dm - The `DM` 6524 . section - The section describing the layout in `v`, or `NULL` to use the default section 6525 . v - The local vector 6526 . point - The point in the `DM` 6527 . csize - The number of values in the closure, or `NULL` 6528 - values - The array of values, which is a borrowed array and should not be freed 6529 6530 Level: intermediate 6531 6532 Note: 6533 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6534 6535 Fortran Notes: 6536 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6537 6538 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6539 @*/ 6540 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6541 { 6542 PetscInt size = 0; 6543 6544 PetscFunctionBegin; 6545 /* Should work without recalculating size */ 6546 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6547 *values = NULL; 6548 PetscFunctionReturn(PETSC_SUCCESS); 6549 } 6550 6551 static inline void add(PetscScalar *x, PetscScalar y) 6552 { 6553 *x += y; 6554 } 6555 static inline void insert(PetscScalar *x, PetscScalar y) 6556 { 6557 *x = y; 6558 } 6559 6560 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[]) 6561 { 6562 PetscInt cdof; /* The number of constraints on this point */ 6563 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6564 PetscScalar *a; 6565 PetscInt off, cind = 0, k; 6566 6567 PetscFunctionBegin; 6568 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6569 PetscCall(PetscSectionGetOffset(section, point, &off)); 6570 a = &array[off]; 6571 if (!cdof || setBC) { 6572 if (clperm) { 6573 if (perm) { 6574 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6575 } else { 6576 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6577 } 6578 } else { 6579 if (perm) { 6580 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6581 } else { 6582 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6583 } 6584 } 6585 } else { 6586 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6587 if (clperm) { 6588 if (perm) { 6589 for (k = 0; k < dof; ++k) { 6590 if ((cind < cdof) && (k == cdofs[cind])) { 6591 ++cind; 6592 continue; 6593 } 6594 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6595 } 6596 } else { 6597 for (k = 0; k < dof; ++k) { 6598 if ((cind < cdof) && (k == cdofs[cind])) { 6599 ++cind; 6600 continue; 6601 } 6602 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6603 } 6604 } 6605 } else { 6606 if (perm) { 6607 for (k = 0; k < dof; ++k) { 6608 if ((cind < cdof) && (k == cdofs[cind])) { 6609 ++cind; 6610 continue; 6611 } 6612 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6613 } 6614 } else { 6615 for (k = 0; k < dof; ++k) { 6616 if ((cind < cdof) && (k == cdofs[cind])) { 6617 ++cind; 6618 continue; 6619 } 6620 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6621 } 6622 } 6623 } 6624 } 6625 PetscFunctionReturn(PETSC_SUCCESS); 6626 } 6627 6628 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[]) 6629 { 6630 PetscInt cdof; /* The number of constraints on this point */ 6631 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6632 PetscScalar *a; 6633 PetscInt off, cind = 0, k; 6634 6635 PetscFunctionBegin; 6636 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6637 PetscCall(PetscSectionGetOffset(section, point, &off)); 6638 a = &array[off]; 6639 if (cdof) { 6640 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6641 if (clperm) { 6642 if (perm) { 6643 for (k = 0; k < dof; ++k) { 6644 if ((cind < cdof) && (k == cdofs[cind])) { 6645 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6646 cind++; 6647 } 6648 } 6649 } else { 6650 for (k = 0; k < dof; ++k) { 6651 if ((cind < cdof) && (k == cdofs[cind])) { 6652 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6653 cind++; 6654 } 6655 } 6656 } 6657 } else { 6658 if (perm) { 6659 for (k = 0; k < dof; ++k) { 6660 if ((cind < cdof) && (k == cdofs[cind])) { 6661 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6662 cind++; 6663 } 6664 } 6665 } else { 6666 for (k = 0; k < dof; ++k) { 6667 if ((cind < cdof) && (k == cdofs[cind])) { 6668 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6669 cind++; 6670 } 6671 } 6672 } 6673 } 6674 } 6675 PetscFunctionReturn(PETSC_SUCCESS); 6676 } 6677 6678 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[]) 6679 { 6680 PetscScalar *a; 6681 PetscInt fdof, foff, fcdof, foffset = *offset; 6682 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6683 PetscInt cind = 0, b; 6684 6685 PetscFunctionBegin; 6686 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6687 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6688 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6689 a = &array[foff]; 6690 if (!fcdof || setBC) { 6691 if (clperm) { 6692 if (perm) { 6693 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6694 } else { 6695 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6696 } 6697 } else { 6698 if (perm) { 6699 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6700 } else { 6701 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6702 } 6703 } 6704 } else { 6705 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6706 if (clperm) { 6707 if (perm) { 6708 for (b = 0; b < fdof; b++) { 6709 if ((cind < fcdof) && (b == fcdofs[cind])) { 6710 ++cind; 6711 continue; 6712 } 6713 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6714 } 6715 } else { 6716 for (b = 0; b < fdof; b++) { 6717 if ((cind < fcdof) && (b == fcdofs[cind])) { 6718 ++cind; 6719 continue; 6720 } 6721 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6722 } 6723 } 6724 } else { 6725 if (perm) { 6726 for (b = 0; b < fdof; b++) { 6727 if ((cind < fcdof) && (b == fcdofs[cind])) { 6728 ++cind; 6729 continue; 6730 } 6731 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6732 } 6733 } else { 6734 for (b = 0; b < fdof; b++) { 6735 if ((cind < fcdof) && (b == fcdofs[cind])) { 6736 ++cind; 6737 continue; 6738 } 6739 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6740 } 6741 } 6742 } 6743 } 6744 *offset += fdof; 6745 PetscFunctionReturn(PETSC_SUCCESS); 6746 } 6747 6748 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[]) 6749 { 6750 PetscScalar *a; 6751 PetscInt fdof, foff, fcdof, foffset = *offset; 6752 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6753 PetscInt Nc, cind = 0, ncind = 0, b; 6754 PetscBool ncSet, fcSet; 6755 6756 PetscFunctionBegin; 6757 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6758 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6759 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6760 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6761 a = &array[foff]; 6762 if (fcdof) { 6763 /* We just override fcdof and fcdofs with Ncc and comps */ 6764 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6765 if (clperm) { 6766 if (perm) { 6767 if (comps) { 6768 for (b = 0; b < fdof; b++) { 6769 ncSet = fcSet = PETSC_FALSE; 6770 if (b % Nc == comps[ncind]) { 6771 ncind = (ncind + 1) % Ncc; 6772 ncSet = PETSC_TRUE; 6773 } 6774 if ((cind < fcdof) && (b == fcdofs[cind])) { 6775 ++cind; 6776 fcSet = PETSC_TRUE; 6777 } 6778 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6779 } 6780 } else { 6781 for (b = 0; b < fdof; b++) { 6782 if ((cind < fcdof) && (b == fcdofs[cind])) { 6783 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6784 ++cind; 6785 } 6786 } 6787 } 6788 } else { 6789 if (comps) { 6790 for (b = 0; b < fdof; b++) { 6791 ncSet = fcSet = PETSC_FALSE; 6792 if (b % Nc == comps[ncind]) { 6793 ncind = (ncind + 1) % Ncc; 6794 ncSet = PETSC_TRUE; 6795 } 6796 if ((cind < fcdof) && (b == fcdofs[cind])) { 6797 ++cind; 6798 fcSet = PETSC_TRUE; 6799 } 6800 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6801 } 6802 } else { 6803 for (b = 0; b < fdof; b++) { 6804 if ((cind < fcdof) && (b == fcdofs[cind])) { 6805 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6806 ++cind; 6807 } 6808 } 6809 } 6810 } 6811 } else { 6812 if (perm) { 6813 if (comps) { 6814 for (b = 0; b < fdof; b++) { 6815 ncSet = fcSet = PETSC_FALSE; 6816 if (b % Nc == comps[ncind]) { 6817 ncind = (ncind + 1) % Ncc; 6818 ncSet = PETSC_TRUE; 6819 } 6820 if ((cind < fcdof) && (b == fcdofs[cind])) { 6821 ++cind; 6822 fcSet = PETSC_TRUE; 6823 } 6824 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6825 } 6826 } else { 6827 for (b = 0; b < fdof; b++) { 6828 if ((cind < fcdof) && (b == fcdofs[cind])) { 6829 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6830 ++cind; 6831 } 6832 } 6833 } 6834 } else { 6835 if (comps) { 6836 for (b = 0; b < fdof; b++) { 6837 ncSet = fcSet = PETSC_FALSE; 6838 if (b % Nc == comps[ncind]) { 6839 ncind = (ncind + 1) % Ncc; 6840 ncSet = PETSC_TRUE; 6841 } 6842 if ((cind < fcdof) && (b == fcdofs[cind])) { 6843 ++cind; 6844 fcSet = PETSC_TRUE; 6845 } 6846 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6847 } 6848 } else { 6849 for (b = 0; b < fdof; b++) { 6850 if ((cind < fcdof) && (b == fcdofs[cind])) { 6851 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6852 ++cind; 6853 } 6854 } 6855 } 6856 } 6857 } 6858 } 6859 *offset += fdof; 6860 PetscFunctionReturn(PETSC_SUCCESS); 6861 } 6862 6863 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6864 { 6865 PetscScalar *array; 6866 const PetscInt *cone, *coneO; 6867 PetscInt pStart, pEnd, p, numPoints, off, dof; 6868 6869 PetscFunctionBeginHot; 6870 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6871 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6872 PetscCall(DMPlexGetCone(dm, point, &cone)); 6873 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6874 PetscCall(VecGetArray(v, &array)); 6875 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6876 const PetscInt cp = !p ? point : cone[p - 1]; 6877 const PetscInt o = !p ? 0 : coneO[p - 1]; 6878 6879 if ((cp < pStart) || (cp >= pEnd)) { 6880 dof = 0; 6881 continue; 6882 } 6883 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6884 /* ADD_VALUES */ 6885 { 6886 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6887 PetscScalar *a; 6888 PetscInt cdof, coff, cind = 0, k; 6889 6890 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6891 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6892 a = &array[coff]; 6893 if (!cdof) { 6894 if (o >= 0) { 6895 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6896 } else { 6897 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6898 } 6899 } else { 6900 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6901 if (o >= 0) { 6902 for (k = 0; k < dof; ++k) { 6903 if ((cind < cdof) && (k == cdofs[cind])) { 6904 ++cind; 6905 continue; 6906 } 6907 a[k] += values[off + k]; 6908 } 6909 } else { 6910 for (k = 0; k < dof; ++k) { 6911 if ((cind < cdof) && (k == cdofs[cind])) { 6912 ++cind; 6913 continue; 6914 } 6915 a[k] += values[off + dof - k - 1]; 6916 } 6917 } 6918 } 6919 } 6920 } 6921 PetscCall(VecRestoreArray(v, &array)); 6922 PetscFunctionReturn(PETSC_SUCCESS); 6923 } 6924 6925 /*@C 6926 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6927 6928 Not collective 6929 6930 Input Parameters: 6931 + dm - The `DM` 6932 . section - The section describing the layout in `v`, or `NULL` to use the default section 6933 . v - The local vector 6934 . point - The point in the `DM` 6935 . values - The array of values 6936 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6937 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6938 6939 Level: intermediate 6940 6941 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6942 @*/ 6943 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6944 { 6945 PetscSection clSection; 6946 IS clPoints; 6947 PetscScalar *array; 6948 PetscInt *points = NULL; 6949 const PetscInt *clp, *clperm = NULL; 6950 PetscInt depth, numFields, numPoints, p, clsize; 6951 6952 PetscFunctionBeginHot; 6953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6954 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6955 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6956 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6957 PetscCall(DMPlexGetDepth(dm, &depth)); 6958 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6959 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6960 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6961 PetscFunctionReturn(PETSC_SUCCESS); 6962 } 6963 /* Get points */ 6964 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6965 for (clsize = 0, p = 0; p < numPoints; p++) { 6966 PetscInt dof; 6967 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6968 clsize += dof; 6969 } 6970 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6971 /* Get array */ 6972 PetscCall(VecGetArray(v, &array)); 6973 /* Get values */ 6974 if (numFields > 0) { 6975 PetscInt offset = 0, f; 6976 for (f = 0; f < numFields; ++f) { 6977 const PetscInt **perms = NULL; 6978 const PetscScalar **flips = NULL; 6979 6980 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6981 switch (mode) { 6982 case INSERT_VALUES: 6983 for (p = 0; p < numPoints; p++) { 6984 const PetscInt point = points[2 * p]; 6985 const PetscInt *perm = perms ? perms[p] : NULL; 6986 const PetscScalar *flip = flips ? flips[p] : NULL; 6987 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6988 } 6989 break; 6990 case INSERT_ALL_VALUES: 6991 for (p = 0; p < numPoints; p++) { 6992 const PetscInt point = points[2 * p]; 6993 const PetscInt *perm = perms ? perms[p] : NULL; 6994 const PetscScalar *flip = flips ? flips[p] : NULL; 6995 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6996 } 6997 break; 6998 case INSERT_BC_VALUES: 6999 for (p = 0; p < numPoints; p++) { 7000 const PetscInt point = points[2 * p]; 7001 const PetscInt *perm = perms ? perms[p] : NULL; 7002 const PetscScalar *flip = flips ? flips[p] : NULL; 7003 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 7004 } 7005 break; 7006 case ADD_VALUES: 7007 for (p = 0; p < numPoints; p++) { 7008 const PetscInt point = points[2 * p]; 7009 const PetscInt *perm = perms ? perms[p] : NULL; 7010 const PetscScalar *flip = flips ? flips[p] : NULL; 7011 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 7012 } 7013 break; 7014 case ADD_ALL_VALUES: 7015 for (p = 0; p < numPoints; p++) { 7016 const PetscInt point = points[2 * p]; 7017 const PetscInt *perm = perms ? perms[p] : NULL; 7018 const PetscScalar *flip = flips ? flips[p] : NULL; 7019 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 7020 } 7021 break; 7022 case ADD_BC_VALUES: 7023 for (p = 0; p < numPoints; p++) { 7024 const PetscInt point = points[2 * p]; 7025 const PetscInt *perm = perms ? perms[p] : NULL; 7026 const PetscScalar *flip = flips ? flips[p] : NULL; 7027 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 7028 } 7029 break; 7030 default: 7031 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7032 } 7033 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7034 } 7035 } else { 7036 PetscInt dof, off; 7037 const PetscInt **perms = NULL; 7038 const PetscScalar **flips = NULL; 7039 7040 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 7041 switch (mode) { 7042 case INSERT_VALUES: 7043 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7044 const PetscInt point = points[2 * p]; 7045 const PetscInt *perm = perms ? perms[p] : NULL; 7046 const PetscScalar *flip = flips ? flips[p] : NULL; 7047 PetscCall(PetscSectionGetDof(section, point, &dof)); 7048 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7049 } 7050 break; 7051 case INSERT_ALL_VALUES: 7052 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7053 const PetscInt point = points[2 * p]; 7054 const PetscInt *perm = perms ? perms[p] : NULL; 7055 const PetscScalar *flip = flips ? flips[p] : NULL; 7056 PetscCall(PetscSectionGetDof(section, point, &dof)); 7057 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7058 } 7059 break; 7060 case INSERT_BC_VALUES: 7061 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7062 const PetscInt point = points[2 * p]; 7063 const PetscInt *perm = perms ? perms[p] : NULL; 7064 const PetscScalar *flip = flips ? flips[p] : NULL; 7065 PetscCall(PetscSectionGetDof(section, point, &dof)); 7066 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 7067 } 7068 break; 7069 case ADD_VALUES: 7070 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7071 const PetscInt point = points[2 * p]; 7072 const PetscInt *perm = perms ? perms[p] : NULL; 7073 const PetscScalar *flip = flips ? flips[p] : NULL; 7074 PetscCall(PetscSectionGetDof(section, point, &dof)); 7075 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 7076 } 7077 break; 7078 case ADD_ALL_VALUES: 7079 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7080 const PetscInt point = points[2 * p]; 7081 const PetscInt *perm = perms ? perms[p] : NULL; 7082 const PetscScalar *flip = flips ? flips[p] : NULL; 7083 PetscCall(PetscSectionGetDof(section, point, &dof)); 7084 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 7085 } 7086 break; 7087 case ADD_BC_VALUES: 7088 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 7089 const PetscInt point = points[2 * p]; 7090 const PetscInt *perm = perms ? perms[p] : NULL; 7091 const PetscScalar *flip = flips ? flips[p] : NULL; 7092 PetscCall(PetscSectionGetDof(section, point, &dof)); 7093 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 7094 } 7095 break; 7096 default: 7097 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7098 } 7099 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 7100 } 7101 /* Cleanup points */ 7102 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7103 /* Cleanup array */ 7104 PetscCall(VecRestoreArray(v, &array)); 7105 PetscFunctionReturn(PETSC_SUCCESS); 7106 } 7107 7108 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 7109 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 7110 { 7111 PetscFunctionBegin; 7112 *contains = PETSC_TRUE; 7113 if (label) { 7114 PetscInt fdof; 7115 7116 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 7117 if (!*contains) { 7118 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7119 *offset += fdof; 7120 PetscFunctionReturn(PETSC_SUCCESS); 7121 } 7122 } 7123 PetscFunctionReturn(PETSC_SUCCESS); 7124 } 7125 7126 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 7127 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) 7128 { 7129 PetscSection clSection; 7130 IS clPoints; 7131 PetscScalar *array; 7132 PetscInt *points = NULL; 7133 const PetscInt *clp; 7134 PetscInt numFields, numPoints, p; 7135 PetscInt offset = 0, f; 7136 7137 PetscFunctionBeginHot; 7138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7139 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7140 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7141 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 7142 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7143 /* Get points */ 7144 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 7145 /* Get array */ 7146 PetscCall(VecGetArray(v, &array)); 7147 /* Get values */ 7148 for (f = 0; f < numFields; ++f) { 7149 const PetscInt **perms = NULL; 7150 const PetscScalar **flips = NULL; 7151 PetscBool contains; 7152 7153 if (!fieldActive[f]) { 7154 for (p = 0; p < numPoints * 2; p += 2) { 7155 PetscInt fdof; 7156 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7157 offset += fdof; 7158 } 7159 continue; 7160 } 7161 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7162 switch (mode) { 7163 case INSERT_VALUES: 7164 for (p = 0; p < numPoints; p++) { 7165 const PetscInt point = points[2 * p]; 7166 const PetscInt *perm = perms ? perms[p] : NULL; 7167 const PetscScalar *flip = flips ? flips[p] : NULL; 7168 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7169 if (!contains) continue; 7170 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 7171 } 7172 break; 7173 case INSERT_ALL_VALUES: 7174 for (p = 0; p < numPoints; p++) { 7175 const PetscInt point = points[2 * p]; 7176 const PetscInt *perm = perms ? perms[p] : NULL; 7177 const PetscScalar *flip = flips ? flips[p] : NULL; 7178 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7179 if (!contains) continue; 7180 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 7181 } 7182 break; 7183 case INSERT_BC_VALUES: 7184 for (p = 0; p < numPoints; p++) { 7185 const PetscInt point = points[2 * p]; 7186 const PetscInt *perm = perms ? perms[p] : NULL; 7187 const PetscScalar *flip = flips ? flips[p] : NULL; 7188 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7189 if (!contains) continue; 7190 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 7191 } 7192 break; 7193 case ADD_VALUES: 7194 for (p = 0; p < numPoints; p++) { 7195 const PetscInt point = points[2 * p]; 7196 const PetscInt *perm = perms ? perms[p] : NULL; 7197 const PetscScalar *flip = flips ? flips[p] : NULL; 7198 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7199 if (!contains) continue; 7200 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 7201 } 7202 break; 7203 case ADD_ALL_VALUES: 7204 for (p = 0; p < numPoints; p++) { 7205 const PetscInt point = points[2 * p]; 7206 const PetscInt *perm = perms ? perms[p] : NULL; 7207 const PetscScalar *flip = flips ? flips[p] : NULL; 7208 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 7209 if (!contains) continue; 7210 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 7211 } 7212 break; 7213 default: 7214 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 7215 } 7216 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 7217 } 7218 /* Cleanup points */ 7219 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 7220 /* Cleanup array */ 7221 PetscCall(VecRestoreArray(v, &array)); 7222 PetscFunctionReturn(PETSC_SUCCESS); 7223 } 7224 7225 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 7226 { 7227 PetscMPIInt rank; 7228 PetscInt i, j; 7229 7230 PetscFunctionBegin; 7231 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7232 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 7233 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 7234 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 7235 numCIndices = numCIndices ? numCIndices : numRIndices; 7236 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 7237 for (i = 0; i < numRIndices; i++) { 7238 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 7239 for (j = 0; j < numCIndices; j++) { 7240 #if defined(PETSC_USE_COMPLEX) 7241 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 7242 #else 7243 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 7244 #endif 7245 } 7246 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 7247 } 7248 PetscFunctionReturn(PETSC_SUCCESS); 7249 } 7250 7251 /* 7252 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 7253 7254 Input Parameters: 7255 + section - The section for this data layout 7256 . islocal - Is the section (and thus indices being requested) local or global? 7257 . point - The point contributing dofs with these indices 7258 . off - The global offset of this point 7259 . loff - The local offset of each field 7260 . setBC - The flag determining whether to include indices of boundary values 7261 . perm - A permutation of the dofs on this point, or NULL 7262 - indperm - A permutation of the entire indices array, or NULL 7263 7264 Output Parameter: 7265 . indices - Indices for dofs on this point 7266 7267 Level: developer 7268 7269 Note: The indices could be local or global, depending on the value of 'off'. 7270 */ 7271 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7272 { 7273 PetscInt dof; /* The number of unknowns on this point */ 7274 PetscInt cdof; /* The number of constraints on this point */ 7275 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7276 PetscInt cind = 0, k; 7277 7278 PetscFunctionBegin; 7279 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7280 PetscCall(PetscSectionGetDof(section, point, &dof)); 7281 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7282 if (!cdof || setBC) { 7283 for (k = 0; k < dof; ++k) { 7284 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7285 const PetscInt ind = indperm ? indperm[preind] : preind; 7286 7287 indices[ind] = off + k; 7288 } 7289 } else { 7290 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7291 for (k = 0; k < dof; ++k) { 7292 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7293 const PetscInt ind = indperm ? indperm[preind] : preind; 7294 7295 if ((cind < cdof) && (k == cdofs[cind])) { 7296 /* Insert check for returning constrained indices */ 7297 indices[ind] = -(off + k + 1); 7298 ++cind; 7299 } else { 7300 indices[ind] = off + k - (islocal ? 0 : cind); 7301 } 7302 } 7303 } 7304 *loff += dof; 7305 PetscFunctionReturn(PETSC_SUCCESS); 7306 } 7307 7308 /* 7309 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7310 7311 Input Parameters: 7312 + section - a section (global or local) 7313 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7314 . point - point within section 7315 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7316 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7317 . setBC - identify constrained (boundary condition) points via involution. 7318 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7319 . permsoff - offset 7320 - indperm - index permutation 7321 7322 Output Parameter: 7323 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7324 . indices - array to hold indices (as defined by section) of each dof associated with point 7325 7326 Notes: 7327 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7328 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7329 in the local vector. 7330 7331 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7332 significant). It is invalid to call with a global section and setBC=true. 7333 7334 Developer Note: 7335 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7336 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7337 offset could be obtained from the section instead of passing it explicitly as we do now. 7338 7339 Example: 7340 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7341 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7342 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7343 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. 7344 7345 Level: developer 7346 */ 7347 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[]) 7348 { 7349 PetscInt numFields, foff, f; 7350 7351 PetscFunctionBegin; 7352 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7353 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7354 for (f = 0, foff = 0; f < numFields; ++f) { 7355 PetscInt fdof, cfdof; 7356 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7357 PetscInt cind = 0, b; 7358 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7359 7360 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7361 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7362 if (!cfdof || setBC) { 7363 for (b = 0; b < fdof; ++b) { 7364 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7365 const PetscInt ind = indperm ? indperm[preind] : preind; 7366 7367 indices[ind] = off + foff + b; 7368 } 7369 } else { 7370 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7371 for (b = 0; b < fdof; ++b) { 7372 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7373 const PetscInt ind = indperm ? indperm[preind] : preind; 7374 7375 if ((cind < cfdof) && (b == fcdofs[cind])) { 7376 indices[ind] = -(off + foff + b + 1); 7377 ++cind; 7378 } else { 7379 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7380 } 7381 } 7382 } 7383 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7384 foffs[f] += fdof; 7385 } 7386 PetscFunctionReturn(PETSC_SUCCESS); 7387 } 7388 7389 /* 7390 This version believes the globalSection offsets for each field, rather than just the point offset 7391 7392 . foffs - The offset into 'indices' for each field, since it is segregated by field 7393 7394 Notes: 7395 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7396 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7397 */ 7398 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7399 { 7400 PetscInt numFields, foff, f; 7401 7402 PetscFunctionBegin; 7403 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7404 for (f = 0; f < numFields; ++f) { 7405 PetscInt fdof, cfdof; 7406 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7407 PetscInt cind = 0, b; 7408 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7409 7410 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7411 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7412 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7413 if (!cfdof) { 7414 for (b = 0; b < fdof; ++b) { 7415 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7416 const PetscInt ind = indperm ? indperm[preind] : preind; 7417 7418 indices[ind] = foff + b; 7419 } 7420 } else { 7421 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7422 for (b = 0; b < fdof; ++b) { 7423 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7424 const PetscInt ind = indperm ? indperm[preind] : preind; 7425 7426 if ((cind < cfdof) && (b == fcdofs[cind])) { 7427 indices[ind] = -(foff + b + 1); 7428 ++cind; 7429 } else { 7430 indices[ind] = foff + b - cind; 7431 } 7432 } 7433 } 7434 foffs[f] += fdof; 7435 } 7436 PetscFunctionReturn(PETSC_SUCCESS); 7437 } 7438 7439 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) 7440 { 7441 Mat cMat; 7442 PetscSection aSec, cSec; 7443 IS aIS; 7444 PetscInt aStart = -1, aEnd = -1; 7445 const PetscInt *anchors; 7446 PetscInt numFields, f, p, q, newP = 0; 7447 PetscInt newNumPoints = 0, newNumIndices = 0; 7448 PetscInt *newPoints, *indices, *newIndices; 7449 PetscInt maxAnchor, maxDof; 7450 PetscInt newOffsets[32]; 7451 PetscInt *pointMatOffsets[32]; 7452 PetscInt *newPointOffsets[32]; 7453 PetscScalar *pointMat[32]; 7454 PetscScalar *newValues = NULL, *tmpValues; 7455 PetscBool anyConstrained = PETSC_FALSE; 7456 7457 PetscFunctionBegin; 7458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7459 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7460 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7461 7462 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7463 /* if there are point-to-point constraints */ 7464 if (aSec) { 7465 PetscCall(PetscArrayzero(newOffsets, 32)); 7466 PetscCall(ISGetIndices(aIS, &anchors)); 7467 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7468 /* figure out how many points are going to be in the new element matrix 7469 * (we allow double counting, because it's all just going to be summed 7470 * into the global matrix anyway) */ 7471 for (p = 0; p < 2 * numPoints; p += 2) { 7472 PetscInt b = points[p]; 7473 PetscInt bDof = 0, bSecDof; 7474 7475 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7476 if (!bSecDof) continue; 7477 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7478 if (bDof) { 7479 /* this point is constrained */ 7480 /* it is going to be replaced by its anchors */ 7481 PetscInt bOff, q; 7482 7483 anyConstrained = PETSC_TRUE; 7484 newNumPoints += bDof; 7485 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7486 for (q = 0; q < bDof; q++) { 7487 PetscInt a = anchors[bOff + q]; 7488 PetscInt aDof; 7489 7490 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7491 newNumIndices += aDof; 7492 for (f = 0; f < numFields; ++f) { 7493 PetscInt fDof; 7494 7495 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7496 newOffsets[f + 1] += fDof; 7497 } 7498 } 7499 } else { 7500 /* this point is not constrained */ 7501 newNumPoints++; 7502 newNumIndices += bSecDof; 7503 for (f = 0; f < numFields; ++f) { 7504 PetscInt fDof; 7505 7506 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7507 newOffsets[f + 1] += fDof; 7508 } 7509 } 7510 } 7511 } 7512 if (!anyConstrained) { 7513 if (outNumPoints) *outNumPoints = 0; 7514 if (outNumIndices) *outNumIndices = 0; 7515 if (outPoints) *outPoints = NULL; 7516 if (outValues) *outValues = NULL; 7517 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7518 PetscFunctionReturn(PETSC_SUCCESS); 7519 } 7520 7521 if (outNumPoints) *outNumPoints = newNumPoints; 7522 if (outNumIndices) *outNumIndices = newNumIndices; 7523 7524 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7525 7526 if (!outPoints && !outValues) { 7527 if (offsets) { 7528 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7529 } 7530 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7531 PetscFunctionReturn(PETSC_SUCCESS); 7532 } 7533 7534 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7535 7536 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7537 7538 /* workspaces */ 7539 if (numFields) { 7540 for (f = 0; f < numFields; f++) { 7541 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7542 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7543 } 7544 } else { 7545 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7546 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7547 } 7548 7549 /* get workspaces for the point-to-point matrices */ 7550 if (numFields) { 7551 PetscInt totalOffset, totalMatOffset; 7552 7553 for (p = 0; p < numPoints; p++) { 7554 PetscInt b = points[2 * p]; 7555 PetscInt bDof = 0, bSecDof; 7556 7557 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7558 if (!bSecDof) { 7559 for (f = 0; f < numFields; f++) { 7560 newPointOffsets[f][p + 1] = 0; 7561 pointMatOffsets[f][p + 1] = 0; 7562 } 7563 continue; 7564 } 7565 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7566 if (bDof) { 7567 for (f = 0; f < numFields; f++) { 7568 PetscInt fDof, q, bOff, allFDof = 0; 7569 7570 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7571 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7572 for (q = 0; q < bDof; q++) { 7573 PetscInt a = anchors[bOff + q]; 7574 PetscInt aFDof; 7575 7576 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7577 allFDof += aFDof; 7578 } 7579 newPointOffsets[f][p + 1] = allFDof; 7580 pointMatOffsets[f][p + 1] = fDof * allFDof; 7581 } 7582 } else { 7583 for (f = 0; f < numFields; f++) { 7584 PetscInt fDof; 7585 7586 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7587 newPointOffsets[f][p + 1] = fDof; 7588 pointMatOffsets[f][p + 1] = 0; 7589 } 7590 } 7591 } 7592 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7593 newPointOffsets[f][0] = totalOffset; 7594 pointMatOffsets[f][0] = totalMatOffset; 7595 for (p = 0; p < numPoints; p++) { 7596 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7597 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7598 } 7599 totalOffset = newPointOffsets[f][numPoints]; 7600 totalMatOffset = pointMatOffsets[f][numPoints]; 7601 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7602 } 7603 } else { 7604 for (p = 0; p < numPoints; p++) { 7605 PetscInt b = points[2 * p]; 7606 PetscInt bDof = 0, bSecDof; 7607 7608 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7609 if (!bSecDof) { 7610 newPointOffsets[0][p + 1] = 0; 7611 pointMatOffsets[0][p + 1] = 0; 7612 continue; 7613 } 7614 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7615 if (bDof) { 7616 PetscInt bOff, q, allDof = 0; 7617 7618 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7619 for (q = 0; q < bDof; q++) { 7620 PetscInt a = anchors[bOff + q], aDof; 7621 7622 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7623 allDof += aDof; 7624 } 7625 newPointOffsets[0][p + 1] = allDof; 7626 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7627 } else { 7628 newPointOffsets[0][p + 1] = bSecDof; 7629 pointMatOffsets[0][p + 1] = 0; 7630 } 7631 } 7632 newPointOffsets[0][0] = 0; 7633 pointMatOffsets[0][0] = 0; 7634 for (p = 0; p < numPoints; p++) { 7635 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7636 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7637 } 7638 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7639 } 7640 7641 /* output arrays */ 7642 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7643 7644 /* get the point-to-point matrices; construct newPoints */ 7645 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7646 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7647 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7648 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7649 if (numFields) { 7650 for (p = 0, newP = 0; p < numPoints; p++) { 7651 PetscInt b = points[2 * p]; 7652 PetscInt o = points[2 * p + 1]; 7653 PetscInt bDof = 0, bSecDof; 7654 7655 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7656 if (!bSecDof) continue; 7657 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7658 if (bDof) { 7659 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7660 7661 fStart[0] = 0; 7662 fEnd[0] = 0; 7663 for (f = 0; f < numFields; f++) { 7664 PetscInt fDof; 7665 7666 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7667 fStart[f + 1] = fStart[f] + fDof; 7668 fEnd[f + 1] = fStart[f + 1]; 7669 } 7670 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7671 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7672 7673 fAnchorStart[0] = 0; 7674 fAnchorEnd[0] = 0; 7675 for (f = 0; f < numFields; f++) { 7676 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7677 7678 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7679 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7680 } 7681 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7682 for (q = 0; q < bDof; q++) { 7683 PetscInt a = anchors[bOff + q], aOff; 7684 7685 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7686 newPoints[2 * (newP + q)] = a; 7687 newPoints[2 * (newP + q) + 1] = 0; 7688 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7689 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7690 } 7691 newP += bDof; 7692 7693 if (outValues) { 7694 /* get the point-to-point submatrix */ 7695 for (f = 0; f < numFields; f++) PetscCall(MatGetValues(cMat, fEnd[f] - fStart[f], indices + fStart[f], fAnchorEnd[f] - fAnchorStart[f], newIndices + fAnchorStart[f], pointMat[f] + pointMatOffsets[f][p])); 7696 } 7697 } else { 7698 newPoints[2 * newP] = b; 7699 newPoints[2 * newP + 1] = o; 7700 newP++; 7701 } 7702 } 7703 } else { 7704 for (p = 0; p < numPoints; p++) { 7705 PetscInt b = points[2 * p]; 7706 PetscInt o = points[2 * p + 1]; 7707 PetscInt bDof = 0, bSecDof; 7708 7709 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7710 if (!bSecDof) continue; 7711 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7712 if (bDof) { 7713 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7714 7715 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7716 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7717 7718 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7719 for (q = 0; q < bDof; q++) { 7720 PetscInt a = anchors[bOff + q], aOff; 7721 7722 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7723 7724 newPoints[2 * (newP + q)] = a; 7725 newPoints[2 * (newP + q) + 1] = 0; 7726 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7727 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7728 } 7729 newP += bDof; 7730 7731 /* get the point-to-point submatrix */ 7732 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7733 } else { 7734 newPoints[2 * newP] = b; 7735 newPoints[2 * newP + 1] = o; 7736 newP++; 7737 } 7738 } 7739 } 7740 7741 if (outValues) { 7742 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7743 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7744 /* multiply constraints on the right */ 7745 if (numFields) { 7746 for (f = 0; f < numFields; f++) { 7747 PetscInt oldOff = offsets[f]; 7748 7749 for (p = 0; p < numPoints; p++) { 7750 PetscInt cStart = newPointOffsets[f][p]; 7751 PetscInt b = points[2 * p]; 7752 PetscInt c, r, k; 7753 PetscInt dof; 7754 7755 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7756 if (!dof) continue; 7757 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7758 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7759 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7760 7761 for (r = 0; r < numIndices; r++) { 7762 for (c = 0; c < nCols; c++) { 7763 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7764 } 7765 } 7766 } else { 7767 /* copy this column as is */ 7768 for (r = 0; r < numIndices; r++) { 7769 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7770 } 7771 } 7772 oldOff += dof; 7773 } 7774 } 7775 } else { 7776 PetscInt oldOff = 0; 7777 for (p = 0; p < numPoints; p++) { 7778 PetscInt cStart = newPointOffsets[0][p]; 7779 PetscInt b = points[2 * p]; 7780 PetscInt c, r, k; 7781 PetscInt dof; 7782 7783 PetscCall(PetscSectionGetDof(section, b, &dof)); 7784 if (!dof) continue; 7785 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7786 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7787 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7788 7789 for (r = 0; r < numIndices; r++) { 7790 for (c = 0; c < nCols; c++) { 7791 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7792 } 7793 } 7794 } else { 7795 /* copy this column as is */ 7796 for (r = 0; r < numIndices; r++) { 7797 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7798 } 7799 } 7800 oldOff += dof; 7801 } 7802 } 7803 7804 if (multiplyLeft) { 7805 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7806 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7807 /* multiply constraints transpose on the left */ 7808 if (numFields) { 7809 for (f = 0; f < numFields; f++) { 7810 PetscInt oldOff = offsets[f]; 7811 7812 for (p = 0; p < numPoints; p++) { 7813 PetscInt rStart = newPointOffsets[f][p]; 7814 PetscInt b = points[2 * p]; 7815 PetscInt c, r, k; 7816 PetscInt dof; 7817 7818 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7819 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7820 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7821 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7822 7823 for (r = 0; r < nRows; r++) { 7824 for (c = 0; c < newNumIndices; c++) { 7825 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7826 } 7827 } 7828 } else { 7829 /* copy this row as is */ 7830 for (r = 0; r < dof; r++) { 7831 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7832 } 7833 } 7834 oldOff += dof; 7835 } 7836 } 7837 } else { 7838 PetscInt oldOff = 0; 7839 7840 for (p = 0; p < numPoints; p++) { 7841 PetscInt rStart = newPointOffsets[0][p]; 7842 PetscInt b = points[2 * p]; 7843 PetscInt c, r, k; 7844 PetscInt dof; 7845 7846 PetscCall(PetscSectionGetDof(section, b, &dof)); 7847 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7848 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7849 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7850 7851 for (r = 0; r < nRows; r++) { 7852 for (c = 0; c < newNumIndices; c++) { 7853 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7854 } 7855 } 7856 } else { 7857 /* copy this row as is */ 7858 for (r = 0; r < dof; r++) { 7859 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7860 } 7861 } 7862 oldOff += dof; 7863 } 7864 } 7865 7866 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7867 } else { 7868 newValues = tmpValues; 7869 } 7870 } 7871 7872 /* clean up */ 7873 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7874 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7875 7876 if (numFields) { 7877 for (f = 0; f < numFields; f++) { 7878 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7879 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7880 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7881 } 7882 } else { 7883 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7884 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7885 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7886 } 7887 PetscCall(ISRestoreIndices(aIS, &anchors)); 7888 7889 /* output */ 7890 if (outPoints) { 7891 *outPoints = newPoints; 7892 } else { 7893 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7894 } 7895 if (outValues) *outValues = newValues; 7896 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7897 PetscFunctionReturn(PETSC_SUCCESS); 7898 } 7899 7900 /*@C 7901 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7902 7903 Not collective 7904 7905 Input Parameters: 7906 + dm - The `DM` 7907 . section - The `PetscSection` describing the points (a local section) 7908 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7909 . point - The point defining the closure 7910 - useClPerm - Use the closure point permutation if available 7911 7912 Output Parameters: 7913 + numIndices - The number of dof indices in the closure of point with the input sections 7914 . indices - The dof indices 7915 . outOffsets - Array to write the field offsets into, or `NULL` 7916 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7917 7918 Level: advanced 7919 7920 Notes: 7921 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7922 7923 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7924 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7925 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7926 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7927 indices (with the above semantics) are implied. 7928 7929 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7930 `PetscSection`, `DMGetGlobalSection()` 7931 @*/ 7932 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7933 { 7934 /* Closure ordering */ 7935 PetscSection clSection; 7936 IS clPoints; 7937 const PetscInt *clp; 7938 PetscInt *points; 7939 const PetscInt *clperm = NULL; 7940 /* Dof permutation and sign flips */ 7941 const PetscInt **perms[32] = {NULL}; 7942 const PetscScalar **flips[32] = {NULL}; 7943 PetscScalar *valCopy = NULL; 7944 /* Hanging node constraints */ 7945 PetscInt *pointsC = NULL; 7946 PetscScalar *valuesC = NULL; 7947 PetscInt NclC, NiC; 7948 7949 PetscInt *idx; 7950 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7951 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7952 7953 PetscFunctionBeginHot; 7954 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7955 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7956 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7957 if (numIndices) PetscAssertPointer(numIndices, 6); 7958 if (indices) PetscAssertPointer(indices, 7); 7959 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7960 if (values) PetscAssertPointer(values, 9); 7961 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7962 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7963 PetscCall(PetscArrayzero(offsets, 32)); 7964 /* 1) Get points in closure */ 7965 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7966 if (useClPerm) { 7967 PetscInt depth, clsize; 7968 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7969 for (clsize = 0, p = 0; p < Ncl; p++) { 7970 PetscInt dof; 7971 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7972 clsize += dof; 7973 } 7974 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7975 } 7976 /* 2) Get number of indices on these points and field offsets from section */ 7977 for (p = 0; p < Ncl * 2; p += 2) { 7978 PetscInt dof, fdof; 7979 7980 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7981 for (f = 0; f < Nf; ++f) { 7982 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7983 offsets[f + 1] += fdof; 7984 } 7985 Ni += dof; 7986 } 7987 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7988 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7989 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7990 for (f = 0; f < PetscMax(1, Nf); ++f) { 7991 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7992 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7993 /* may need to apply sign changes to the element matrix */ 7994 if (values && flips[f]) { 7995 PetscInt foffset = offsets[f]; 7996 7997 for (p = 0; p < Ncl; ++p) { 7998 PetscInt pnt = points[2 * p], fdof; 7999 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 8000 8001 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 8002 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 8003 if (flip) { 8004 PetscInt i, j, k; 8005 8006 if (!valCopy) { 8007 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8008 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 8009 *values = valCopy; 8010 } 8011 for (i = 0; i < fdof; ++i) { 8012 PetscScalar fval = flip[i]; 8013 8014 for (k = 0; k < Ni; ++k) { 8015 valCopy[Ni * (foffset + i) + k] *= fval; 8016 valCopy[Ni * k + (foffset + i)] *= fval; 8017 } 8018 } 8019 } 8020 foffset += fdof; 8021 } 8022 } 8023 } 8024 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 8025 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 8026 if (NclC) { 8027 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 8028 for (f = 0; f < PetscMax(1, Nf); ++f) { 8029 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8030 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8031 } 8032 for (f = 0; f < PetscMax(1, Nf); ++f) { 8033 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 8034 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 8035 } 8036 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8037 Ncl = NclC; 8038 Ni = NiC; 8039 points = pointsC; 8040 if (values) *values = valuesC; 8041 } 8042 /* 5) Calculate indices */ 8043 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 8044 if (Nf) { 8045 PetscInt idxOff; 8046 PetscBool useFieldOffsets; 8047 8048 if (outOffsets) { 8049 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 8050 } 8051 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 8052 if (useFieldOffsets) { 8053 for (p = 0; p < Ncl; ++p) { 8054 const PetscInt pnt = points[p * 2]; 8055 8056 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 8057 } 8058 } else { 8059 for (p = 0; p < Ncl; ++p) { 8060 const PetscInt pnt = points[p * 2]; 8061 8062 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8063 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8064 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 8065 * global section. */ 8066 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 8067 } 8068 } 8069 } else { 8070 PetscInt off = 0, idxOff; 8071 8072 for (p = 0; p < Ncl; ++p) { 8073 const PetscInt pnt = points[p * 2]; 8074 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 8075 8076 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 8077 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 8078 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 8079 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 8080 } 8081 } 8082 /* 6) Cleanup */ 8083 for (f = 0; f < PetscMax(1, Nf); ++f) { 8084 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 8085 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 8086 } 8087 if (NclC) { 8088 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 8089 } else { 8090 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 8091 } 8092 8093 if (numIndices) *numIndices = Ni; 8094 if (indices) *indices = idx; 8095 PetscFunctionReturn(PETSC_SUCCESS); 8096 } 8097 8098 /*@C 8099 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 8100 8101 Not collective 8102 8103 Input Parameters: 8104 + dm - The `DM` 8105 . section - The `PetscSection` describing the points (a local section) 8106 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 8107 . point - The point defining the closure 8108 - useClPerm - Use the closure point permutation if available 8109 8110 Output Parameters: 8111 + numIndices - The number of dof indices in the closure of point with the input sections 8112 . indices - The dof indices 8113 . outOffsets - Array to write the field offsets into, or `NULL` 8114 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 8115 8116 Level: advanced 8117 8118 Notes: 8119 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 8120 8121 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 8122 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 8123 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 8124 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 8125 indices (with the above semantics) are implied. 8126 8127 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 8128 @*/ 8129 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 8130 { 8131 PetscFunctionBegin; 8132 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8133 PetscAssertPointer(indices, 7); 8134 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 8135 PetscFunctionReturn(PETSC_SUCCESS); 8136 } 8137 8138 PetscErrorCode DMPlexMatSetClosure_Internal(DM dm, PetscSection section, PetscSection globalSection, PetscBool useClPerm, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8139 { 8140 DM_Plex *mesh = (DM_Plex *)dm->data; 8141 PetscInt *indices; 8142 PetscInt numIndices; 8143 const PetscScalar *valuesOrig = values; 8144 PetscErrorCode ierr; 8145 8146 PetscFunctionBegin; 8147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8148 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 8149 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 8150 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 8151 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 8152 PetscValidHeaderSpecific(A, MAT_CLASSID, 5); 8153 8154 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, useClPerm, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8155 8156 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 8157 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8158 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 8159 if (ierr) { 8160 PetscMPIInt rank; 8161 8162 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8163 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8164 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 8165 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8166 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8167 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 8168 } 8169 if (mesh->printFEM > 1) { 8170 PetscInt i; 8171 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 8172 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 8173 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8174 } 8175 8176 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 8177 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 8178 PetscFunctionReturn(PETSC_SUCCESS); 8179 } 8180 8181 /*@C 8182 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 8183 8184 Not collective 8185 8186 Input Parameters: 8187 + dm - The `DM` 8188 . section - The section describing the layout in `v`, or `NULL` to use the default section 8189 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 8190 . A - The matrix 8191 . point - The point in the `DM` 8192 . values - The array of values 8193 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8194 8195 Level: intermediate 8196 8197 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8198 @*/ 8199 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8200 { 8201 PetscFunctionBegin; 8202 PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, PETSC_TRUE, A, point, values, mode)); 8203 PetscFunctionReturn(PETSC_SUCCESS); 8204 } 8205 8206 /*@C 8207 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 8208 8209 Not collective 8210 8211 Input Parameters: 8212 + dmRow - The `DM` for the row fields 8213 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 8214 . useRowPerm - The flag to use the closure permutation of the `dmRow` if available 8215 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 8216 . dmCol - The `DM` for the column fields 8217 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 8218 . useColPerm - The flag to use the closure permutation of the `dmCol` if available 8219 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 8220 . A - The matrix 8221 . point - The point in the `DM` 8222 . values - The array of values 8223 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 8224 8225 Level: intermediate 8226 8227 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 8228 @*/ 8229 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) 8230 { 8231 DM_Plex *mesh = (DM_Plex *)dmRow->data; 8232 PetscInt *indicesRow, *indicesCol; 8233 PetscInt numIndicesRow, numIndicesCol; 8234 const PetscScalar *valuesOrig = values; 8235 PetscErrorCode ierr; 8236 8237 PetscFunctionBegin; 8238 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 8239 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 8240 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 8241 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 8242 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 8243 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 5); 8244 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 8245 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 6); 8246 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 8247 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 7); 8248 PetscValidHeaderSpecific(A, MAT_CLASSID, 9); 8249 8250 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8251 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8252 8253 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8254 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8255 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 8256 if (ierr) { 8257 PetscMPIInt rank; 8258 8259 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8260 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8261 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 8262 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8263 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 8264 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8265 } 8266 8267 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, useRowPerm, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 8268 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, useColPerm, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 8269 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 8270 PetscFunctionReturn(PETSC_SUCCESS); 8271 } 8272 8273 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8274 { 8275 DM_Plex *mesh = (DM_Plex *)dmf->data; 8276 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8277 PetscInt *cpoints = NULL; 8278 PetscInt *findices, *cindices; 8279 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8280 PetscInt foffsets[32], coffsets[32]; 8281 DMPolytopeType ct; 8282 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8283 PetscErrorCode ierr; 8284 8285 PetscFunctionBegin; 8286 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8287 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8288 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8289 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8290 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8291 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8292 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8293 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8294 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8295 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8296 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8297 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8298 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8299 PetscCall(PetscArrayzero(foffsets, 32)); 8300 PetscCall(PetscArrayzero(coffsets, 32)); 8301 /* Column indices */ 8302 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8303 maxFPoints = numCPoints; 8304 /* Compress out points not in the section */ 8305 /* TODO: Squeeze out points with 0 dof as well */ 8306 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8307 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8308 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8309 cpoints[q * 2] = cpoints[p]; 8310 cpoints[q * 2 + 1] = cpoints[p + 1]; 8311 ++q; 8312 } 8313 } 8314 numCPoints = q; 8315 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8316 PetscInt fdof; 8317 8318 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8319 if (!dof) continue; 8320 for (f = 0; f < numFields; ++f) { 8321 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8322 coffsets[f + 1] += fdof; 8323 } 8324 numCIndices += dof; 8325 } 8326 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8327 /* Row indices */ 8328 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8329 { 8330 DMPlexTransform tr; 8331 DMPolytopeType *rct; 8332 PetscInt *rsize, *rcone, *rornt, Nt; 8333 8334 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8335 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8336 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8337 numSubcells = rsize[Nt - 1]; 8338 PetscCall(DMPlexTransformDestroy(&tr)); 8339 } 8340 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8341 for (r = 0, q = 0; r < numSubcells; ++r) { 8342 /* TODO Map from coarse to fine cells */ 8343 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8344 /* Compress out points not in the section */ 8345 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8346 for (p = 0; p < numFPoints * 2; p += 2) { 8347 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8348 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8349 if (!dof) continue; 8350 for (s = 0; s < q; ++s) 8351 if (fpoints[p] == ftotpoints[s * 2]) break; 8352 if (s < q) continue; 8353 ftotpoints[q * 2] = fpoints[p]; 8354 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8355 ++q; 8356 } 8357 } 8358 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8359 } 8360 numFPoints = q; 8361 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8362 PetscInt fdof; 8363 8364 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8365 if (!dof) continue; 8366 for (f = 0; f < numFields; ++f) { 8367 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8368 foffsets[f + 1] += fdof; 8369 } 8370 numFIndices += dof; 8371 } 8372 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8373 8374 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8375 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8376 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8377 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8378 if (numFields) { 8379 const PetscInt **permsF[32] = {NULL}; 8380 const PetscInt **permsC[32] = {NULL}; 8381 8382 for (f = 0; f < numFields; f++) { 8383 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8384 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8385 } 8386 for (p = 0; p < numFPoints; p++) { 8387 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8388 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8389 } 8390 for (p = 0; p < numCPoints; p++) { 8391 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8392 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8393 } 8394 for (f = 0; f < numFields; f++) { 8395 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8396 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8397 } 8398 } else { 8399 const PetscInt **permsF = NULL; 8400 const PetscInt **permsC = NULL; 8401 8402 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8403 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8404 for (p = 0, off = 0; p < numFPoints; p++) { 8405 const PetscInt *perm = permsF ? permsF[p] : NULL; 8406 8407 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8408 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8409 } 8410 for (p = 0, off = 0; p < numCPoints; p++) { 8411 const PetscInt *perm = permsC ? permsC[p] : NULL; 8412 8413 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8414 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8415 } 8416 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8417 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8418 } 8419 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8420 /* TODO: flips */ 8421 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8422 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8423 if (ierr) { 8424 PetscMPIInt rank; 8425 8426 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8427 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8428 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8429 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8430 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8431 } 8432 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8433 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8434 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8435 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8436 PetscFunctionReturn(PETSC_SUCCESS); 8437 } 8438 8439 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8440 { 8441 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8442 PetscInt *cpoints = NULL; 8443 PetscInt foffsets[32], coffsets[32]; 8444 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8445 DMPolytopeType ct; 8446 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8447 8448 PetscFunctionBegin; 8449 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8450 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8451 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8452 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8453 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8454 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8455 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8456 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8457 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8458 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8459 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8460 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8461 PetscCall(PetscArrayzero(foffsets, 32)); 8462 PetscCall(PetscArrayzero(coffsets, 32)); 8463 /* Column indices */ 8464 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8465 maxFPoints = numCPoints; 8466 /* Compress out points not in the section */ 8467 /* TODO: Squeeze out points with 0 dof as well */ 8468 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8469 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8470 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8471 cpoints[q * 2] = cpoints[p]; 8472 cpoints[q * 2 + 1] = cpoints[p + 1]; 8473 ++q; 8474 } 8475 } 8476 numCPoints = q; 8477 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8478 PetscInt fdof; 8479 8480 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8481 if (!dof) continue; 8482 for (f = 0; f < numFields; ++f) { 8483 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8484 coffsets[f + 1] += fdof; 8485 } 8486 numCIndices += dof; 8487 } 8488 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8489 /* Row indices */ 8490 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8491 { 8492 DMPlexTransform tr; 8493 DMPolytopeType *rct; 8494 PetscInt *rsize, *rcone, *rornt, Nt; 8495 8496 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8497 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8498 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8499 numSubcells = rsize[Nt - 1]; 8500 PetscCall(DMPlexTransformDestroy(&tr)); 8501 } 8502 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8503 for (r = 0, q = 0; r < numSubcells; ++r) { 8504 /* TODO Map from coarse to fine cells */ 8505 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8506 /* Compress out points not in the section */ 8507 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8508 for (p = 0; p < numFPoints * 2; p += 2) { 8509 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8510 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8511 if (!dof) continue; 8512 for (s = 0; s < q; ++s) 8513 if (fpoints[p] == ftotpoints[s * 2]) break; 8514 if (s < q) continue; 8515 ftotpoints[q * 2] = fpoints[p]; 8516 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8517 ++q; 8518 } 8519 } 8520 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8521 } 8522 numFPoints = q; 8523 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8524 PetscInt fdof; 8525 8526 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8527 if (!dof) continue; 8528 for (f = 0; f < numFields; ++f) { 8529 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8530 foffsets[f + 1] += fdof; 8531 } 8532 numFIndices += dof; 8533 } 8534 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8535 8536 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8537 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8538 if (numFields) { 8539 const PetscInt **permsF[32] = {NULL}; 8540 const PetscInt **permsC[32] = {NULL}; 8541 8542 for (f = 0; f < numFields; f++) { 8543 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8544 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8545 } 8546 for (p = 0; p < numFPoints; p++) { 8547 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8548 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8549 } 8550 for (p = 0; p < numCPoints; p++) { 8551 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8552 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8553 } 8554 for (f = 0; f < numFields; f++) { 8555 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8556 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8557 } 8558 } else { 8559 const PetscInt **permsF = NULL; 8560 const PetscInt **permsC = NULL; 8561 8562 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8563 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8564 for (p = 0, off = 0; p < numFPoints; p++) { 8565 const PetscInt *perm = permsF ? permsF[p] : NULL; 8566 8567 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8568 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8569 } 8570 for (p = 0, off = 0; p < numCPoints; p++) { 8571 const PetscInt *perm = permsC ? permsC[p] : NULL; 8572 8573 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8574 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8575 } 8576 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8577 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8578 } 8579 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8580 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8581 PetscFunctionReturn(PETSC_SUCCESS); 8582 } 8583 8584 /*@C 8585 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8586 8587 Input Parameter: 8588 . dm - The `DMPLEX` object 8589 8590 Output Parameter: 8591 . cellHeight - The height of a cell 8592 8593 Level: developer 8594 8595 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8596 @*/ 8597 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8598 { 8599 DM_Plex *mesh = (DM_Plex *)dm->data; 8600 8601 PetscFunctionBegin; 8602 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8603 PetscAssertPointer(cellHeight, 2); 8604 *cellHeight = mesh->vtkCellHeight; 8605 PetscFunctionReturn(PETSC_SUCCESS); 8606 } 8607 8608 /*@C 8609 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8610 8611 Input Parameters: 8612 + dm - The `DMPLEX` object 8613 - cellHeight - The height of a cell 8614 8615 Level: developer 8616 8617 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8618 @*/ 8619 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8620 { 8621 DM_Plex *mesh = (DM_Plex *)dm->data; 8622 8623 PetscFunctionBegin; 8624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8625 mesh->vtkCellHeight = cellHeight; 8626 PetscFunctionReturn(PETSC_SUCCESS); 8627 } 8628 8629 /*@ 8630 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8631 8632 Input Parameters: 8633 + dm - The `DMPLEX` object 8634 - ct - The `DMPolytopeType` of the cell 8635 8636 Output Parameters: 8637 + start - The first cell of this type, or `NULL` 8638 - end - The upper bound on this celltype, or `NULL` 8639 8640 Level: advanced 8641 8642 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8643 @*/ 8644 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8645 { 8646 DM_Plex *mesh = (DM_Plex *)dm->data; 8647 DMLabel label; 8648 PetscInt pStart, pEnd; 8649 8650 PetscFunctionBegin; 8651 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8652 if (start) { 8653 PetscAssertPointer(start, 3); 8654 *start = 0; 8655 } 8656 if (end) { 8657 PetscAssertPointer(end, 4); 8658 *end = 0; 8659 } 8660 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8661 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8662 if (mesh->tr) { 8663 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8664 } else { 8665 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8666 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8667 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8668 } 8669 PetscFunctionReturn(PETSC_SUCCESS); 8670 } 8671 8672 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8673 { 8674 PetscSection section, globalSection; 8675 PetscInt *numbers, p; 8676 8677 PetscFunctionBegin; 8678 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8679 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8680 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8681 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8682 PetscCall(PetscSectionSetUp(section)); 8683 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8684 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8685 for (p = pStart; p < pEnd; ++p) { 8686 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8687 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8688 else numbers[p - pStart] += shift; 8689 } 8690 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8691 if (globalSize) { 8692 PetscLayout layout; 8693 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8694 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8695 PetscCall(PetscLayoutDestroy(&layout)); 8696 } 8697 PetscCall(PetscSectionDestroy(§ion)); 8698 PetscCall(PetscSectionDestroy(&globalSection)); 8699 PetscFunctionReturn(PETSC_SUCCESS); 8700 } 8701 8702 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8703 { 8704 PetscInt cellHeight, cStart, cEnd; 8705 8706 PetscFunctionBegin; 8707 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8708 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8709 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8710 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8711 PetscFunctionReturn(PETSC_SUCCESS); 8712 } 8713 8714 /*@ 8715 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8716 8717 Input Parameter: 8718 . dm - The `DMPLEX` object 8719 8720 Output Parameter: 8721 . globalCellNumbers - Global cell numbers for all cells on this process 8722 8723 Level: developer 8724 8725 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8726 @*/ 8727 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8728 { 8729 DM_Plex *mesh = (DM_Plex *)dm->data; 8730 8731 PetscFunctionBegin; 8732 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8733 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8734 *globalCellNumbers = mesh->globalCellNumbers; 8735 PetscFunctionReturn(PETSC_SUCCESS); 8736 } 8737 8738 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8739 { 8740 PetscInt vStart, vEnd; 8741 8742 PetscFunctionBegin; 8743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8744 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8745 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8746 PetscFunctionReturn(PETSC_SUCCESS); 8747 } 8748 8749 /*@ 8750 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8751 8752 Input Parameter: 8753 . dm - The `DMPLEX` object 8754 8755 Output Parameter: 8756 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8757 8758 Level: developer 8759 8760 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8761 @*/ 8762 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8763 { 8764 DM_Plex *mesh = (DM_Plex *)dm->data; 8765 8766 PetscFunctionBegin; 8767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8768 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8769 *globalVertexNumbers = mesh->globalVertexNumbers; 8770 PetscFunctionReturn(PETSC_SUCCESS); 8771 } 8772 8773 /*@ 8774 DMPlexCreatePointNumbering - Create a global numbering for all points. 8775 8776 Collective 8777 8778 Input Parameter: 8779 . dm - The `DMPLEX` object 8780 8781 Output Parameter: 8782 . globalPointNumbers - Global numbers for all points on this process 8783 8784 Level: developer 8785 8786 Notes: 8787 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8788 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8789 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8790 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8791 8792 The partitioned mesh is 8793 ``` 8794 (2)--0--(3)--1--(4) (1)--0--(2) 8795 ``` 8796 and its global numbering is 8797 ``` 8798 (3)--0--(4)--1--(5)--2--(6) 8799 ``` 8800 Then the global numbering is provided as 8801 ``` 8802 [0] Number of indices in set 5 8803 [0] 0 0 8804 [0] 1 1 8805 [0] 2 3 8806 [0] 3 4 8807 [0] 4 -6 8808 [1] Number of indices in set 3 8809 [1] 0 2 8810 [1] 1 5 8811 [1] 2 6 8812 ``` 8813 8814 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8815 @*/ 8816 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8817 { 8818 IS nums[4]; 8819 PetscInt depths[4], gdepths[4], starts[4]; 8820 PetscInt depth, d, shift = 0; 8821 PetscBool empty = PETSC_FALSE; 8822 8823 PetscFunctionBegin; 8824 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8825 PetscCall(DMPlexGetDepth(dm, &depth)); 8826 // For unstratified meshes use dim instead of depth 8827 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8828 // If any stratum is empty, we must mark all empty 8829 for (d = 0; d <= depth; ++d) { 8830 PetscInt end; 8831 8832 depths[d] = depth - d; 8833 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8834 if (!(starts[d] - end)) empty = PETSC_TRUE; 8835 } 8836 if (empty) 8837 for (d = 0; d <= depth; ++d) { 8838 depths[d] = -1; 8839 starts[d] = -1; 8840 } 8841 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8842 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8843 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]); 8844 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8845 for (d = 0; d <= depth; ++d) { 8846 PetscInt pStart, pEnd, gsize; 8847 8848 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8849 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8850 shift += gsize; 8851 } 8852 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8853 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8854 PetscFunctionReturn(PETSC_SUCCESS); 8855 } 8856 8857 /*@ 8858 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8859 8860 Input Parameter: 8861 . dm - The `DMPLEX` object 8862 8863 Output Parameter: 8864 . ranks - The rank field 8865 8866 Options Database Key: 8867 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8868 8869 Level: intermediate 8870 8871 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8872 @*/ 8873 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8874 { 8875 DM rdm; 8876 PetscFE fe; 8877 PetscScalar *r; 8878 PetscMPIInt rank; 8879 DMPolytopeType ct; 8880 PetscInt dim, cStart, cEnd, c; 8881 PetscBool simplex; 8882 8883 PetscFunctionBeginUser; 8884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8885 PetscAssertPointer(ranks, 2); 8886 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8887 PetscCall(DMClone(dm, &rdm)); 8888 PetscCall(DMGetDimension(rdm, &dim)); 8889 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8890 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8891 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8892 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8893 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8894 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8895 PetscCall(PetscFEDestroy(&fe)); 8896 PetscCall(DMCreateDS(rdm)); 8897 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8898 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8899 PetscCall(VecGetArray(*ranks, &r)); 8900 for (c = cStart; c < cEnd; ++c) { 8901 PetscScalar *lr; 8902 8903 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8904 if (lr) *lr = rank; 8905 } 8906 PetscCall(VecRestoreArray(*ranks, &r)); 8907 PetscCall(DMDestroy(&rdm)); 8908 PetscFunctionReturn(PETSC_SUCCESS); 8909 } 8910 8911 /*@ 8912 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8913 8914 Input Parameters: 8915 + dm - The `DMPLEX` 8916 - label - The `DMLabel` 8917 8918 Output Parameter: 8919 . val - The label value field 8920 8921 Options Database Key: 8922 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8923 8924 Level: intermediate 8925 8926 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8927 @*/ 8928 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8929 { 8930 DM rdm; 8931 PetscFE fe; 8932 PetscScalar *v; 8933 PetscInt dim, cStart, cEnd, c; 8934 8935 PetscFunctionBeginUser; 8936 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8937 PetscAssertPointer(label, 2); 8938 PetscAssertPointer(val, 3); 8939 PetscCall(DMClone(dm, &rdm)); 8940 PetscCall(DMGetDimension(rdm, &dim)); 8941 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8942 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8943 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8944 PetscCall(PetscFEDestroy(&fe)); 8945 PetscCall(DMCreateDS(rdm)); 8946 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8947 PetscCall(DMCreateGlobalVector(rdm, val)); 8948 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8949 PetscCall(VecGetArray(*val, &v)); 8950 for (c = cStart; c < cEnd; ++c) { 8951 PetscScalar *lv; 8952 PetscInt cval; 8953 8954 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8955 PetscCall(DMLabelGetValue(label, c, &cval)); 8956 *lv = cval; 8957 } 8958 PetscCall(VecRestoreArray(*val, &v)); 8959 PetscCall(DMDestroy(&rdm)); 8960 PetscFunctionReturn(PETSC_SUCCESS); 8961 } 8962 8963 /*@ 8964 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8965 8966 Input Parameter: 8967 . dm - The `DMPLEX` object 8968 8969 Level: developer 8970 8971 Notes: 8972 This is a useful diagnostic when creating meshes programmatically. 8973 8974 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8975 8976 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8977 @*/ 8978 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8979 { 8980 PetscSection coneSection, supportSection; 8981 const PetscInt *cone, *support; 8982 PetscInt coneSize, c, supportSize, s; 8983 PetscInt pStart, pEnd, p, pp, csize, ssize; 8984 PetscBool storagecheck = PETSC_TRUE; 8985 8986 PetscFunctionBegin; 8987 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8988 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8989 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8990 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8991 /* Check that point p is found in the support of its cone points, and vice versa */ 8992 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8993 for (p = pStart; p < pEnd; ++p) { 8994 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8995 PetscCall(DMPlexGetCone(dm, p, &cone)); 8996 for (c = 0; c < coneSize; ++c) { 8997 PetscBool dup = PETSC_FALSE; 8998 PetscInt d; 8999 for (d = c - 1; d >= 0; --d) { 9000 if (cone[c] == cone[d]) { 9001 dup = PETSC_TRUE; 9002 break; 9003 } 9004 } 9005 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 9006 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 9007 for (s = 0; s < supportSize; ++s) { 9008 if (support[s] == p) break; 9009 } 9010 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 9011 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 9012 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 9013 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9014 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 9015 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 9016 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9017 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]); 9018 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 9019 } 9020 } 9021 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 9022 if (p != pp) { 9023 storagecheck = PETSC_FALSE; 9024 continue; 9025 } 9026 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 9027 PetscCall(DMPlexGetSupport(dm, p, &support)); 9028 for (s = 0; s < supportSize; ++s) { 9029 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 9030 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 9031 for (c = 0; c < coneSize; ++c) { 9032 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 9033 if (cone[c] != pp) { 9034 c = 0; 9035 break; 9036 } 9037 if (cone[c] == p) break; 9038 } 9039 if (c >= coneSize) { 9040 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 9041 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 9042 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9043 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 9044 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 9045 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9046 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 9047 } 9048 } 9049 } 9050 if (storagecheck) { 9051 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 9052 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 9053 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 9054 } 9055 PetscFunctionReturn(PETSC_SUCCESS); 9056 } 9057 9058 /* 9059 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. 9060 */ 9061 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 9062 { 9063 DMPolytopeType cct; 9064 PetscInt ptpoints[4]; 9065 const PetscInt *cone, *ccone, *ptcone; 9066 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 9067 9068 PetscFunctionBegin; 9069 *unsplit = 0; 9070 switch (ct) { 9071 case DM_POLYTOPE_POINT_PRISM_TENSOR: 9072 ptpoints[npt++] = c; 9073 break; 9074 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9075 PetscCall(DMPlexGetCone(dm, c, &cone)); 9076 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9077 for (cp = 0; cp < coneSize; ++cp) { 9078 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 9079 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 9080 } 9081 break; 9082 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9083 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9084 PetscCall(DMPlexGetCone(dm, c, &cone)); 9085 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9086 for (cp = 0; cp < coneSize; ++cp) { 9087 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 9088 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 9089 for (ccp = 0; ccp < cconeSize; ++ccp) { 9090 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 9091 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 9092 PetscInt p; 9093 for (p = 0; p < npt; ++p) 9094 if (ptpoints[p] == ccone[ccp]) break; 9095 if (p == npt) ptpoints[npt++] = ccone[ccp]; 9096 } 9097 } 9098 } 9099 break; 9100 default: 9101 break; 9102 } 9103 for (pt = 0; pt < npt; ++pt) { 9104 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 9105 if (ptcone[0] == ptcone[1]) ++(*unsplit); 9106 } 9107 PetscFunctionReturn(PETSC_SUCCESS); 9108 } 9109 9110 /*@ 9111 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 9112 9113 Input Parameters: 9114 + dm - The `DMPLEX` object 9115 - cellHeight - Normally 0 9116 9117 Level: developer 9118 9119 Notes: 9120 This is a useful diagnostic when creating meshes programmatically. 9121 Currently applicable only to homogeneous simplex or tensor meshes. 9122 9123 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9124 9125 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9126 @*/ 9127 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 9128 { 9129 DMPlexInterpolatedFlag interp; 9130 DMPolytopeType ct; 9131 PetscInt vStart, vEnd, cStart, cEnd, c; 9132 9133 PetscFunctionBegin; 9134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9135 PetscCall(DMPlexIsInterpolated(dm, &interp)); 9136 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9137 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9138 for (c = cStart; c < cEnd; ++c) { 9139 PetscInt *closure = NULL; 9140 PetscInt coneSize, closureSize, cl, Nv = 0; 9141 9142 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9143 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 9144 if (ct == DM_POLYTOPE_UNKNOWN) continue; 9145 if (interp == DMPLEX_INTERPOLATED_FULL) { 9146 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9147 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)); 9148 } 9149 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9150 for (cl = 0; cl < closureSize * 2; cl += 2) { 9151 const PetscInt p = closure[cl]; 9152 if ((p >= vStart) && (p < vEnd)) ++Nv; 9153 } 9154 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9155 /* Special Case: Tensor faces with identified vertices */ 9156 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 9157 PetscInt unsplit; 9158 9159 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9160 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 9161 } 9162 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)); 9163 } 9164 PetscFunctionReturn(PETSC_SUCCESS); 9165 } 9166 9167 /*@ 9168 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 9169 9170 Collective 9171 9172 Input Parameters: 9173 + dm - The `DMPLEX` object 9174 - cellHeight - Normally 0 9175 9176 Level: developer 9177 9178 Notes: 9179 This is a useful diagnostic when creating meshes programmatically. 9180 This routine is only relevant for meshes that are fully interpolated across all ranks. 9181 It will error out if a partially interpolated mesh is given on some rank. 9182 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 9183 9184 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9185 9186 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 9187 @*/ 9188 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 9189 { 9190 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 9191 DMPlexInterpolatedFlag interpEnum; 9192 9193 PetscFunctionBegin; 9194 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9195 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 9196 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 9197 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 9198 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 9199 PetscFunctionReturn(PETSC_SUCCESS); 9200 } 9201 9202 PetscCall(DMGetDimension(dm, &dim)); 9203 PetscCall(DMPlexGetDepth(dm, &depth)); 9204 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 9205 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 9206 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 9207 for (c = cStart; c < cEnd; ++c) { 9208 const PetscInt *cone, *ornt, *faceSizes, *faces; 9209 const DMPolytopeType *faceTypes; 9210 DMPolytopeType ct; 9211 PetscInt numFaces, coneSize, f; 9212 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 9213 9214 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9215 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9216 if (unsplit) continue; 9217 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 9218 PetscCall(DMPlexGetCone(dm, c, &cone)); 9219 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 9220 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9221 for (cl = 0; cl < closureSize * 2; cl += 2) { 9222 const PetscInt p = closure[cl]; 9223 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 9224 } 9225 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9226 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); 9227 for (f = 0; f < numFaces; ++f) { 9228 DMPolytopeType fct; 9229 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 9230 9231 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 9232 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9233 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 9234 const PetscInt p = fclosure[cl]; 9235 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 9236 } 9237 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]); 9238 for (v = 0; v < fnumCorners; ++v) { 9239 if (fclosure[v] != faces[fOff + v]) { 9240 PetscInt v1; 9241 9242 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 9243 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 9244 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 9245 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 9246 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 9247 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]); 9248 } 9249 } 9250 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 9251 fOff += faceSizes[f]; 9252 } 9253 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 9254 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 9255 } 9256 } 9257 PetscFunctionReturn(PETSC_SUCCESS); 9258 } 9259 9260 /*@ 9261 DMPlexCheckGeometry - Check the geometry of mesh cells 9262 9263 Input Parameter: 9264 . dm - The `DMPLEX` object 9265 9266 Level: developer 9267 9268 Notes: 9269 This is a useful diagnostic when creating meshes programmatically. 9270 9271 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9272 9273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9274 @*/ 9275 PetscErrorCode DMPlexCheckGeometry(DM dm) 9276 { 9277 Vec coordinates; 9278 PetscReal detJ, J[9], refVol = 1.0; 9279 PetscReal vol; 9280 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9281 9282 PetscFunctionBegin; 9283 PetscCall(DMGetDimension(dm, &dim)); 9284 PetscCall(DMGetCoordinateDim(dm, &dE)); 9285 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9286 PetscCall(DMPlexGetDepth(dm, &depth)); 9287 for (d = 0; d < dim; ++d) refVol *= 2.0; 9288 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9289 /* Make sure local coordinates are created, because that step is collective */ 9290 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9291 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9292 for (c = cStart; c < cEnd; ++c) { 9293 DMPolytopeType ct; 9294 PetscInt unsplit; 9295 PetscBool ignoreZeroVol = PETSC_FALSE; 9296 9297 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9298 switch (ct) { 9299 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9300 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9301 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9302 ignoreZeroVol = PETSC_TRUE; 9303 break; 9304 default: 9305 break; 9306 } 9307 switch (ct) { 9308 case DM_POLYTOPE_TRI_PRISM: 9309 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9310 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9311 case DM_POLYTOPE_PYRAMID: 9312 continue; 9313 default: 9314 break; 9315 } 9316 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9317 if (unsplit) continue; 9318 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9319 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); 9320 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9321 /* This should work with periodicity since DG coordinates should be used */ 9322 if (depth > 1) { 9323 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9324 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); 9325 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9326 } 9327 } 9328 PetscFunctionReturn(PETSC_SUCCESS); 9329 } 9330 9331 /*@ 9332 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9333 9334 Collective 9335 9336 Input Parameters: 9337 + dm - The `DMPLEX` object 9338 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9339 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9340 9341 Level: developer 9342 9343 Notes: 9344 This is mainly intended for debugging/testing purposes. 9345 9346 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9347 9348 Extra roots can come from periodic cuts, where additional points appear on the boundary 9349 9350 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9351 @*/ 9352 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9353 { 9354 PetscInt l, nleaves, nroots, overlap; 9355 const PetscInt *locals; 9356 const PetscSFNode *remotes; 9357 PetscBool distributed; 9358 MPI_Comm comm; 9359 PetscMPIInt rank; 9360 9361 PetscFunctionBegin; 9362 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9363 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9364 else pointSF = dm->sf; 9365 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9366 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9367 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9368 { 9369 PetscMPIInt mpiFlag; 9370 9371 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9372 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9373 } 9374 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9375 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9376 if (!distributed) { 9377 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); 9378 PetscFunctionReturn(PETSC_SUCCESS); 9379 } 9380 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); 9381 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9382 9383 /* Check SF graph is compatible with DMPlex chart */ 9384 { 9385 PetscInt pStart, pEnd, maxLeaf; 9386 9387 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9388 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9389 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9390 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9391 } 9392 9393 /* Check Point SF has no local points referenced */ 9394 for (l = 0; l < nleaves; l++) { 9395 PetscAssert(remotes[l].rank != (PetscInt)rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 9396 } 9397 9398 /* Check there are no cells in interface */ 9399 if (!overlap) { 9400 PetscInt cellHeight, cStart, cEnd; 9401 9402 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9403 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9404 for (l = 0; l < nleaves; ++l) { 9405 const PetscInt point = locals ? locals[l] : l; 9406 9407 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9408 } 9409 } 9410 9411 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9412 { 9413 const PetscInt *rootdegree; 9414 9415 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9416 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9417 for (l = 0; l < nleaves; ++l) { 9418 const PetscInt point = locals ? locals[l] : l; 9419 const PetscInt *cone; 9420 PetscInt coneSize, c, idx; 9421 9422 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9423 PetscCall(DMPlexGetCone(dm, point, &cone)); 9424 for (c = 0; c < coneSize; ++c) { 9425 if (!rootdegree[cone[c]]) { 9426 if (locals) { 9427 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9428 } else { 9429 idx = (cone[c] < nleaves) ? cone[c] : -1; 9430 } 9431 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9432 } 9433 } 9434 } 9435 } 9436 PetscFunctionReturn(PETSC_SUCCESS); 9437 } 9438 9439 /*@ 9440 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9441 9442 Input Parameter: 9443 . dm - The `DMPLEX` object 9444 9445 Level: developer 9446 9447 Notes: 9448 This is a useful diagnostic when creating meshes programmatically. 9449 9450 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9451 9452 Currently does not include `DMPlexCheckCellShape()`. 9453 9454 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9455 @*/ 9456 PetscErrorCode DMPlexCheck(DM dm) 9457 { 9458 PetscInt cellHeight; 9459 9460 PetscFunctionBegin; 9461 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9462 PetscCall(DMPlexCheckSymmetry(dm)); 9463 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9464 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9465 PetscCall(DMPlexCheckGeometry(dm)); 9466 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9467 PetscCall(DMPlexCheckInterfaceCones(dm)); 9468 PetscFunctionReturn(PETSC_SUCCESS); 9469 } 9470 9471 typedef struct cell_stats { 9472 PetscReal min, max, sum, squaresum; 9473 PetscInt count; 9474 } cell_stats_t; 9475 9476 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9477 { 9478 PetscInt i, N = *len; 9479 9480 for (i = 0; i < N; i++) { 9481 cell_stats_t *A = (cell_stats_t *)a; 9482 cell_stats_t *B = (cell_stats_t *)b; 9483 9484 B->min = PetscMin(A->min, B->min); 9485 B->max = PetscMax(A->max, B->max); 9486 B->sum += A->sum; 9487 B->squaresum += A->squaresum; 9488 B->count += A->count; 9489 } 9490 } 9491 9492 /*@ 9493 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9494 9495 Collective 9496 9497 Input Parameters: 9498 + dm - The `DMPLEX` object 9499 . output - If true, statistics will be displayed on `stdout` 9500 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9501 9502 Level: developer 9503 9504 Notes: 9505 This is mainly intended for debugging/testing purposes. 9506 9507 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9508 9509 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9510 @*/ 9511 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9512 { 9513 DM dmCoarse; 9514 cell_stats_t stats, globalStats; 9515 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9516 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9517 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9518 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9519 PetscMPIInt rank, size; 9520 9521 PetscFunctionBegin; 9522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9523 stats.min = PETSC_MAX_REAL; 9524 stats.max = PETSC_MIN_REAL; 9525 stats.sum = stats.squaresum = 0.; 9526 stats.count = 0; 9527 9528 PetscCallMPI(MPI_Comm_size(comm, &size)); 9529 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9530 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9531 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9532 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9533 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9534 for (c = cStart; c < cEnd; c++) { 9535 PetscInt i; 9536 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9537 9538 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9539 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9540 for (i = 0; i < PetscSqr(cdim); ++i) { 9541 frobJ += J[i] * J[i]; 9542 frobInvJ += invJ[i] * invJ[i]; 9543 } 9544 cond2 = frobJ * frobInvJ; 9545 cond = PetscSqrtReal(cond2); 9546 9547 stats.min = PetscMin(stats.min, cond); 9548 stats.max = PetscMax(stats.max, cond); 9549 stats.sum += cond; 9550 stats.squaresum += cond2; 9551 stats.count++; 9552 if (output && cond > limit) { 9553 PetscSection coordSection; 9554 Vec coordsLocal; 9555 PetscScalar *coords = NULL; 9556 PetscInt Nv, d, clSize, cl, *closure = NULL; 9557 9558 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9559 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9560 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9561 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9562 for (i = 0; i < Nv / cdim; ++i) { 9563 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9564 for (d = 0; d < cdim; ++d) { 9565 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9566 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9567 } 9568 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9569 } 9570 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9571 for (cl = 0; cl < clSize * 2; cl += 2) { 9572 const PetscInt edge = closure[cl]; 9573 9574 if ((edge >= eStart) && (edge < eEnd)) { 9575 PetscReal len; 9576 9577 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9578 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9579 } 9580 } 9581 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9582 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9583 } 9584 } 9585 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9586 9587 if (size > 1) { 9588 PetscMPIInt blockLengths[2] = {4, 1}; 9589 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9590 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9591 MPI_Op statReduce; 9592 9593 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9594 PetscCallMPI(MPI_Type_commit(&statType)); 9595 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9596 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9597 PetscCallMPI(MPI_Op_free(&statReduce)); 9598 PetscCallMPI(MPI_Type_free(&statType)); 9599 } else { 9600 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9601 } 9602 if (rank == 0) { 9603 count = globalStats.count; 9604 min = globalStats.min; 9605 max = globalStats.max; 9606 mean = globalStats.sum / globalStats.count; 9607 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9608 } 9609 9610 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)); 9611 PetscCall(PetscFree2(J, invJ)); 9612 9613 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9614 if (dmCoarse) { 9615 PetscBool isplex; 9616 9617 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9618 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9619 } 9620 PetscFunctionReturn(PETSC_SUCCESS); 9621 } 9622 9623 /*@ 9624 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9625 orthogonal quality below given tolerance. 9626 9627 Collective 9628 9629 Input Parameters: 9630 + dm - The `DMPLEX` object 9631 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9632 - atol - [0, 1] Absolute tolerance for tagging cells. 9633 9634 Output Parameters: 9635 + OrthQual - `Vec` containing orthogonal quality per cell 9636 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9637 9638 Options Database Keys: 9639 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9640 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9641 9642 Level: intermediate 9643 9644 Notes: 9645 Orthogonal quality is given by the following formula\: 9646 9647 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9648 9649 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 9650 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9651 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9652 calculating the cosine of the angle between these vectors. 9653 9654 Orthogonal quality ranges from 1 (best) to 0 (worst). 9655 9656 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9657 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9658 9659 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9660 9661 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9662 @*/ 9663 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9664 { 9665 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9666 PetscInt *idx; 9667 PetscScalar *oqVals; 9668 const PetscScalar *cellGeomArr, *faceGeomArr; 9669 PetscReal *ci, *fi, *Ai; 9670 MPI_Comm comm; 9671 Vec cellgeom, facegeom; 9672 DM dmFace, dmCell; 9673 IS glob; 9674 ISLocalToGlobalMapping ltog; 9675 PetscViewer vwr; 9676 9677 PetscFunctionBegin; 9678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9679 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9680 PetscAssertPointer(OrthQual, 4); 9681 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9682 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9683 PetscCall(DMGetDimension(dm, &nc)); 9684 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9685 { 9686 DMPlexInterpolatedFlag interpFlag; 9687 9688 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9689 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9690 PetscMPIInt rank; 9691 9692 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9693 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9694 } 9695 } 9696 if (OrthQualLabel) { 9697 PetscAssertPointer(OrthQualLabel, 5); 9698 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9699 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9700 } else { 9701 *OrthQualLabel = NULL; 9702 } 9703 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9704 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9705 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9706 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9707 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9708 PetscCall(VecCreate(comm, OrthQual)); 9709 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9710 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9711 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9712 PetscCall(VecSetUp(*OrthQual)); 9713 PetscCall(ISDestroy(&glob)); 9714 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9715 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9716 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9717 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9718 PetscCall(VecGetDM(cellgeom, &dmCell)); 9719 PetscCall(VecGetDM(facegeom, &dmFace)); 9720 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9721 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9722 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9723 PetscInt cellarr[2], *adj = NULL; 9724 PetscScalar *cArr, *fArr; 9725 PetscReal minvalc = 1.0, minvalf = 1.0; 9726 PetscFVCellGeom *cg; 9727 9728 idx[cellIter] = cell - cStart; 9729 cellarr[0] = cell; 9730 /* Make indexing into cellGeom easier */ 9731 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9732 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9733 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9734 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9735 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9736 PetscInt i; 9737 const PetscInt neigh = adj[cellneigh]; 9738 PetscReal normci = 0, normfi = 0, normai = 0; 9739 PetscFVCellGeom *cgneigh; 9740 PetscFVFaceGeom *fg; 9741 9742 /* Don't count ourselves in the neighbor list */ 9743 if (neigh == cell) continue; 9744 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9745 cellarr[1] = neigh; 9746 { 9747 PetscInt numcovpts; 9748 const PetscInt *covpts; 9749 9750 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9751 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9752 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9753 } 9754 9755 /* Compute c_i, f_i and their norms */ 9756 for (i = 0; i < nc; i++) { 9757 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9758 fi[i] = fg->centroid[i] - cg->centroid[i]; 9759 Ai[i] = fg->normal[i]; 9760 normci += PetscPowReal(ci[i], 2); 9761 normfi += PetscPowReal(fi[i], 2); 9762 normai += PetscPowReal(Ai[i], 2); 9763 } 9764 normci = PetscSqrtReal(normci); 9765 normfi = PetscSqrtReal(normfi); 9766 normai = PetscSqrtReal(normai); 9767 9768 /* Normalize and compute for each face-cell-normal pair */ 9769 for (i = 0; i < nc; i++) { 9770 ci[i] = ci[i] / normci; 9771 fi[i] = fi[i] / normfi; 9772 Ai[i] = Ai[i] / normai; 9773 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9774 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9775 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9776 } 9777 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9778 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9779 } 9780 PetscCall(PetscFree(adj)); 9781 PetscCall(PetscFree2(cArr, fArr)); 9782 /* Defer to cell if they're equal */ 9783 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9784 if (OrthQualLabel) { 9785 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9786 } 9787 } 9788 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9789 PetscCall(VecAssemblyBegin(*OrthQual)); 9790 PetscCall(VecAssemblyEnd(*OrthQual)); 9791 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9792 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9793 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9794 if (OrthQualLabel) { 9795 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9796 } 9797 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9798 PetscCall(PetscOptionsRestoreViewer(&vwr)); 9799 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9800 PetscFunctionReturn(PETSC_SUCCESS); 9801 } 9802 9803 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9804 * interpolator construction */ 9805 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9806 { 9807 PetscSection section, newSection, gsection; 9808 PetscSF sf; 9809 PetscBool hasConstraints, ghasConstraints; 9810 9811 PetscFunctionBegin; 9812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9813 PetscAssertPointer(odm, 2); 9814 PetscCall(DMGetLocalSection(dm, §ion)); 9815 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9816 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9817 if (!ghasConstraints) { 9818 PetscCall(PetscObjectReference((PetscObject)dm)); 9819 *odm = dm; 9820 PetscFunctionReturn(PETSC_SUCCESS); 9821 } 9822 PetscCall(DMClone(dm, odm)); 9823 PetscCall(DMCopyFields(dm, *odm)); 9824 PetscCall(DMGetLocalSection(*odm, &newSection)); 9825 PetscCall(DMGetPointSF(*odm, &sf)); 9826 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9827 PetscCall(DMSetGlobalSection(*odm, gsection)); 9828 PetscCall(PetscSectionDestroy(&gsection)); 9829 PetscFunctionReturn(PETSC_SUCCESS); 9830 } 9831 9832 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9833 { 9834 DM dmco, dmfo; 9835 Mat interpo; 9836 Vec rscale; 9837 Vec cglobalo, clocal; 9838 Vec fglobal, fglobalo, flocal; 9839 PetscBool regular; 9840 9841 PetscFunctionBegin; 9842 PetscCall(DMGetFullDM(dmc, &dmco)); 9843 PetscCall(DMGetFullDM(dmf, &dmfo)); 9844 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9845 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9846 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9847 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9848 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9849 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9850 PetscCall(VecSet(cglobalo, 0.)); 9851 PetscCall(VecSet(clocal, 0.)); 9852 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9853 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9854 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9855 PetscCall(VecSet(fglobal, 0.)); 9856 PetscCall(VecSet(fglobalo, 0.)); 9857 PetscCall(VecSet(flocal, 0.)); 9858 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9859 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9860 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9861 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9862 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9863 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9864 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9865 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9866 *shift = fglobal; 9867 PetscCall(VecDestroy(&flocal)); 9868 PetscCall(VecDestroy(&fglobalo)); 9869 PetscCall(VecDestroy(&clocal)); 9870 PetscCall(VecDestroy(&cglobalo)); 9871 PetscCall(VecDestroy(&rscale)); 9872 PetscCall(MatDestroy(&interpo)); 9873 PetscCall(DMDestroy(&dmfo)); 9874 PetscCall(DMDestroy(&dmco)); 9875 PetscFunctionReturn(PETSC_SUCCESS); 9876 } 9877 9878 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9879 { 9880 PetscObject shifto; 9881 Vec shift; 9882 9883 PetscFunctionBegin; 9884 if (!interp) { 9885 Vec rscale; 9886 9887 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9888 PetscCall(VecDestroy(&rscale)); 9889 } else { 9890 PetscCall(PetscObjectReference((PetscObject)interp)); 9891 } 9892 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9893 if (!shifto) { 9894 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9895 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9896 shifto = (PetscObject)shift; 9897 PetscCall(VecDestroy(&shift)); 9898 } 9899 shift = (Vec)shifto; 9900 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9901 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9902 PetscCall(MatDestroy(&interp)); 9903 PetscFunctionReturn(PETSC_SUCCESS); 9904 } 9905 9906 /* Pointwise interpolation 9907 Just code FEM for now 9908 u^f = I u^c 9909 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9910 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9911 I_{ij} = psi^f_i phi^c_j 9912 */ 9913 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9914 { 9915 PetscSection gsc, gsf; 9916 PetscInt m, n; 9917 void *ctx; 9918 DM cdm; 9919 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9920 9921 PetscFunctionBegin; 9922 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9923 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9924 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9925 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9926 9927 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9928 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9929 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9930 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9931 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9932 9933 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9934 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9935 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9936 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9937 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9938 if (scaling) { 9939 /* Use naive scaling */ 9940 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9941 } 9942 PetscFunctionReturn(PETSC_SUCCESS); 9943 } 9944 9945 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9946 { 9947 VecScatter ctx; 9948 9949 PetscFunctionBegin; 9950 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9951 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9952 PetscCall(VecScatterDestroy(&ctx)); 9953 PetscFunctionReturn(PETSC_SUCCESS); 9954 } 9955 9956 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[]) 9957 { 9958 const PetscInt Nc = uOff[1] - uOff[0]; 9959 PetscInt c; 9960 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9961 } 9962 9963 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9964 { 9965 DM dmc; 9966 PetscDS ds; 9967 Vec ones, locmass; 9968 IS cellIS; 9969 PetscFormKey key; 9970 PetscInt depth; 9971 9972 PetscFunctionBegin; 9973 PetscCall(DMClone(dm, &dmc)); 9974 PetscCall(DMCopyDisc(dm, dmc)); 9975 PetscCall(DMGetDS(dmc, &ds)); 9976 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9977 PetscCall(DMCreateGlobalVector(dmc, mass)); 9978 PetscCall(DMGetLocalVector(dmc, &ones)); 9979 PetscCall(DMGetLocalVector(dmc, &locmass)); 9980 PetscCall(DMPlexGetDepth(dmc, &depth)); 9981 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9982 PetscCall(VecSet(locmass, 0.0)); 9983 PetscCall(VecSet(ones, 1.0)); 9984 key.label = NULL; 9985 key.value = 0; 9986 key.field = 0; 9987 key.part = 0; 9988 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9989 PetscCall(ISDestroy(&cellIS)); 9990 PetscCall(VecSet(*mass, 0.0)); 9991 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9992 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9993 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9994 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9995 PetscCall(DMDestroy(&dmc)); 9996 PetscFunctionReturn(PETSC_SUCCESS); 9997 } 9998 9999 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 10000 { 10001 PetscSection gsc, gsf; 10002 PetscInt m, n; 10003 void *ctx; 10004 DM cdm; 10005 PetscBool regular; 10006 10007 PetscFunctionBegin; 10008 if (dmFine == dmCoarse) { 10009 DM dmc; 10010 PetscDS ds; 10011 PetscWeakForm wf; 10012 Vec u; 10013 IS cellIS; 10014 PetscFormKey key; 10015 PetscInt depth; 10016 10017 PetscCall(DMClone(dmFine, &dmc)); 10018 PetscCall(DMCopyDisc(dmFine, dmc)); 10019 PetscCall(DMGetDS(dmc, &ds)); 10020 PetscCall(PetscDSGetWeakForm(ds, &wf)); 10021 PetscCall(PetscWeakFormClear(wf)); 10022 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 10023 PetscCall(DMCreateMatrix(dmc, mass)); 10024 PetscCall(DMGetLocalVector(dmc, &u)); 10025 PetscCall(DMPlexGetDepth(dmc, &depth)); 10026 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 10027 PetscCall(MatZeroEntries(*mass)); 10028 key.label = NULL; 10029 key.value = 0; 10030 key.field = 0; 10031 key.part = 0; 10032 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 10033 PetscCall(ISDestroy(&cellIS)); 10034 PetscCall(DMRestoreLocalVector(dmc, &u)); 10035 PetscCall(DMDestroy(&dmc)); 10036 } else { 10037 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 10038 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 10039 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 10040 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 10041 10042 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 10043 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 10044 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 10045 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 10046 10047 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 10048 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 10049 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 10050 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 10051 } 10052 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 10053 PetscFunctionReturn(PETSC_SUCCESS); 10054 } 10055 10056 /*@ 10057 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10058 10059 Input Parameter: 10060 . dm - The `DMPLEX` object 10061 10062 Output Parameter: 10063 . regular - The flag 10064 10065 Level: intermediate 10066 10067 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 10068 @*/ 10069 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 10070 { 10071 PetscFunctionBegin; 10072 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10073 PetscAssertPointer(regular, 2); 10074 *regular = ((DM_Plex *)dm->data)->regularRefinement; 10075 PetscFunctionReturn(PETSC_SUCCESS); 10076 } 10077 10078 /*@ 10079 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 10080 10081 Input Parameters: 10082 + dm - The `DMPLEX` object 10083 - regular - The flag 10084 10085 Level: intermediate 10086 10087 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 10088 @*/ 10089 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 10090 { 10091 PetscFunctionBegin; 10092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10093 ((DM_Plex *)dm->data)->regularRefinement = regular; 10094 PetscFunctionReturn(PETSC_SUCCESS); 10095 } 10096 10097 /*@ 10098 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 10099 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 10100 10101 Not Collective 10102 10103 Input Parameter: 10104 . dm - The `DMPLEX` object 10105 10106 Output Parameters: 10107 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 10108 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 10109 10110 Level: intermediate 10111 10112 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 10113 @*/ 10114 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 10115 { 10116 DM_Plex *plex = (DM_Plex *)dm->data; 10117 10118 PetscFunctionBegin; 10119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10120 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 10121 if (anchorSection) *anchorSection = plex->anchorSection; 10122 if (anchorIS) *anchorIS = plex->anchorIS; 10123 PetscFunctionReturn(PETSC_SUCCESS); 10124 } 10125 10126 /*@ 10127 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 10128 10129 Collective 10130 10131 Input Parameters: 10132 + dm - The `DMPLEX` object 10133 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 10134 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10135 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 10136 10137 Level: intermediate 10138 10139 Notes: 10140 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 10141 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 10142 combination of other points' degrees of freedom. 10143 10144 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 10145 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 10146 10147 The reference counts of `anchorSection` and `anchorIS` are incremented. 10148 10149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 10150 @*/ 10151 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 10152 { 10153 DM_Plex *plex = (DM_Plex *)dm->data; 10154 PetscMPIInt result; 10155 10156 PetscFunctionBegin; 10157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10158 if (anchorSection) { 10159 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 10160 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 10161 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 10162 } 10163 if (anchorIS) { 10164 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 10165 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 10166 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 10167 } 10168 10169 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 10170 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 10171 plex->anchorSection = anchorSection; 10172 10173 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 10174 PetscCall(ISDestroy(&plex->anchorIS)); 10175 plex->anchorIS = anchorIS; 10176 10177 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 10178 PetscInt size, a, pStart, pEnd; 10179 const PetscInt *anchors; 10180 10181 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10182 PetscCall(ISGetLocalSize(anchorIS, &size)); 10183 PetscCall(ISGetIndices(anchorIS, &anchors)); 10184 for (a = 0; a < size; a++) { 10185 PetscInt p; 10186 10187 p = anchors[a]; 10188 if (p >= pStart && p < pEnd) { 10189 PetscInt dof; 10190 10191 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10192 if (dof) { 10193 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10194 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 10195 } 10196 } 10197 } 10198 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 10199 } 10200 /* reset the generic constraints */ 10201 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 10202 PetscFunctionReturn(PETSC_SUCCESS); 10203 } 10204 10205 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 10206 { 10207 PetscSection anchorSection; 10208 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 10209 10210 PetscFunctionBegin; 10211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10212 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10213 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 10214 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10215 if (numFields) { 10216 PetscInt f; 10217 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 10218 10219 for (f = 0; f < numFields; f++) { 10220 PetscInt numComp; 10221 10222 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 10223 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 10224 } 10225 } 10226 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 10227 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10228 pStart = PetscMax(pStart, sStart); 10229 pEnd = PetscMin(pEnd, sEnd); 10230 pEnd = PetscMax(pStart, pEnd); 10231 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 10232 for (p = pStart; p < pEnd; p++) { 10233 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 10234 if (dof) { 10235 PetscCall(PetscSectionGetDof(section, p, &dof)); 10236 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 10237 for (f = 0; f < numFields; f++) { 10238 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 10239 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 10240 } 10241 } 10242 } 10243 PetscCall(PetscSectionSetUp(*cSec)); 10244 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 10245 PetscFunctionReturn(PETSC_SUCCESS); 10246 } 10247 10248 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 10249 { 10250 PetscSection aSec; 10251 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 10252 const PetscInt *anchors; 10253 PetscInt numFields, f; 10254 IS aIS; 10255 MatType mtype; 10256 PetscBool iscuda, iskokkos; 10257 10258 PetscFunctionBegin; 10259 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10260 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 10261 PetscCall(PetscSectionGetStorageSize(section, &n)); 10262 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 10263 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 10264 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 10265 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 10266 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 10267 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 10268 if (iscuda) mtype = MATSEQAIJCUSPARSE; 10269 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 10270 else mtype = MATSEQAIJ; 10271 PetscCall(MatSetType(*cMat, mtype)); 10272 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10273 PetscCall(ISGetIndices(aIS, &anchors)); 10274 /* cSec will be a subset of aSec and section */ 10275 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10276 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10277 PetscCall(PetscMalloc1(m + 1, &i)); 10278 i[0] = 0; 10279 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10280 for (p = pStart; p < pEnd; p++) { 10281 PetscInt rDof, rOff, r; 10282 10283 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10284 if (!rDof) continue; 10285 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10286 if (numFields) { 10287 for (f = 0; f < numFields; f++) { 10288 annz = 0; 10289 for (r = 0; r < rDof; r++) { 10290 a = anchors[rOff + r]; 10291 if (a < sStart || a >= sEnd) continue; 10292 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10293 annz += aDof; 10294 } 10295 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10296 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10297 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10298 } 10299 } else { 10300 annz = 0; 10301 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10302 for (q = 0; q < dof; q++) { 10303 a = anchors[rOff + q]; 10304 if (a < sStart || a >= sEnd) continue; 10305 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10306 annz += aDof; 10307 } 10308 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10309 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10310 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10311 } 10312 } 10313 nnz = i[m]; 10314 PetscCall(PetscMalloc1(nnz, &j)); 10315 offset = 0; 10316 for (p = pStart; p < pEnd; p++) { 10317 if (numFields) { 10318 for (f = 0; f < numFields; f++) { 10319 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10320 for (q = 0; q < dof; q++) { 10321 PetscInt rDof, rOff, r; 10322 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10323 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10324 for (r = 0; r < rDof; r++) { 10325 PetscInt s; 10326 10327 a = anchors[rOff + r]; 10328 if (a < sStart || a >= sEnd) continue; 10329 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10330 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10331 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10332 } 10333 } 10334 } 10335 } else { 10336 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10337 for (q = 0; q < dof; q++) { 10338 PetscInt rDof, rOff, r; 10339 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10340 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10341 for (r = 0; r < rDof; r++) { 10342 PetscInt s; 10343 10344 a = anchors[rOff + r]; 10345 if (a < sStart || a >= sEnd) continue; 10346 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10347 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10348 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10349 } 10350 } 10351 } 10352 } 10353 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10354 PetscCall(PetscFree(i)); 10355 PetscCall(PetscFree(j)); 10356 PetscCall(ISRestoreIndices(aIS, &anchors)); 10357 PetscFunctionReturn(PETSC_SUCCESS); 10358 } 10359 10360 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10361 { 10362 DM_Plex *plex = (DM_Plex *)dm->data; 10363 PetscSection anchorSection, section, cSec; 10364 Mat cMat; 10365 10366 PetscFunctionBegin; 10367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10368 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10369 if (anchorSection) { 10370 PetscInt Nf; 10371 10372 PetscCall(DMGetLocalSection(dm, §ion)); 10373 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10374 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10375 PetscCall(DMGetNumFields(dm, &Nf)); 10376 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10377 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10378 PetscCall(PetscSectionDestroy(&cSec)); 10379 PetscCall(MatDestroy(&cMat)); 10380 } 10381 PetscFunctionReturn(PETSC_SUCCESS); 10382 } 10383 10384 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10385 { 10386 IS subis; 10387 PetscSection section, subsection; 10388 10389 PetscFunctionBegin; 10390 PetscCall(DMGetLocalSection(dm, §ion)); 10391 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10392 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10393 /* Create subdomain */ 10394 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10395 /* Create submodel */ 10396 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10397 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10398 PetscCall(DMSetLocalSection(*subdm, subsection)); 10399 PetscCall(PetscSectionDestroy(&subsection)); 10400 PetscCall(DMCopyDisc(dm, *subdm)); 10401 /* Create map from submodel to global model */ 10402 if (is) { 10403 PetscSection sectionGlobal, subsectionGlobal; 10404 IS spIS; 10405 const PetscInt *spmap; 10406 PetscInt *subIndices; 10407 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10408 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10409 10410 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10411 PetscCall(ISGetIndices(spIS, &spmap)); 10412 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10413 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10414 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10415 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10416 for (p = pStart; p < pEnd; ++p) { 10417 PetscInt gdof, pSubSize = 0; 10418 10419 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10420 if (gdof > 0) { 10421 for (f = 0; f < Nf; ++f) { 10422 PetscInt fdof, fcdof; 10423 10424 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10425 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10426 pSubSize += fdof - fcdof; 10427 } 10428 subSize += pSubSize; 10429 if (pSubSize) { 10430 if (bs < 0) { 10431 bs = pSubSize; 10432 } else if (bs != pSubSize) { 10433 /* Layout does not admit a pointwise block size */ 10434 bs = 1; 10435 } 10436 } 10437 } 10438 } 10439 /* Must have same blocksize on all procs (some might have no points) */ 10440 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10441 bsLocal[1] = bs; 10442 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10443 if (bsMinMax[0] != bsMinMax[1]) { 10444 bs = 1; 10445 } else { 10446 bs = bsMinMax[0]; 10447 } 10448 PetscCall(PetscMalloc1(subSize, &subIndices)); 10449 for (p = pStart; p < pEnd; ++p) { 10450 PetscInt gdof, goff; 10451 10452 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10453 if (gdof > 0) { 10454 const PetscInt point = spmap[p]; 10455 10456 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10457 for (f = 0; f < Nf; ++f) { 10458 PetscInt fdof, fcdof, fc, f2, poff = 0; 10459 10460 /* Can get rid of this loop by storing field information in the global section */ 10461 for (f2 = 0; f2 < f; ++f2) { 10462 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10463 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10464 poff += fdof - fcdof; 10465 } 10466 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10467 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10468 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10469 } 10470 } 10471 } 10472 PetscCall(ISRestoreIndices(spIS, &spmap)); 10473 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10474 if (bs > 1) { 10475 /* We need to check that the block size does not come from non-contiguous fields */ 10476 PetscInt i, j, set = 1; 10477 for (i = 0; i < subSize; i += bs) { 10478 for (j = 0; j < bs; ++j) { 10479 if (subIndices[i + j] != subIndices[i] + j) { 10480 set = 0; 10481 break; 10482 } 10483 } 10484 } 10485 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10486 } 10487 /* Attach nullspace */ 10488 for (f = 0; f < Nf; ++f) { 10489 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10490 if ((*subdm)->nullspaceConstructors[f]) break; 10491 } 10492 if (f < Nf) { 10493 MatNullSpace nullSpace; 10494 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10495 10496 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10497 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10498 } 10499 } 10500 PetscFunctionReturn(PETSC_SUCCESS); 10501 } 10502 10503 /*@ 10504 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10505 10506 Input Parameters: 10507 + dm - The `DM` 10508 - dummy - unused argument 10509 10510 Options Database Key: 10511 . -dm_plex_monitor_throughput - Activate the monitor 10512 10513 Level: developer 10514 10515 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10516 @*/ 10517 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10518 { 10519 PetscLogHandler default_handler; 10520 10521 PetscFunctionBegin; 10522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10523 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10524 if (default_handler) { 10525 PetscLogEvent event; 10526 PetscEventPerfInfo eventInfo; 10527 PetscReal cellRate, flopRate; 10528 PetscInt cStart, cEnd, Nf, N; 10529 const char *name; 10530 10531 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10532 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10533 PetscCall(DMGetNumFields(dm, &Nf)); 10534 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10535 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10536 N = (cEnd - cStart) * Nf * eventInfo.count; 10537 flopRate = eventInfo.flops / eventInfo.time; 10538 cellRate = N / eventInfo.time; 10539 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DM (%s) FE Residual Integration: %" PetscInt_FMT " integrals %d reps\n Cell rate: %.2g/s flop rate: %.2g MF/s\n", name ? name : "unknown", N, eventInfo.count, (double)cellRate, (double)(flopRate / 1.e6))); 10540 } else { 10541 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."); 10542 } 10543 PetscFunctionReturn(PETSC_SUCCESS); 10544 } 10545