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 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The `DMPLEX` object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Level: intermediate 28 29 Note: 30 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 31 If the mesh has no cells, this returns `PETSC_FALSE`. 32 33 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 34 @*/ 35 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 36 { 37 DMPolytopeType ct; 38 PetscInt cStart, cEnd; 39 40 PetscFunctionBegin; 41 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 42 if (cEnd <= cStart) { 43 *simplex = PETSC_FALSE; 44 PetscFunctionReturn(PETSC_SUCCESS); 45 } 46 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 47 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 48 PetscFunctionReturn(PETSC_SUCCESS); 49 } 50 51 /*@ 52 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 53 54 Input Parameters: 55 + dm - The `DMPLEX` object 56 - height - The cell height in the Plex, 0 is the default 57 58 Output Parameters: 59 + cStart - The first "normal" cell 60 - cEnd - The upper bound on "normal"" cells 61 62 Level: developer 63 64 Note: 65 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 66 67 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetCellTypeStratum()` 68 @*/ 69 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 70 { 71 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 72 PetscInt cS, cE, c; 73 74 PetscFunctionBegin; 75 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 76 for (c = cS; c < cE; ++c) { 77 DMPolytopeType cct; 78 79 PetscCall(DMPlexGetCellType(dm, c, &cct)); 80 if ((PetscInt)cct < 0) break; 81 switch (cct) { 82 case DM_POLYTOPE_POINT: 83 case DM_POLYTOPE_SEGMENT: 84 case DM_POLYTOPE_TRIANGLE: 85 case DM_POLYTOPE_QUADRILATERAL: 86 case DM_POLYTOPE_TETRAHEDRON: 87 case DM_POLYTOPE_HEXAHEDRON: 88 ct = cct; 89 break; 90 default: 91 break; 92 } 93 if (ct != DM_POLYTOPE_UNKNOWN) break; 94 } 95 if (ct != DM_POLYTOPE_UNKNOWN) { 96 DMLabel ctLabel; 97 98 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 99 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 100 // Reset label for fast lookup 101 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 102 } 103 if (cStart) *cStart = cS; 104 if (cEnd) *cEnd = cE; 105 PetscFunctionReturn(PETSC_SUCCESS); 106 } 107 108 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 109 { 110 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 111 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 112 113 PetscFunctionBegin; 114 *ft = PETSC_VTK_INVALID; 115 PetscCall(DMGetCoordinateDim(dm, &cdim)); 116 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 117 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 118 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 119 if (field >= 0) { 120 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 121 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 122 } else { 123 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 124 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 125 } 126 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 127 if (globalvcdof[0]) { 128 *sStart = vStart; 129 *sEnd = vEnd; 130 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 131 else *ft = PETSC_VTK_POINT_FIELD; 132 } else if (globalvcdof[1]) { 133 *sStart = cStart; 134 *sEnd = cEnd; 135 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 136 else *ft = PETSC_VTK_CELL_FIELD; 137 } else { 138 if (field >= 0) { 139 const char *fieldname; 140 141 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 143 } else { 144 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 145 } 146 } 147 PetscFunctionReturn(PETSC_SUCCESS); 148 } 149 150 /*@ 151 DMPlexVecView1D - Plot many 1D solutions on the same line graph 152 153 Collective 154 155 Input Parameters: 156 + dm - The `DMPLEX` object 157 . n - The number of vectors 158 . u - The array of local vectors 159 - viewer - The `PetscViewer` 160 161 Level: advanced 162 163 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 164 @*/ 165 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 166 { 167 PetscDS ds; 168 PetscDraw draw = NULL; 169 PetscDrawLG lg; 170 Vec coordinates; 171 const PetscScalar *coords, **sol; 172 PetscReal *vals; 173 PetscInt *Nc; 174 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 175 char **names; 176 177 PetscFunctionBegin; 178 PetscCall(DMGetDS(dm, &ds)); 179 PetscCall(PetscDSGetNumFields(ds, &Nf)); 180 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 181 PetscCall(PetscDSGetComponents(ds, &Nc)); 182 183 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 184 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 185 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 186 187 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 188 for (i = 0, l = 0; i < n; ++i) { 189 const char *vname; 190 191 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 192 for (f = 0; f < Nf; ++f) { 193 PetscObject disc; 194 const char *fname; 195 char tmpname[PETSC_MAX_PATH_LEN]; 196 197 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 198 /* TODO Create names for components */ 199 for (c = 0; c < Nc[f]; ++c, ++l) { 200 PetscCall(PetscObjectGetName(disc, &fname)); 201 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 202 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 203 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 204 PetscCall(PetscStrallocpy(tmpname, &names[l])); 205 } 206 } 207 } 208 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 209 /* Just add P_1 support for now */ 210 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 211 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 212 PetscCall(VecGetArrayRead(coordinates, &coords)); 213 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 214 for (v = vStart; v < vEnd; ++v) { 215 PetscScalar *x, *svals; 216 217 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 218 for (i = 0; i < n; ++i) { 219 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 220 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 221 } 222 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 223 } 224 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 225 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 226 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 227 PetscCall(PetscFree3(sol, names, vals)); 228 229 PetscCall(PetscDrawLGDraw(lg)); 230 PetscCall(PetscDrawLGDestroy(&lg)); 231 PetscFunctionReturn(PETSC_SUCCESS); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 235 { 236 DM dm; 237 238 PetscFunctionBegin; 239 PetscCall(VecGetDM(u, &dm)); 240 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 241 PetscFunctionReturn(PETSC_SUCCESS); 242 } 243 244 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 245 { 246 DM dm; 247 PetscSection s; 248 PetscDraw draw, popup; 249 DM cdm; 250 PetscSection coordSection; 251 Vec coordinates; 252 const PetscScalar *array; 253 PetscReal lbound[3], ubound[3]; 254 PetscReal vbound[2], time; 255 PetscBool flg; 256 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 257 const char *name; 258 char title[PETSC_MAX_PATH_LEN]; 259 260 PetscFunctionBegin; 261 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 262 PetscCall(VecGetDM(v, &dm)); 263 PetscCall(DMGetCoordinateDim(dm, &dim)); 264 PetscCall(DMGetLocalSection(dm, &s)); 265 PetscCall(PetscSectionGetNumFields(s, &Nf)); 266 PetscCall(DMGetCoarsenLevel(dm, &level)); 267 PetscCall(DMGetCoordinateDM(dm, &cdm)); 268 PetscCall(DMGetLocalSection(cdm, &coordSection)); 269 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 270 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 271 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 272 273 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 274 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 275 276 PetscCall(VecGetLocalSize(coordinates, &N)); 277 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 278 PetscCall(PetscDrawClear(draw)); 279 280 /* Could implement something like DMDASelectFields() */ 281 for (f = 0; f < Nf; ++f) { 282 DM fdm = dm; 283 Vec fv = v; 284 IS fis; 285 char prefix[PETSC_MAX_PATH_LEN]; 286 const char *fname; 287 288 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 289 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 290 291 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 292 else prefix[0] = '\0'; 293 if (Nf > 1) { 294 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 295 PetscCall(VecGetSubVector(v, fis, &fv)); 296 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 297 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 298 } 299 for (comp = 0; comp < Nc; ++comp, ++w) { 300 PetscInt nmax = 2; 301 302 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 303 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 304 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 305 PetscCall(PetscDrawSetTitle(draw, title)); 306 307 /* TODO Get max and min only for this component */ 308 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 309 if (!flg) { 310 PetscCall(VecMin(fv, NULL, &vbound[0])); 311 PetscCall(VecMax(fv, NULL, &vbound[1])); 312 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 313 } 314 315 PetscCall(PetscDrawGetPopup(draw, &popup)); 316 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 317 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 318 PetscCall(VecGetArrayRead(fv, &array)); 319 for (c = cStart; c < cEnd; ++c) { 320 PetscScalar *coords = NULL, *a = NULL; 321 const PetscScalar *coords_arr; 322 PetscBool isDG; 323 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 324 325 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 326 if (a) { 327 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 328 color[1] = color[2] = color[3] = color[0]; 329 } else { 330 PetscScalar *vals = NULL; 331 PetscInt numVals, va; 332 333 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 334 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); 335 switch (numVals / Nc) { 336 case 3: /* P1 Triangle */ 337 case 4: /* P1 Quadrangle */ 338 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 339 break; 340 case 6: /* P2 Triangle */ 341 case 8: /* P2 Quadrangle */ 342 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 343 break; 344 default: 345 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 346 } 347 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 348 } 349 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 350 switch (numCoords) { 351 case 6: 352 case 12: /* Localized triangle */ 353 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])); 354 break; 355 case 8: 356 case 16: /* Localized quadrilateral */ 357 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])); 358 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])); 359 break; 360 default: 361 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 362 } 363 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 364 } 365 PetscCall(VecRestoreArrayRead(fv, &array)); 366 PetscCall(PetscDrawFlush(draw)); 367 PetscCall(PetscDrawPause(draw)); 368 PetscCall(PetscDrawSave(draw)); 369 } 370 if (Nf > 1) { 371 PetscCall(VecRestoreSubVector(v, fis, &fv)); 372 PetscCall(ISDestroy(&fis)); 373 PetscCall(DMDestroy(&fdm)); 374 } 375 } 376 PetscFunctionReturn(PETSC_SUCCESS); 377 } 378 379 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 380 { 381 DM dm; 382 PetscDraw draw; 383 PetscInt dim; 384 PetscBool isnull; 385 386 PetscFunctionBegin; 387 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 388 PetscCall(PetscDrawIsNull(draw, &isnull)); 389 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 390 391 PetscCall(VecGetDM(v, &dm)); 392 PetscCall(DMGetCoordinateDim(dm, &dim)); 393 switch (dim) { 394 case 1: 395 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 396 break; 397 case 2: 398 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 399 break; 400 default: 401 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 402 } 403 PetscFunctionReturn(PETSC_SUCCESS); 404 } 405 406 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 407 { 408 DM dm; 409 Vec locv; 410 const char *name; 411 PetscSection section; 412 PetscInt pStart, pEnd; 413 PetscInt numFields; 414 PetscViewerVTKFieldType ft; 415 416 PetscFunctionBegin; 417 PetscCall(VecGetDM(v, &dm)); 418 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 419 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 420 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 421 PetscCall(VecCopy(v, locv)); 422 PetscCall(DMGetLocalSection(dm, §ion)); 423 PetscCall(PetscSectionGetNumFields(section, &numFields)); 424 if (!numFields) { 425 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 426 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 427 } else { 428 PetscInt f; 429 430 for (f = 0; f < numFields; f++) { 431 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 432 if (ft == PETSC_VTK_INVALID) continue; 433 PetscCall(PetscObjectReference((PetscObject)locv)); 434 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 435 } 436 PetscCall(VecDestroy(&locv)); 437 } 438 PetscFunctionReturn(PETSC_SUCCESS); 439 } 440 441 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 442 { 443 DM dm; 444 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 445 446 PetscFunctionBegin; 447 PetscCall(VecGetDM(v, &dm)); 448 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 449 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 450 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 451 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 453 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 454 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 455 PetscInt i, numFields; 456 PetscObject fe; 457 PetscBool fem = PETSC_FALSE; 458 Vec locv = v; 459 const char *name; 460 PetscInt step; 461 PetscReal time; 462 463 PetscCall(DMGetNumFields(dm, &numFields)); 464 for (i = 0; i < numFields; i++) { 465 PetscCall(DMGetField(dm, i, NULL, &fe)); 466 if (fe->classid == PETSCFE_CLASSID) { 467 fem = PETSC_TRUE; 468 break; 469 } 470 } 471 if (fem) { 472 PetscObject isZero; 473 474 PetscCall(DMGetLocalVector(dm, &locv)); 475 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 476 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 477 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 478 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 479 PetscCall(VecCopy(v, locv)); 480 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 481 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 482 } 483 if (isvtk) { 484 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 485 } else if (ishdf5) { 486 #if defined(PETSC_HAVE_HDF5) 487 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 488 #else 489 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 490 #endif 491 } else if (isdraw) { 492 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 493 } else if (isglvis) { 494 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 495 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 496 PetscCall(VecView_GLVis(locv, viewer)); 497 } else if (iscgns) { 498 #if defined(PETSC_HAVE_CGNS) 499 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 500 #else 501 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 502 #endif 503 } 504 if (fem) { 505 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 506 PetscCall(DMRestoreLocalVector(dm, &locv)); 507 } 508 } else { 509 PetscBool isseq; 510 511 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 512 if (isseq) PetscCall(VecView_Seq(v, viewer)); 513 else PetscCall(VecView_MPI(v, viewer)); 514 } 515 PetscFunctionReturn(PETSC_SUCCESS); 516 } 517 518 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 519 { 520 DM dm; 521 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 526 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 527 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 528 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 529 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 530 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 532 if (isvtk || isdraw || isglvis || iscgns) { 533 Vec locv; 534 PetscObject isZero; 535 const char *name; 536 537 PetscCall(DMGetLocalVector(dm, &locv)); 538 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 539 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 540 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 541 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 542 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 543 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 544 PetscCall(VecView_Plex_Local(locv, viewer)); 545 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 546 PetscCall(DMRestoreLocalVector(dm, &locv)); 547 } else if (ishdf5) { 548 #if defined(PETSC_HAVE_HDF5) 549 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 550 #else 551 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 552 #endif 553 } else if (isexodusii) { 554 #if defined(PETSC_HAVE_EXODUSII) 555 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 556 #else 557 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 558 #endif 559 } else { 560 PetscBool isseq; 561 562 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 563 if (isseq) PetscCall(VecView_Seq(v, viewer)); 564 else PetscCall(VecView_MPI(v, viewer)); 565 } 566 PetscFunctionReturn(PETSC_SUCCESS); 567 } 568 569 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 570 { 571 DM dm; 572 MPI_Comm comm; 573 PetscViewerFormat format; 574 Vec v; 575 PetscBool isvtk, ishdf5; 576 577 PetscFunctionBegin; 578 PetscCall(VecGetDM(originalv, &dm)); 579 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 580 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 581 PetscCall(PetscViewerGetFormat(viewer, &format)); 582 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 583 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 584 if (format == PETSC_VIEWER_NATIVE) { 585 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 586 /* this need a better fix */ 587 if (dm->useNatural) { 588 if (dm->sfNatural) { 589 const char *vecname; 590 PetscInt n, nroots; 591 592 PetscCall(VecGetLocalSize(originalv, &n)); 593 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 594 if (n == nroots) { 595 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 596 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 597 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 598 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 599 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 600 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 601 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 602 } else v = originalv; 603 } else v = originalv; 604 605 if (ishdf5) { 606 #if defined(PETSC_HAVE_HDF5) 607 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 608 #else 609 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 610 #endif 611 } else if (isvtk) { 612 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 613 } else { 614 PetscBool isseq; 615 616 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 617 if (isseq) PetscCall(VecView_Seq(v, viewer)); 618 else PetscCall(VecView_MPI(v, viewer)); 619 } 620 if (v != originalv) PetscCall(VecDestroy(&v)); 621 PetscFunctionReturn(PETSC_SUCCESS); 622 } 623 624 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 625 { 626 DM dm; 627 PetscBool ishdf5; 628 629 PetscFunctionBegin; 630 PetscCall(VecGetDM(v, &dm)); 631 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 632 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 633 if (ishdf5) { 634 DM dmBC; 635 Vec gv; 636 const char *name; 637 638 PetscCall(DMGetOutputDM(dm, &dmBC)); 639 PetscCall(DMGetGlobalVector(dmBC, &gv)); 640 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 641 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 642 PetscCall(VecLoad_Default(gv, viewer)); 643 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 644 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 645 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 646 } else PetscCall(VecLoad_Default(v, viewer)); 647 PetscFunctionReturn(PETSC_SUCCESS); 648 } 649 650 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 651 { 652 DM dm; 653 PetscBool ishdf5, isexodusii; 654 655 PetscFunctionBegin; 656 PetscCall(VecGetDM(v, &dm)); 657 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 658 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 659 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 660 if (ishdf5) { 661 #if defined(PETSC_HAVE_HDF5) 662 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 665 #endif 666 } else if (isexodusii) { 667 #if defined(PETSC_HAVE_EXODUSII) 668 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 669 #else 670 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 671 #endif 672 } else PetscCall(VecLoad_Default(v, viewer)); 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 PetscViewerFormat format; 680 PetscBool ishdf5; 681 682 PetscFunctionBegin; 683 PetscCall(VecGetDM(originalv, &dm)); 684 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 685 PetscCall(PetscViewerGetFormat(viewer, &format)); 686 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 687 if (format == PETSC_VIEWER_NATIVE) { 688 if (dm->useNatural) { 689 if (dm->sfNatural) { 690 if (ishdf5) { 691 #if defined(PETSC_HAVE_HDF5) 692 Vec v; 693 const char *vecname; 694 695 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 696 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 697 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 698 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 699 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 700 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 701 PetscCall(VecDestroy(&v)); 702 #else 703 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 704 #endif 705 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 706 } 707 } else PetscCall(VecLoad_Default(originalv, viewer)); 708 } 709 PetscFunctionReturn(PETSC_SUCCESS); 710 } 711 712 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 713 { 714 PetscSection coordSection; 715 Vec coordinates; 716 DMLabel depthLabel, celltypeLabel; 717 const char *name[4]; 718 const PetscScalar *a; 719 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 720 721 PetscFunctionBegin; 722 PetscCall(DMGetDimension(dm, &dim)); 723 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 724 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 725 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 726 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 727 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 728 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 729 PetscCall(VecGetArrayRead(coordinates, &a)); 730 name[0] = "vertex"; 731 name[1] = "edge"; 732 name[dim - 1] = "face"; 733 name[dim] = "cell"; 734 for (c = cStart; c < cEnd; ++c) { 735 PetscInt *closure = NULL; 736 PetscInt closureSize, cl, ct; 737 738 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 739 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 740 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 741 PetscCall(PetscViewerASCIIPushTab(viewer)); 742 for (cl = 0; cl < closureSize * 2; cl += 2) { 743 PetscInt point = closure[cl], depth, dof, off, d, p; 744 745 if ((point < pStart) || (point >= pEnd)) continue; 746 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 747 if (!dof) continue; 748 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 749 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 750 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 751 for (p = 0; p < dof / dim; ++p) { 752 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 753 for (d = 0; d < dim; ++d) { 754 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 755 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 756 } 757 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 758 } 759 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 760 } 761 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 762 PetscCall(PetscViewerASCIIPopTab(viewer)); 763 } 764 PetscCall(VecRestoreArrayRead(coordinates, &a)); 765 PetscFunctionReturn(PETSC_SUCCESS); 766 } 767 768 typedef enum { 769 CS_CARTESIAN, 770 CS_POLAR, 771 CS_CYLINDRICAL, 772 CS_SPHERICAL 773 } CoordSystem; 774 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 775 776 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 777 { 778 PetscInt i; 779 780 PetscFunctionBegin; 781 if (dim > 3) { 782 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 783 } else { 784 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 785 786 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 787 switch (cs) { 788 case CS_CARTESIAN: 789 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 790 break; 791 case CS_POLAR: 792 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 793 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 794 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 795 break; 796 case CS_CYLINDRICAL: 797 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 798 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 799 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 800 trcoords[2] = coords[2]; 801 break; 802 case CS_SPHERICAL: 803 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 804 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 805 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 806 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 807 break; 808 } 809 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 810 } 811 PetscFunctionReturn(PETSC_SUCCESS); 812 } 813 814 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 815 { 816 DM_Plex *mesh = (DM_Plex *)dm->data; 817 DM cdm, cdmCell; 818 PetscSection coordSection, coordSectionCell; 819 Vec coordinates, coordinatesCell; 820 PetscViewerFormat format; 821 822 PetscFunctionBegin; 823 PetscCall(PetscViewerGetFormat(viewer, &format)); 824 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 825 const char *name; 826 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 827 PetscInt pStart, pEnd, p, numLabels, l; 828 PetscMPIInt rank, size; 829 830 PetscCall(DMGetCoordinateDM(dm, &cdm)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 833 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 834 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 835 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 836 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 837 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 838 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 839 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 840 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 841 PetscCall(DMGetDimension(dm, &dim)); 842 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 843 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 844 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 845 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 847 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 848 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 849 for (p = pStart; p < pEnd; ++p) { 850 PetscInt dof, off, s; 851 852 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 853 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 854 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 855 } 856 PetscCall(PetscViewerFlush(viewer)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 858 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 859 for (p = pStart; p < pEnd; ++p) { 860 PetscInt dof, off, c; 861 862 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 863 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 864 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])); 865 } 866 PetscCall(PetscViewerFlush(viewer)); 867 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 868 if (coordSection && coordinates) { 869 CoordSystem cs = CS_CARTESIAN; 870 const PetscScalar *array, *arrayCell = NULL; 871 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 872 PetscMPIInt rank; 873 const char *name; 874 875 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 876 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 877 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 878 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 879 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 880 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 881 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 882 pStart = PetscMin(pvStart, pcStart); 883 pEnd = PetscMax(pvEnd, pcEnd); 884 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 885 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 886 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 887 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 888 889 PetscCall(VecGetArrayRead(coordinates, &array)); 890 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 891 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 892 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 893 for (p = pStart; p < pEnd; ++p) { 894 PetscInt dof, off; 895 896 if (p >= pvStart && p < pvEnd) { 897 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 898 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 899 if (dof) { 900 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 901 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 902 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 903 } 904 } 905 if (cdmCell && p >= pcStart && p < pcEnd) { 906 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 907 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 908 if (dof) { 909 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 910 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 911 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 912 } 913 } 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 917 PetscCall(VecRestoreArrayRead(coordinates, &array)); 918 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 919 } 920 PetscCall(DMGetNumLabels(dm, &numLabels)); 921 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 922 for (l = 0; l < numLabels; ++l) { 923 DMLabel label; 924 PetscBool isdepth; 925 const char *name; 926 927 PetscCall(DMGetLabelName(dm, l, &name)); 928 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 929 if (isdepth) continue; 930 PetscCall(DMGetLabel(dm, name, &label)); 931 PetscCall(DMLabelView(label, viewer)); 932 } 933 if (size > 1) { 934 PetscSF sf; 935 936 PetscCall(DMGetPointSF(dm, &sf)); 937 PetscCall(PetscSFView(sf, viewer)); 938 } 939 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 940 PetscCall(PetscViewerFlush(viewer)); 941 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 942 const char *name, *color; 943 const char *defcolors[3] = {"gray", "orange", "green"}; 944 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 945 char lname[PETSC_MAX_PATH_LEN]; 946 PetscReal scale = 2.0; 947 PetscReal tikzscale = 1.0; 948 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 949 double tcoords[3]; 950 PetscScalar *coords; 951 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 952 PetscMPIInt rank, size; 953 char **names, **colors, **lcolors; 954 PetscBool flg, lflg; 955 PetscBT wp = NULL; 956 PetscInt pEnd, pStart; 957 958 PetscCall(DMGetCoordinateDM(dm, &cdm)); 959 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 960 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 961 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 962 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 963 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 964 PetscCall(DMGetDimension(dm, &dim)); 965 PetscCall(DMPlexGetDepth(dm, &depth)); 966 PetscCall(DMGetNumLabels(dm, &numLabels)); 967 numLabels = PetscMax(numLabels, 10); 968 numColors = 10; 969 numLColors = 10; 970 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 971 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 972 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 973 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 974 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 975 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 976 n = 4; 977 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 978 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 979 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 980 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 981 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 982 if (!useLabels) numLabels = 0; 983 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 984 if (!useColors) { 985 numColors = 3; 986 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 987 } 988 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 989 if (!useColors) { 990 numLColors = 4; 991 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 992 } 993 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 994 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 995 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 996 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 997 if (depth < dim) plotEdges = PETSC_FALSE; 998 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 999 1000 /* filter points with labelvalue != labeldefaultvalue */ 1001 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1002 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1003 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1004 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1005 if (lflg) { 1006 DMLabel lbl; 1007 1008 PetscCall(DMGetLabel(dm, lname, &lbl)); 1009 if (lbl) { 1010 PetscInt val, defval; 1011 1012 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1013 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1014 for (c = pStart; c < pEnd; c++) { 1015 PetscInt *closure = NULL; 1016 PetscInt closureSize; 1017 1018 PetscCall(DMLabelGetValue(lbl, c, &val)); 1019 if (val == defval) continue; 1020 1021 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1022 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1023 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1024 } 1025 } 1026 } 1027 1028 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1029 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1030 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1031 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1032 \\documentclass[tikz]{standalone}\n\n\ 1033 \\usepackage{pgflibraryshapes}\n\ 1034 \\usetikzlibrary{backgrounds}\n\ 1035 \\usetikzlibrary{arrows}\n\ 1036 \\begin{document}\n")); 1037 if (size > 1) { 1038 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1039 for (p = 0; p < size; ++p) { 1040 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1041 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1042 } 1043 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1044 } 1045 if (drawHasse) { 1046 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1047 1048 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1049 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1050 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1058 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1060 } 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1062 1063 /* Plot vertices */ 1064 PetscCall(VecGetArray(coordinates, &coords)); 1065 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1066 for (v = vStart; v < vEnd; ++v) { 1067 PetscInt off, dof, d; 1068 PetscBool isLabeled = PETSC_FALSE; 1069 1070 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1071 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1072 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1073 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1074 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1075 for (d = 0; d < dof; ++d) { 1076 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1077 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1078 } 1079 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1080 if (dim == 3) { 1081 PetscReal tmp = tcoords[1]; 1082 tcoords[1] = tcoords[2]; 1083 tcoords[2] = -tmp; 1084 } 1085 for (d = 0; d < dof; ++d) { 1086 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1088 } 1089 if (drawHasse) color = colors[0 % numColors]; 1090 else color = colors[rank % numColors]; 1091 for (l = 0; l < numLabels; ++l) { 1092 PetscInt val; 1093 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1094 if (val >= 0) { 1095 color = lcolors[l % numLColors]; 1096 isLabeled = PETSC_TRUE; 1097 break; 1098 } 1099 } 1100 if (drawNumbers[0]) { 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1102 } else if (drawColors[0]) { 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1104 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1105 } 1106 PetscCall(VecRestoreArray(coordinates, &coords)); 1107 PetscCall(PetscViewerFlush(viewer)); 1108 /* Plot edges */ 1109 if (plotEdges) { 1110 PetscCall(VecGetArray(coordinates, &coords)); 1111 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1112 for (e = eStart; e < eEnd; ++e) { 1113 const PetscInt *cone; 1114 PetscInt coneSize, offA, offB, dof, d; 1115 1116 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1117 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1118 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1119 PetscCall(DMPlexGetCone(dm, e, &cone)); 1120 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1121 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1122 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1123 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1124 for (d = 0; d < dof; ++d) { 1125 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1126 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1127 } 1128 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1129 if (dim == 3) { 1130 PetscReal tmp = tcoords[1]; 1131 tcoords[1] = tcoords[2]; 1132 tcoords[2] = -tmp; 1133 } 1134 for (d = 0; d < dof; ++d) { 1135 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1136 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1137 } 1138 if (drawHasse) color = colors[1 % numColors]; 1139 else color = colors[rank % numColors]; 1140 for (l = 0; l < numLabels; ++l) { 1141 PetscInt val; 1142 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1143 if (val >= 0) { 1144 color = lcolors[l % numLColors]; 1145 break; 1146 } 1147 } 1148 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1149 } 1150 PetscCall(VecRestoreArray(coordinates, &coords)); 1151 PetscCall(PetscViewerFlush(viewer)); 1152 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1153 } 1154 /* Plot cells */ 1155 if (dim == 3 || !drawNumbers[1]) { 1156 for (e = eStart; e < eEnd; ++e) { 1157 const PetscInt *cone; 1158 1159 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1160 color = colors[rank % numColors]; 1161 for (l = 0; l < numLabels; ++l) { 1162 PetscInt val; 1163 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1164 if (val >= 0) { 1165 color = lcolors[l % numLColors]; 1166 break; 1167 } 1168 } 1169 PetscCall(DMPlexGetCone(dm, e, &cone)); 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1171 } 1172 } else { 1173 DMPolytopeType ct; 1174 1175 /* Drawing a 2D polygon */ 1176 for (c = cStart; c < cEnd; ++c) { 1177 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1178 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1179 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1180 const PetscInt *cone; 1181 PetscInt coneSize, e; 1182 1183 PetscCall(DMPlexGetCone(dm, c, &cone)); 1184 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1185 for (e = 0; e < coneSize; ++e) { 1186 const PetscInt *econe; 1187 1188 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1189 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)); 1190 } 1191 } else { 1192 PetscInt *closure = NULL; 1193 PetscInt closureSize, Nv = 0, v; 1194 1195 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1196 for (p = 0; p < closureSize * 2; p += 2) { 1197 const PetscInt point = closure[p]; 1198 1199 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1200 } 1201 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1202 for (v = 0; v <= Nv; ++v) { 1203 const PetscInt vertex = closure[v % Nv]; 1204 1205 if (v > 0) { 1206 if (plotEdges) { 1207 const PetscInt *edge; 1208 PetscInt endpoints[2], ne; 1209 1210 endpoints[0] = closure[v - 1]; 1211 endpoints[1] = vertex; 1212 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1213 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1214 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1215 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1216 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1217 } 1218 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1219 } 1220 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1221 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1222 } 1223 } 1224 } 1225 for (c = cStart; c < cEnd; ++c) { 1226 double ccoords[3] = {0.0, 0.0, 0.0}; 1227 PetscBool isLabeled = PETSC_FALSE; 1228 PetscScalar *cellCoords = NULL; 1229 const PetscScalar *array; 1230 PetscInt numCoords, cdim, d; 1231 PetscBool isDG; 1232 1233 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1234 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1235 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1236 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1237 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1238 for (p = 0; p < numCoords / cdim; ++p) { 1239 for (d = 0; d < cdim; ++d) { 1240 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1241 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1242 } 1243 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1244 if (cdim == 3) { 1245 PetscReal tmp = tcoords[1]; 1246 tcoords[1] = tcoords[2]; 1247 tcoords[2] = -tmp; 1248 } 1249 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1250 } 1251 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1252 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1253 for (d = 0; d < cdim; ++d) { 1254 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1255 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1256 } 1257 if (drawHasse) color = colors[depth % numColors]; 1258 else color = colors[rank % numColors]; 1259 for (l = 0; l < numLabels; ++l) { 1260 PetscInt val; 1261 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1262 if (val >= 0) { 1263 color = lcolors[l % numLColors]; 1264 isLabeled = PETSC_TRUE; 1265 break; 1266 } 1267 } 1268 if (drawNumbers[dim]) { 1269 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1270 } else if (drawColors[dim]) { 1271 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1272 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1273 } 1274 if (drawHasse) { 1275 color = colors[depth % numColors]; 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1278 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1279 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1280 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1281 1282 color = colors[1 % numColors]; 1283 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1284 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1286 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1287 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1288 1289 color = colors[0 % numColors]; 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1291 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1293 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1294 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1295 1296 for (p = pStart; p < pEnd; ++p) { 1297 const PetscInt *cone; 1298 PetscInt coneSize, cp; 1299 1300 PetscCall(DMPlexGetCone(dm, p, &cone)); 1301 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1302 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1303 } 1304 } 1305 PetscCall(PetscViewerFlush(viewer)); 1306 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1307 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1308 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1309 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1310 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1311 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1312 PetscCall(PetscFree3(names, colors, lcolors)); 1313 PetscCall(PetscBTDestroy(&wp)); 1314 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1315 Vec cown, acown; 1316 VecScatter sct; 1317 ISLocalToGlobalMapping g2l; 1318 IS gid, acis; 1319 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1320 MPI_Group ggroup, ngroup; 1321 PetscScalar *array, nid; 1322 const PetscInt *idxs; 1323 PetscInt *idxs2, *start, *adjacency, *work; 1324 PetscInt64 lm[3], gm[3]; 1325 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1326 PetscMPIInt d1, d2, rank; 1327 1328 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1329 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1330 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1331 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1332 #endif 1333 if (ncomm != MPI_COMM_NULL) { 1334 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1335 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1336 d1 = 0; 1337 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1338 nid = d2; 1339 PetscCallMPI(MPI_Group_free(&ggroup)); 1340 PetscCallMPI(MPI_Group_free(&ngroup)); 1341 PetscCallMPI(MPI_Comm_free(&ncomm)); 1342 } else nid = 0.0; 1343 1344 /* Get connectivity */ 1345 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1346 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1347 1348 /* filter overlapped local cells */ 1349 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1350 PetscCall(ISGetIndices(gid, &idxs)); 1351 PetscCall(ISGetLocalSize(gid, &cum)); 1352 PetscCall(PetscMalloc1(cum, &idxs2)); 1353 for (c = cStart, cum = 0; c < cEnd; c++) { 1354 if (idxs[c - cStart] < 0) continue; 1355 idxs2[cum++] = idxs[c - cStart]; 1356 } 1357 PetscCall(ISRestoreIndices(gid, &idxs)); 1358 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1359 PetscCall(ISDestroy(&gid)); 1360 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1361 1362 /* support for node-aware cell locality */ 1363 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1364 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1365 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1366 PetscCall(VecGetArray(cown, &array)); 1367 for (c = 0; c < numVertices; c++) array[c] = nid; 1368 PetscCall(VecRestoreArray(cown, &array)); 1369 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1370 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1371 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1372 PetscCall(ISDestroy(&acis)); 1373 PetscCall(VecScatterDestroy(&sct)); 1374 PetscCall(VecDestroy(&cown)); 1375 1376 /* compute edgeCut */ 1377 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1378 PetscCall(PetscMalloc1(cum, &work)); 1379 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1380 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1381 PetscCall(ISDestroy(&gid)); 1382 PetscCall(VecGetArray(acown, &array)); 1383 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1384 PetscInt totl; 1385 1386 totl = start[c + 1] - start[c]; 1387 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1388 for (i = 0; i < totl; i++) { 1389 if (work[i] < 0) { 1390 ect += 1; 1391 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1392 } 1393 } 1394 } 1395 PetscCall(PetscFree(work)); 1396 PetscCall(VecRestoreArray(acown, &array)); 1397 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1398 lm[1] = -numVertices; 1399 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1401 lm[0] = ect; /* edgeCut */ 1402 lm[1] = ectn; /* node-aware edgeCut */ 1403 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1404 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1406 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1407 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1408 #else 1409 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1410 #endif 1411 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1412 PetscCall(PetscFree(start)); 1413 PetscCall(PetscFree(adjacency)); 1414 PetscCall(VecDestroy(&acown)); 1415 } else { 1416 const char *name; 1417 PetscInt *sizes, *hybsizes, *ghostsizes; 1418 PetscInt locDepth, depth, cellHeight, dim, d; 1419 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1420 PetscInt numLabels, l, maxSize = 17; 1421 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1422 MPI_Comm comm; 1423 PetscMPIInt size, rank; 1424 1425 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1426 PetscCallMPI(MPI_Comm_size(comm, &size)); 1427 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1428 PetscCall(DMGetDimension(dm, &dim)); 1429 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1430 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1431 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1432 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1433 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1434 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1435 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1436 PetscCall(DMPlexGetCellTypeStratum(dm, DM_POLYTOPE_FV_GHOST, &gcStart, &gcEnd)); 1437 gcNum = gcEnd - gcStart; 1438 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1439 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1440 for (d = 0; d <= depth; d++) { 1441 PetscInt Nc[2] = {0, 0}, ict; 1442 1443 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1444 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1445 ict = ct0; 1446 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1447 ct0 = (DMPolytopeType)ict; 1448 for (p = pStart; p < pEnd; ++p) { 1449 DMPolytopeType ct; 1450 1451 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1452 if (ct == ct0) ++Nc[0]; 1453 else ++Nc[1]; 1454 } 1455 if (size < maxSize) { 1456 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1457 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1458 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1459 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1460 for (p = 0; p < size; ++p) { 1461 if (rank == 0) { 1462 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1463 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1464 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1465 } 1466 } 1467 } else { 1468 PetscInt locMinMax[2]; 1469 1470 locMinMax[0] = Nc[0] + Nc[1]; 1471 locMinMax[1] = Nc[0] + Nc[1]; 1472 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1473 locMinMax[0] = Nc[1]; 1474 locMinMax[1] = Nc[1]; 1475 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1476 if (d == depth) { 1477 locMinMax[0] = gcNum; 1478 locMinMax[1] = gcNum; 1479 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1480 } 1481 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1483 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1484 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1485 } 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1487 } 1488 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1489 { 1490 const PetscReal *maxCell; 1491 const PetscReal *L; 1492 PetscBool localized; 1493 1494 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1495 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1496 if (L || localized) { 1497 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1498 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1499 if (L) { 1500 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1501 for (d = 0; d < dim; ++d) { 1502 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1504 } 1505 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1506 } 1507 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1508 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1509 } 1510 } 1511 PetscCall(DMGetNumLabels(dm, &numLabels)); 1512 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1513 for (l = 0; l < numLabels; ++l) { 1514 DMLabel label; 1515 const char *name; 1516 IS valueIS; 1517 const PetscInt *values; 1518 PetscInt numValues, v; 1519 1520 PetscCall(DMGetLabelName(dm, l, &name)); 1521 PetscCall(DMGetLabel(dm, name, &label)); 1522 PetscCall(DMLabelGetNumValues(label, &numValues)); 1523 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1524 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1525 PetscCall(ISGetIndices(valueIS, &values)); 1526 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1527 for (v = 0; v < numValues; ++v) { 1528 PetscInt size; 1529 1530 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1531 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1532 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1533 } 1534 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1535 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1536 PetscCall(ISRestoreIndices(valueIS, &values)); 1537 PetscCall(ISDestroy(&valueIS)); 1538 } 1539 { 1540 char **labelNames; 1541 PetscInt Nl = numLabels; 1542 PetscBool flg; 1543 1544 PetscCall(PetscMalloc1(Nl, &labelNames)); 1545 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1546 for (l = 0; l < Nl; ++l) { 1547 DMLabel label; 1548 1549 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1550 if (flg) { 1551 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1552 PetscCall(DMLabelView(label, viewer)); 1553 } 1554 PetscCall(PetscFree(labelNames[l])); 1555 } 1556 PetscCall(PetscFree(labelNames)); 1557 } 1558 /* If no fields are specified, people do not want to see adjacency */ 1559 if (dm->Nf) { 1560 PetscInt f; 1561 1562 for (f = 0; f < dm->Nf; ++f) { 1563 const char *name; 1564 1565 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1566 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1567 PetscCall(PetscViewerASCIIPushTab(viewer)); 1568 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1569 if (dm->fields[f].adjacency[0]) { 1570 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1571 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1572 } else { 1573 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1574 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1575 } 1576 PetscCall(PetscViewerASCIIPopTab(viewer)); 1577 } 1578 } 1579 PetscCall(DMGetCoarseDM(dm, &cdm)); 1580 if (cdm) { 1581 PetscCall(PetscViewerASCIIPushTab(viewer)); 1582 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1583 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1584 PetscCall(PetscViewerASCIIPopTab(viewer)); 1585 } 1586 } 1587 PetscFunctionReturn(PETSC_SUCCESS); 1588 } 1589 1590 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1591 { 1592 DMPolytopeType ct; 1593 PetscMPIInt rank; 1594 PetscInt cdim; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1600 switch (ct) { 1601 case DM_POLYTOPE_SEGMENT: 1602 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1603 switch (cdim) { 1604 case 1: { 1605 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1606 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1607 1608 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1609 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1610 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1611 } break; 1612 case 2: { 1613 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1614 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1615 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1616 1617 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1618 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)); 1619 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)); 1620 } break; 1621 default: 1622 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1623 } 1624 break; 1625 case DM_POLYTOPE_TRIANGLE: 1626 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)); 1627 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1628 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1629 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1630 break; 1631 case DM_POLYTOPE_QUADRILATERAL: 1632 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)); 1633 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)); 1634 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1635 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1636 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1637 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1638 break; 1639 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1640 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)); 1641 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)); 1642 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1643 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1644 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1645 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1646 break; 1647 case DM_POLYTOPE_FV_GHOST: 1648 break; 1649 default: 1650 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1651 } 1652 PetscFunctionReturn(PETSC_SUCCESS); 1653 } 1654 1655 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1656 { 1657 DMPolytopeType ct; 1658 PetscReal centroid[2] = {0., 0.}; 1659 PetscMPIInt rank; 1660 PetscInt fillColor, v, e, d; 1661 1662 PetscFunctionBegin; 1663 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1664 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1665 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1666 switch (ct) { 1667 case DM_POLYTOPE_TRIANGLE: { 1668 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1669 1670 for (v = 0; v < 3; ++v) { 1671 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1672 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1673 } 1674 for (e = 0; e < 3; ++e) { 1675 refCoords[0] = refVertices[e * 2 + 0]; 1676 refCoords[1] = refVertices[e * 2 + 1]; 1677 for (d = 1; d <= edgeDiv; ++d) { 1678 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1679 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1680 } 1681 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1682 for (d = 0; d < edgeDiv; ++d) { 1683 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)); 1684 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1685 } 1686 } 1687 } break; 1688 default: 1689 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1690 } 1691 PetscFunctionReturn(PETSC_SUCCESS); 1692 } 1693 1694 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1695 { 1696 PetscDraw draw; 1697 DM cdm; 1698 PetscSection coordSection; 1699 Vec coordinates; 1700 PetscReal xyl[3], xyr[3]; 1701 PetscReal *refCoords, *edgeCoords; 1702 PetscBool isnull, drawAffine = PETSC_TRUE; 1703 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1704 1705 PetscFunctionBegin; 1706 PetscCall(DMGetCoordinateDim(dm, &dim)); 1707 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1708 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1709 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1710 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1711 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1712 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1713 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1714 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1715 1716 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1717 PetscCall(PetscDrawIsNull(draw, &isnull)); 1718 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1719 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1720 1721 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1722 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1723 PetscCall(PetscDrawClear(draw)); 1724 1725 for (c = cStart; c < cEnd; ++c) { 1726 PetscScalar *coords = NULL; 1727 const PetscScalar *coords_arr; 1728 PetscInt numCoords; 1729 PetscBool isDG; 1730 1731 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1732 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1733 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1734 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1735 } 1736 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1737 PetscCall(PetscDrawFlush(draw)); 1738 PetscCall(PetscDrawPause(draw)); 1739 PetscCall(PetscDrawSave(draw)); 1740 PetscFunctionReturn(PETSC_SUCCESS); 1741 } 1742 1743 #if defined(PETSC_HAVE_EXODUSII) 1744 #include <exodusII.h> 1745 #include <petscviewerexodusii.h> 1746 #endif 1747 1748 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1749 { 1750 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1751 char name[PETSC_MAX_PATH_LEN]; 1752 1753 PetscFunctionBegin; 1754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1755 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1756 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1757 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1758 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1759 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1760 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1761 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1762 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1763 if (iascii) { 1764 PetscViewerFormat format; 1765 PetscCall(PetscViewerGetFormat(viewer, &format)); 1766 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1767 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1768 } else if (ishdf5) { 1769 #if defined(PETSC_HAVE_HDF5) 1770 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1771 #else 1772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1773 #endif 1774 } else if (isvtk) { 1775 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1776 } else if (isdraw) { 1777 PetscCall(DMPlexView_Draw(dm, viewer)); 1778 } else if (isglvis) { 1779 PetscCall(DMPlexView_GLVis(dm, viewer)); 1780 #if defined(PETSC_HAVE_EXODUSII) 1781 } else if (isexodus) { 1782 /* 1783 exodusII requires that all sets be part of exactly one cell set. 1784 If the dm does not have a "Cell Sets" label defined, we create one 1785 with ID 1, containing all cells. 1786 Note that if the Cell Sets label is defined but does not cover all cells, 1787 we may still have a problem. This should probably be checked here or in the viewer; 1788 */ 1789 PetscInt numCS; 1790 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1791 if (!numCS) { 1792 PetscInt cStart, cEnd, c; 1793 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1794 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1795 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1796 } 1797 PetscCall(DMView_PlexExodusII(dm, viewer)); 1798 #endif 1799 #if defined(PETSC_HAVE_CGNS) 1800 } else if (iscgns) { 1801 PetscCall(DMView_PlexCGNS(dm, viewer)); 1802 #endif 1803 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1804 /* Optionally view the partition */ 1805 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1806 if (flg) { 1807 Vec ranks; 1808 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1809 PetscCall(VecView(ranks, viewer)); 1810 PetscCall(VecDestroy(&ranks)); 1811 } 1812 /* Optionally view a label */ 1813 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1814 if (flg) { 1815 DMLabel label; 1816 Vec val; 1817 1818 PetscCall(DMGetLabel(dm, name, &label)); 1819 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1820 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1821 PetscCall(VecView(val, viewer)); 1822 PetscCall(VecDestroy(&val)); 1823 } 1824 PetscFunctionReturn(PETSC_SUCCESS); 1825 } 1826 1827 /*@ 1828 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1829 1830 Collective 1831 1832 Input Parameters: 1833 + dm - The `DM` whose topology is to be saved 1834 - viewer - The `PetscViewer` to save it in 1835 1836 Level: advanced 1837 1838 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1839 @*/ 1840 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1841 { 1842 PetscBool ishdf5; 1843 1844 PetscFunctionBegin; 1845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1846 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1848 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1849 if (ishdf5) { 1850 #if defined(PETSC_HAVE_HDF5) 1851 PetscViewerFormat format; 1852 PetscCall(PetscViewerGetFormat(viewer, &format)); 1853 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1854 IS globalPointNumbering; 1855 1856 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1857 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1858 PetscCall(ISDestroy(&globalPointNumbering)); 1859 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1860 #else 1861 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1862 #endif 1863 } 1864 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 /*@ 1869 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1870 1871 Collective 1872 1873 Input Parameters: 1874 + dm - The `DM` whose coordinates are to be saved 1875 - viewer - The `PetscViewer` for saving 1876 1877 Level: advanced 1878 1879 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1880 @*/ 1881 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1882 { 1883 PetscBool ishdf5; 1884 1885 PetscFunctionBegin; 1886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1887 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1888 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1889 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1890 if (ishdf5) { 1891 #if defined(PETSC_HAVE_HDF5) 1892 PetscViewerFormat format; 1893 PetscCall(PetscViewerGetFormat(viewer, &format)); 1894 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1895 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1896 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1897 #else 1898 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1899 #endif 1900 } 1901 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1902 PetscFunctionReturn(PETSC_SUCCESS); 1903 } 1904 1905 /*@ 1906 DMPlexLabelsView - Saves `DMPLEX` labels into a file 1907 1908 Collective 1909 1910 Input Parameters: 1911 + dm - The `DM` whose labels are to be saved 1912 - viewer - The `PetscViewer` for saving 1913 1914 Level: advanced 1915 1916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 1917 @*/ 1918 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1919 { 1920 PetscBool ishdf5; 1921 1922 PetscFunctionBegin; 1923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1924 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1925 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1926 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1927 if (ishdf5) { 1928 #if defined(PETSC_HAVE_HDF5) 1929 IS globalPointNumbering; 1930 PetscViewerFormat format; 1931 1932 PetscCall(PetscViewerGetFormat(viewer, &format)); 1933 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1934 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1935 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1936 PetscCall(ISDestroy(&globalPointNumbering)); 1937 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1938 #else 1939 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1940 #endif 1941 } 1942 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1943 PetscFunctionReturn(PETSC_SUCCESS); 1944 } 1945 1946 /*@ 1947 DMPlexSectionView - Saves a section associated with a `DMPLEX` 1948 1949 Collective 1950 1951 Input Parameters: 1952 + dm - The `DM` that contains the topology on which the section to be saved is defined 1953 . viewer - The `PetscViewer` for saving 1954 - sectiondm - The `DM` that contains the section to be saved 1955 1956 Level: advanced 1957 1958 Notes: 1959 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. 1960 1961 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. 1962 1963 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 1964 @*/ 1965 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1966 { 1967 PetscBool ishdf5; 1968 1969 PetscFunctionBegin; 1970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1971 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1972 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1973 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1974 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1975 if (ishdf5) { 1976 #if defined(PETSC_HAVE_HDF5) 1977 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1978 #else 1979 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1980 #endif 1981 } 1982 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1983 PetscFunctionReturn(PETSC_SUCCESS); 1984 } 1985 1986 /*@ 1987 DMPlexGlobalVectorView - Saves a global vector 1988 1989 Collective 1990 1991 Input Parameters: 1992 + dm - The `DM` that represents the topology 1993 . viewer - The `PetscViewer` to save data with 1994 . sectiondm - The `DM` that contains the global section on which vec is defined 1995 - vec - The global vector to be saved 1996 1997 Level: advanced 1998 1999 Notes: 2000 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. 2001 2002 Calling sequence: 2003 .vb 2004 DMCreate(PETSC_COMM_WORLD, &dm); 2005 DMSetType(dm, DMPLEX); 2006 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2007 DMClone(dm, §iondm); 2008 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2009 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2010 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2011 PetscSectionSetChart(section, pStart, pEnd); 2012 PetscSectionSetUp(section); 2013 DMSetLocalSection(sectiondm, section); 2014 PetscSectionDestroy(§ion); 2015 DMGetGlobalVector(sectiondm, &vec); 2016 PetscObjectSetName((PetscObject)vec, "vec_name"); 2017 DMPlexTopologyView(dm, viewer); 2018 DMPlexSectionView(dm, viewer, sectiondm); 2019 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2020 DMRestoreGlobalVector(sectiondm, &vec); 2021 DMDestroy(§iondm); 2022 DMDestroy(&dm); 2023 .ve 2024 2025 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2026 @*/ 2027 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2028 { 2029 PetscBool ishdf5; 2030 2031 PetscFunctionBegin; 2032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2033 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2034 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2035 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2036 /* Check consistency */ 2037 { 2038 PetscSection section; 2039 PetscBool includesConstraints; 2040 PetscInt m, m1; 2041 2042 PetscCall(VecGetLocalSize(vec, &m1)); 2043 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2044 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2045 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2046 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2047 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2048 } 2049 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2050 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2051 if (ishdf5) { 2052 #if defined(PETSC_HAVE_HDF5) 2053 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2054 #else 2055 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2056 #endif 2057 } 2058 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2059 PetscFunctionReturn(PETSC_SUCCESS); 2060 } 2061 2062 /*@ 2063 DMPlexLocalVectorView - Saves a local vector 2064 2065 Collective 2066 2067 Input Parameters: 2068 + dm - The `DM` that represents the topology 2069 . viewer - The `PetscViewer` to save data with 2070 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2071 - vec - The local vector to be saved 2072 2073 Level: advanced 2074 2075 Note: 2076 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. 2077 2078 Calling sequence: 2079 .vb 2080 DMCreate(PETSC_COMM_WORLD, &dm); 2081 DMSetType(dm, DMPLEX); 2082 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2083 DMClone(dm, §iondm); 2084 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2085 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2086 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2087 PetscSectionSetChart(section, pStart, pEnd); 2088 PetscSectionSetUp(section); 2089 DMSetLocalSection(sectiondm, section); 2090 DMGetLocalVector(sectiondm, &vec); 2091 PetscObjectSetName((PetscObject)vec, "vec_name"); 2092 DMPlexTopologyView(dm, viewer); 2093 DMPlexSectionView(dm, viewer, sectiondm); 2094 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2095 DMRestoreLocalVector(sectiondm, &vec); 2096 DMDestroy(§iondm); 2097 DMDestroy(&dm); 2098 .ve 2099 2100 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2101 @*/ 2102 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2103 { 2104 PetscBool ishdf5; 2105 2106 PetscFunctionBegin; 2107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2108 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2109 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2110 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2111 /* Check consistency */ 2112 { 2113 PetscSection section; 2114 PetscBool includesConstraints; 2115 PetscInt m, m1; 2116 2117 PetscCall(VecGetLocalSize(vec, &m1)); 2118 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2119 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2120 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2121 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2122 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2123 } 2124 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2125 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2126 if (ishdf5) { 2127 #if defined(PETSC_HAVE_HDF5) 2128 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2129 #else 2130 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2131 #endif 2132 } 2133 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2134 PetscFunctionReturn(PETSC_SUCCESS); 2135 } 2136 2137 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2138 { 2139 PetscBool ishdf5; 2140 2141 PetscFunctionBegin; 2142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2143 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2144 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2145 if (ishdf5) { 2146 #if defined(PETSC_HAVE_HDF5) 2147 PetscViewerFormat format; 2148 PetscCall(PetscViewerGetFormat(viewer, &format)); 2149 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2150 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2151 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2152 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2153 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2154 PetscFunctionReturn(PETSC_SUCCESS); 2155 #else 2156 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2157 #endif 2158 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2159 } 2160 2161 /*@ 2162 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2163 2164 Collective 2165 2166 Input Parameters: 2167 + dm - The `DM` into which the topology is loaded 2168 - viewer - The `PetscViewer` for the saved topology 2169 2170 Output Parameter: 2171 . 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 2172 2173 Level: advanced 2174 2175 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2176 `PetscViewer`, `PetscSF` 2177 @*/ 2178 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2179 { 2180 PetscBool ishdf5; 2181 2182 PetscFunctionBegin; 2183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2184 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2185 if (globalToLocalPointSF) PetscAssertPointer(globalToLocalPointSF, 3); 2186 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2187 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2188 if (ishdf5) { 2189 #if defined(PETSC_HAVE_HDF5) 2190 PetscViewerFormat format; 2191 PetscCall(PetscViewerGetFormat(viewer, &format)); 2192 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2193 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2194 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2195 #else 2196 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2197 #endif 2198 } 2199 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2200 PetscFunctionReturn(PETSC_SUCCESS); 2201 } 2202 2203 /*@ 2204 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2205 2206 Collective 2207 2208 Input Parameters: 2209 + dm - The `DM` into which the coordinates are loaded 2210 . viewer - The `PetscViewer` for the saved coordinates 2211 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2212 2213 Level: advanced 2214 2215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2216 `PetscSF`, `PetscViewer` 2217 @*/ 2218 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2219 { 2220 PetscBool ishdf5; 2221 2222 PetscFunctionBegin; 2223 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2224 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2225 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2226 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2227 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2228 if (ishdf5) { 2229 #if defined(PETSC_HAVE_HDF5) 2230 PetscViewerFormat format; 2231 PetscCall(PetscViewerGetFormat(viewer, &format)); 2232 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2233 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2234 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2235 #else 2236 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2237 #endif 2238 } 2239 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2240 PetscFunctionReturn(PETSC_SUCCESS); 2241 } 2242 2243 /*@ 2244 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2245 2246 Collective 2247 2248 Input Parameters: 2249 + dm - The `DM` into which the labels are loaded 2250 . viewer - The `PetscViewer` for the saved labels 2251 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2252 2253 Level: advanced 2254 2255 Note: 2256 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2257 2258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2259 `PetscSF`, `PetscViewer` 2260 @*/ 2261 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2262 { 2263 PetscBool ishdf5; 2264 2265 PetscFunctionBegin; 2266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2267 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2268 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2269 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2270 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2271 if (ishdf5) { 2272 #if defined(PETSC_HAVE_HDF5) 2273 PetscViewerFormat format; 2274 2275 PetscCall(PetscViewerGetFormat(viewer, &format)); 2276 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2277 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2278 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2279 #else 2280 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2281 #endif 2282 } 2283 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2284 PetscFunctionReturn(PETSC_SUCCESS); 2285 } 2286 2287 /*@ 2288 DMPlexSectionLoad - Loads section into a `DMPLEX` 2289 2290 Collective 2291 2292 Input Parameters: 2293 + dm - The `DM` that represents the topology 2294 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2295 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2296 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2297 2298 Output Parameters: 2299 + 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) 2300 - 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) 2301 2302 Level: advanced 2303 2304 Notes: 2305 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. 2306 2307 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2308 2309 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. 2310 2311 Example using 2 processes: 2312 .vb 2313 NX (number of points on dm): 4 2314 sectionA : the on-disk section 2315 vecA : a vector associated with sectionA 2316 sectionB : sectiondm's local section constructed in this function 2317 vecB (local) : a vector associated with sectiondm's local section 2318 vecB (global) : a vector associated with sectiondm's global section 2319 2320 rank 0 rank 1 2321 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2322 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2323 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2324 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2325 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2326 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2327 sectionB->atlasDof : 1 0 1 | 1 3 2328 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2329 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2330 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2331 .ve 2332 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2333 2334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2335 @*/ 2336 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2344 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2345 if (globalDofSF) PetscAssertPointer(globalDofSF, 5); 2346 if (localDofSF) PetscAssertPointer(localDofSF, 6); 2347 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2348 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2349 if (ishdf5) { 2350 #if defined(PETSC_HAVE_HDF5) 2351 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2352 #else 2353 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2354 #endif 2355 } 2356 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2357 PetscFunctionReturn(PETSC_SUCCESS); 2358 } 2359 2360 /*@ 2361 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2362 2363 Collective 2364 2365 Input Parameters: 2366 + dm - The `DM` that represents the topology 2367 . viewer - The `PetscViewer` that represents the on-disk vector data 2368 . sectiondm - The `DM` that contains the global section on which vec is defined 2369 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2370 - vec - The global vector to set values of 2371 2372 Level: advanced 2373 2374 Notes: 2375 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. 2376 2377 Calling sequence: 2378 .vb 2379 DMCreate(PETSC_COMM_WORLD, &dm); 2380 DMSetType(dm, DMPLEX); 2381 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2382 DMPlexTopologyLoad(dm, viewer, &sfX); 2383 DMClone(dm, §iondm); 2384 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2385 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2386 DMGetGlobalVector(sectiondm, &vec); 2387 PetscObjectSetName((PetscObject)vec, "vec_name"); 2388 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2389 DMRestoreGlobalVector(sectiondm, &vec); 2390 PetscSFDestroy(&gsf); 2391 PetscSFDestroy(&sfX); 2392 DMDestroy(§iondm); 2393 DMDestroy(&dm); 2394 .ve 2395 2396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2397 `PetscSF`, `PetscViewer` 2398 @*/ 2399 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2400 { 2401 PetscBool ishdf5; 2402 2403 PetscFunctionBegin; 2404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2405 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2406 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2407 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2408 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2409 /* Check consistency */ 2410 { 2411 PetscSection section; 2412 PetscBool includesConstraints; 2413 PetscInt m, m1; 2414 2415 PetscCall(VecGetLocalSize(vec, &m1)); 2416 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2417 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2418 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2419 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2420 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2421 } 2422 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2423 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2424 if (ishdf5) { 2425 #if defined(PETSC_HAVE_HDF5) 2426 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2427 #else 2428 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2429 #endif 2430 } 2431 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2432 PetscFunctionReturn(PETSC_SUCCESS); 2433 } 2434 2435 /*@ 2436 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2437 2438 Collective 2439 2440 Input Parameters: 2441 + dm - The `DM` that represents the topology 2442 . viewer - The `PetscViewer` that represents the on-disk vector data 2443 . sectiondm - The `DM` that contains the local section on which vec is defined 2444 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2445 - vec - The local vector to set values of 2446 2447 Level: advanced 2448 2449 Notes: 2450 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. 2451 2452 Calling sequence: 2453 .vb 2454 DMCreate(PETSC_COMM_WORLD, &dm); 2455 DMSetType(dm, DMPLEX); 2456 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2457 DMPlexTopologyLoad(dm, viewer, &sfX); 2458 DMClone(dm, §iondm); 2459 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2460 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2461 DMGetLocalVector(sectiondm, &vec); 2462 PetscObjectSetName((PetscObject)vec, "vec_name"); 2463 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2464 DMRestoreLocalVector(sectiondm, &vec); 2465 PetscSFDestroy(&lsf); 2466 PetscSFDestroy(&sfX); 2467 DMDestroy(§iondm); 2468 DMDestroy(&dm); 2469 .ve 2470 2471 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2472 `PetscSF`, `PetscViewer` 2473 @*/ 2474 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2475 { 2476 PetscBool ishdf5; 2477 2478 PetscFunctionBegin; 2479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2480 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2481 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2482 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2483 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2484 /* Check consistency */ 2485 { 2486 PetscSection section; 2487 PetscBool includesConstraints; 2488 PetscInt m, m1; 2489 2490 PetscCall(VecGetLocalSize(vec, &m1)); 2491 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2492 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2493 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2494 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2495 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2496 } 2497 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2498 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2499 if (ishdf5) { 2500 #if defined(PETSC_HAVE_HDF5) 2501 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2502 #else 2503 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2504 #endif 2505 } 2506 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2507 PetscFunctionReturn(PETSC_SUCCESS); 2508 } 2509 2510 PetscErrorCode DMDestroy_Plex(DM dm) 2511 { 2512 DM_Plex *mesh = (DM_Plex *)dm->data; 2513 2514 PetscFunctionBegin; 2515 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2516 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2517 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2518 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2519 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2520 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2521 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2522 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2523 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2524 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2525 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2526 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2527 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2528 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2529 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2530 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2531 PetscCall(PetscFree(mesh->cones)); 2532 PetscCall(PetscFree(mesh->coneOrientations)); 2533 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2534 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2535 PetscCall(PetscFree(mesh->supports)); 2536 PetscCall(PetscFree(mesh->cellTypes)); 2537 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2538 PetscCall(PetscFree(mesh->tetgenOpts)); 2539 PetscCall(PetscFree(mesh->triangleOpts)); 2540 PetscCall(PetscFree(mesh->transformType)); 2541 PetscCall(PetscFree(mesh->distributionName)); 2542 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2543 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2544 PetscCall(ISDestroy(&mesh->subpointIS)); 2545 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2546 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2547 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2548 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2549 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2550 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2551 PetscCall(ISDestroy(&mesh->anchorIS)); 2552 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2553 PetscCall(PetscFree(mesh->parents)); 2554 PetscCall(PetscFree(mesh->childIDs)); 2555 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2556 PetscCall(PetscFree(mesh->children)); 2557 PetscCall(DMDestroy(&mesh->referenceTree)); 2558 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2559 PetscCall(PetscFree(mesh->neighbors)); 2560 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2561 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2562 PetscCall(PetscFree(mesh)); 2563 PetscFunctionReturn(PETSC_SUCCESS); 2564 } 2565 2566 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2567 { 2568 PetscSection sectionGlobal; 2569 PetscInt bs = -1, mbs; 2570 PetscInt localSize, localStart = 0; 2571 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2572 MatType mtype; 2573 ISLocalToGlobalMapping ltog; 2574 2575 PetscFunctionBegin; 2576 PetscCall(MatInitializePackage()); 2577 mtype = dm->mattype; 2578 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2579 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2580 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2581 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2582 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2583 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2584 PetscCall(MatSetType(*J, mtype)); 2585 PetscCall(MatSetFromOptions(*J)); 2586 PetscCall(MatGetBlockSize(*J, &mbs)); 2587 if (mbs > 1) bs = mbs; 2588 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2589 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2590 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2591 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2592 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2593 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2594 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2595 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2596 if (!isShell) { 2597 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2598 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2599 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2600 2601 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2602 2603 PetscCall(PetscCalloc1(localSize, &pblocks)); 2604 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2605 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2606 for (p = pStart; p < pEnd; ++p) { 2607 switch (dm->blocking_type) { 2608 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2609 PetscInt bdof, offset; 2610 2611 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2612 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2613 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2614 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2615 dof = dof < 0 ? -(dof + 1) : dof; 2616 bdof = cdof && (dof - cdof) ? 1 : dof; 2617 if (dof) { 2618 if (bs < 0) { 2619 bs = bdof; 2620 } else if (bs != bdof) { 2621 bs = 1; 2622 } 2623 } 2624 } break; 2625 case DM_BLOCKING_FIELD_NODE: { 2626 for (PetscInt field = 0; field < num_fields; field++) { 2627 PetscInt num_comp, bdof, offset; 2628 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2629 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2630 if (dof < 0) continue; 2631 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2632 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2633 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); 2634 PetscInt num_nodes = dof / num_comp; 2635 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2636 // Handle possibly constant block size (unlikely) 2637 bdof = cdof && (dof - cdof) ? 1 : dof; 2638 if (dof) { 2639 if (bs < 0) { 2640 bs = bdof; 2641 } else if (bs != bdof) { 2642 bs = 1; 2643 } 2644 } 2645 } 2646 } break; 2647 } 2648 } 2649 /* Must have same blocksize on all procs (some might have no points) */ 2650 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2651 bsLocal[1] = bs; 2652 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2653 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2654 else bs = bsMinMax[0]; 2655 bs = PetscMax(1, bs); 2656 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2657 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2658 PetscCall(MatSetBlockSize(*J, bs)); 2659 PetscCall(MatSetUp(*J)); 2660 } else { 2661 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2662 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2663 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2664 } 2665 { // Consolidate blocks 2666 PetscInt nblocks = 0; 2667 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2668 if (pblocks[i] == 0) continue; 2669 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2670 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]); 2671 } 2672 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2673 } 2674 PetscCall(PetscFree(pblocks)); 2675 } 2676 PetscCall(MatSetDM(*J, dm)); 2677 PetscFunctionReturn(PETSC_SUCCESS); 2678 } 2679 2680 /*@ 2681 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2682 2683 Not Collective 2684 2685 Input Parameter: 2686 . dm - The `DMPLEX` 2687 2688 Output Parameter: 2689 . subsection - The subdomain section 2690 2691 Level: developer 2692 2693 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2694 @*/ 2695 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2696 { 2697 DM_Plex *mesh = (DM_Plex *)dm->data; 2698 2699 PetscFunctionBegin; 2700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2701 if (!mesh->subdomainSection) { 2702 PetscSection section; 2703 PetscSF sf; 2704 2705 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2706 PetscCall(DMGetLocalSection(dm, §ion)); 2707 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2708 PetscCall(PetscSFDestroy(&sf)); 2709 } 2710 *subsection = mesh->subdomainSection; 2711 PetscFunctionReturn(PETSC_SUCCESS); 2712 } 2713 2714 /*@ 2715 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2716 2717 Not Collective 2718 2719 Input Parameter: 2720 . dm - The `DMPLEX` 2721 2722 Output Parameters: 2723 + pStart - The first mesh point 2724 - pEnd - The upper bound for mesh points 2725 2726 Level: beginner 2727 2728 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2729 @*/ 2730 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2731 { 2732 DM_Plex *mesh = (DM_Plex *)dm->data; 2733 2734 PetscFunctionBegin; 2735 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2736 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2737 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2738 PetscFunctionReturn(PETSC_SUCCESS); 2739 } 2740 2741 /*@ 2742 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2743 2744 Not Collective 2745 2746 Input Parameters: 2747 + dm - The `DMPLEX` 2748 . pStart - The first mesh point 2749 - pEnd - The upper bound for mesh points 2750 2751 Level: beginner 2752 2753 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2754 @*/ 2755 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2756 { 2757 DM_Plex *mesh = (DM_Plex *)dm->data; 2758 2759 PetscFunctionBegin; 2760 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2761 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2762 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2763 PetscCall(PetscFree(mesh->cellTypes)); 2764 PetscFunctionReturn(PETSC_SUCCESS); 2765 } 2766 2767 /*@ 2768 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2769 2770 Not Collective 2771 2772 Input Parameters: 2773 + dm - The `DMPLEX` 2774 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2775 2776 Output Parameter: 2777 . size - The cone size for point `p` 2778 2779 Level: beginner 2780 2781 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2782 @*/ 2783 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2784 { 2785 DM_Plex *mesh = (DM_Plex *)dm->data; 2786 2787 PetscFunctionBegin; 2788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2789 PetscAssertPointer(size, 3); 2790 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2791 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2792 PetscFunctionReturn(PETSC_SUCCESS); 2793 } 2794 2795 /*@ 2796 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2797 2798 Not Collective 2799 2800 Input Parameters: 2801 + dm - The `DMPLEX` 2802 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2803 - size - The cone size for point `p` 2804 2805 Level: beginner 2806 2807 Note: 2808 This should be called after `DMPlexSetChart()`. 2809 2810 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2811 @*/ 2812 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2813 { 2814 DM_Plex *mesh = (DM_Plex *)dm->data; 2815 2816 PetscFunctionBegin; 2817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2818 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2819 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2820 PetscFunctionReturn(PETSC_SUCCESS); 2821 } 2822 2823 /*@C 2824 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2825 2826 Not Collective 2827 2828 Input Parameters: 2829 + dm - The `DMPLEX` 2830 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2831 2832 Output Parameter: 2833 . cone - An array of points which are on the in-edges for point `p` 2834 2835 Level: beginner 2836 2837 Fortran Notes: 2838 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2839 `DMPlexRestoreCone()` is not needed/available in C. 2840 2841 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2842 @*/ 2843 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2844 { 2845 DM_Plex *mesh = (DM_Plex *)dm->data; 2846 PetscInt off; 2847 2848 PetscFunctionBegin; 2849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2850 PetscAssertPointer(cone, 3); 2851 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2852 *cone = &mesh->cones[off]; 2853 PetscFunctionReturn(PETSC_SUCCESS); 2854 } 2855 2856 /*@C 2857 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2858 2859 Not Collective 2860 2861 Input Parameters: 2862 + dm - The `DMPLEX` 2863 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2864 2865 Output Parameters: 2866 + pConesSection - `PetscSection` describing the layout of `pCones` 2867 - pCones - An array of points which are on the in-edges for the point set `p` 2868 2869 Level: intermediate 2870 2871 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2872 @*/ 2873 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2874 { 2875 PetscSection cs, newcs; 2876 PetscInt *cones; 2877 PetscInt *newarr = NULL; 2878 PetscInt n; 2879 2880 PetscFunctionBegin; 2881 PetscCall(DMPlexGetCones(dm, &cones)); 2882 PetscCall(DMPlexGetConeSection(dm, &cs)); 2883 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2884 if (pConesSection) *pConesSection = newcs; 2885 if (pCones) { 2886 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2887 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2888 } 2889 PetscFunctionReturn(PETSC_SUCCESS); 2890 } 2891 2892 /*@ 2893 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2894 2895 Not Collective 2896 2897 Input Parameters: 2898 + dm - The `DMPLEX` 2899 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2900 2901 Output Parameter: 2902 . expandedPoints - An array of vertices recursively expanded from input points 2903 2904 Level: advanced 2905 2906 Notes: 2907 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 2908 2909 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 2910 2911 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 2912 `DMPlexGetDepth()`, `IS` 2913 @*/ 2914 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2915 { 2916 IS *expandedPointsAll; 2917 PetscInt depth; 2918 2919 PetscFunctionBegin; 2920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2921 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2922 PetscAssertPointer(expandedPoints, 3); 2923 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2924 *expandedPoints = expandedPointsAll[0]; 2925 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2926 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2927 PetscFunctionReturn(PETSC_SUCCESS); 2928 } 2929 2930 /*@ 2931 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). 2932 2933 Not Collective 2934 2935 Input Parameters: 2936 + dm - The `DMPLEX` 2937 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2938 2939 Output Parameters: 2940 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 2941 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2942 - sections - (optional) An array of sections which describe mappings from points to their cone points 2943 2944 Level: advanced 2945 2946 Notes: 2947 Like `DMPlexGetConeTuple()` but recursive. 2948 2949 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. 2950 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2951 2952 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\: 2953 (1) DAG points in `expandedPoints`[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 2954 (2) DAG points in `expandedPoints`[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 2955 2956 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 2957 `DMPlexGetDepth()`, `PetscSection`, `IS` 2958 @*/ 2959 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2960 { 2961 const PetscInt *arr0 = NULL, *cone = NULL; 2962 PetscInt *arr = NULL, *newarr = NULL; 2963 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2964 IS *expandedPoints_; 2965 PetscSection *sections_; 2966 2967 PetscFunctionBegin; 2968 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2969 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2970 if (depth) PetscAssertPointer(depth, 3); 2971 if (expandedPoints) PetscAssertPointer(expandedPoints, 4); 2972 if (sections) PetscAssertPointer(sections, 5); 2973 PetscCall(ISGetLocalSize(points, &n)); 2974 PetscCall(ISGetIndices(points, &arr0)); 2975 PetscCall(DMPlexGetDepth(dm, &depth_)); 2976 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2977 PetscCall(PetscCalloc1(depth_, §ions_)); 2978 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2979 for (d = depth_ - 1; d >= 0; d--) { 2980 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2981 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2982 for (i = 0; i < n; i++) { 2983 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2984 if (arr[i] >= start && arr[i] < end) { 2985 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2986 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2987 } else { 2988 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2989 } 2990 } 2991 PetscCall(PetscSectionSetUp(sections_[d])); 2992 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2993 PetscCall(PetscMalloc1(newn, &newarr)); 2994 for (i = 0; i < n; i++) { 2995 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2996 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2997 if (cn > 1) { 2998 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2999 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3000 } else { 3001 newarr[co] = arr[i]; 3002 } 3003 } 3004 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3005 arr = newarr; 3006 n = newn; 3007 } 3008 PetscCall(ISRestoreIndices(points, &arr0)); 3009 *depth = depth_; 3010 if (expandedPoints) *expandedPoints = expandedPoints_; 3011 else { 3012 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3013 PetscCall(PetscFree(expandedPoints_)); 3014 } 3015 if (sections) *sections = sections_; 3016 else { 3017 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3018 PetscCall(PetscFree(sections_)); 3019 } 3020 PetscFunctionReturn(PETSC_SUCCESS); 3021 } 3022 3023 /*@ 3024 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3025 3026 Not Collective 3027 3028 Input Parameters: 3029 + dm - The `DMPLEX` 3030 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3031 3032 Output Parameters: 3033 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3034 . expandedPoints - (optional) An array of recursively expanded cones 3035 - sections - (optional) An array of sections which describe mappings from points to their cone points 3036 3037 Level: advanced 3038 3039 Note: 3040 See `DMPlexGetConeRecursive()` 3041 3042 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3043 `DMPlexGetDepth()`, `IS`, `PetscSection` 3044 @*/ 3045 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3046 { 3047 PetscInt d, depth_; 3048 3049 PetscFunctionBegin; 3050 PetscCall(DMPlexGetDepth(dm, &depth_)); 3051 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3052 if (depth) *depth = 0; 3053 if (expandedPoints) { 3054 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3055 PetscCall(PetscFree(*expandedPoints)); 3056 } 3057 if (sections) { 3058 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3059 PetscCall(PetscFree(*sections)); 3060 } 3061 PetscFunctionReturn(PETSC_SUCCESS); 3062 } 3063 3064 /*@ 3065 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 3066 3067 Not Collective 3068 3069 Input Parameters: 3070 + dm - The `DMPLEX` 3071 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3072 - cone - An array of points which are on the in-edges for point `p` 3073 3074 Level: beginner 3075 3076 Note: 3077 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3078 3079 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3080 @*/ 3081 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3082 { 3083 DM_Plex *mesh = (DM_Plex *)dm->data; 3084 PetscInt dof, off, c; 3085 3086 PetscFunctionBegin; 3087 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3088 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3089 if (dof) PetscAssertPointer(cone, 3); 3090 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3091 if (PetscDefined(USE_DEBUG)) { 3092 PetscInt pStart, pEnd; 3093 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3094 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); 3095 for (c = 0; c < dof; ++c) { 3096 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); 3097 mesh->cones[off + c] = cone[c]; 3098 } 3099 } else { 3100 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3101 } 3102 PetscFunctionReturn(PETSC_SUCCESS); 3103 } 3104 3105 /*@C 3106 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3107 3108 Not Collective 3109 3110 Input Parameters: 3111 + dm - The `DMPLEX` 3112 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3113 3114 Output Parameter: 3115 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3116 integer giving the prescription for cone traversal. 3117 3118 Level: beginner 3119 3120 Note: 3121 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3122 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3123 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3124 with the identity. 3125 3126 Fortran Notes: 3127 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3128 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3129 3130 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3131 @*/ 3132 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3133 { 3134 DM_Plex *mesh = (DM_Plex *)dm->data; 3135 PetscInt off; 3136 3137 PetscFunctionBegin; 3138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3139 if (PetscDefined(USE_DEBUG)) { 3140 PetscInt dof; 3141 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3142 if (dof) PetscAssertPointer(coneOrientation, 3); 3143 } 3144 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3145 3146 *coneOrientation = &mesh->coneOrientations[off]; 3147 PetscFunctionReturn(PETSC_SUCCESS); 3148 } 3149 3150 /*@ 3151 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3152 3153 Not Collective 3154 3155 Input Parameters: 3156 + dm - The `DMPLEX` 3157 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3158 - coneOrientation - An array of orientations 3159 3160 Level: beginner 3161 3162 Notes: 3163 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3164 3165 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3166 3167 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3168 @*/ 3169 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3170 { 3171 DM_Plex *mesh = (DM_Plex *)dm->data; 3172 PetscInt pStart, pEnd; 3173 PetscInt dof, off, c; 3174 3175 PetscFunctionBegin; 3176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3177 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3178 if (dof) PetscAssertPointer(coneOrientation, 3); 3179 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3180 if (PetscDefined(USE_DEBUG)) { 3181 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3182 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); 3183 for (c = 0; c < dof; ++c) { 3184 PetscInt cdof, o = coneOrientation[c]; 3185 3186 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3187 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); 3188 mesh->coneOrientations[off + c] = o; 3189 } 3190 } else { 3191 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3192 } 3193 PetscFunctionReturn(PETSC_SUCCESS); 3194 } 3195 3196 /*@ 3197 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3198 3199 Not Collective 3200 3201 Input Parameters: 3202 + dm - The `DMPLEX` 3203 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3204 . conePos - The local index in the cone where the point should be put 3205 - conePoint - The mesh point to insert 3206 3207 Level: beginner 3208 3209 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3210 @*/ 3211 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3212 { 3213 DM_Plex *mesh = (DM_Plex *)dm->data; 3214 PetscInt pStart, pEnd; 3215 PetscInt dof, off; 3216 3217 PetscFunctionBegin; 3218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3219 if (PetscDefined(USE_DEBUG)) { 3220 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3221 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); 3222 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); 3223 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3224 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); 3225 } 3226 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3227 mesh->cones[off + conePos] = conePoint; 3228 PetscFunctionReturn(PETSC_SUCCESS); 3229 } 3230 3231 /*@ 3232 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3233 3234 Not Collective 3235 3236 Input Parameters: 3237 + dm - The `DMPLEX` 3238 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3239 . conePos - The local index in the cone where the point should be put 3240 - coneOrientation - The point orientation to insert 3241 3242 Level: beginner 3243 3244 Note: 3245 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3246 3247 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3248 @*/ 3249 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3250 { 3251 DM_Plex *mesh = (DM_Plex *)dm->data; 3252 PetscInt pStart, pEnd; 3253 PetscInt dof, off; 3254 3255 PetscFunctionBegin; 3256 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3257 if (PetscDefined(USE_DEBUG)) { 3258 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3259 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); 3260 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3261 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); 3262 } 3263 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3264 mesh->coneOrientations[off + conePos] = coneOrientation; 3265 PetscFunctionReturn(PETSC_SUCCESS); 3266 } 3267 3268 /*@C 3269 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3270 3271 Not collective 3272 3273 Input Parameters: 3274 + dm - The DMPlex 3275 - p - The point, which must lie in the chart set with DMPlexSetChart() 3276 3277 Output Parameters: 3278 + cone - An array of points which are on the in-edges for point `p` 3279 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3280 integer giving the prescription for cone traversal. 3281 3282 Level: beginner 3283 3284 Notes: 3285 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3286 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3287 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3288 with the identity. 3289 3290 Fortran Notes: 3291 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3292 `DMPlexRestoreCone()` is not needed/available in C. 3293 3294 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3295 @*/ 3296 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3297 { 3298 DM_Plex *mesh = (DM_Plex *)dm->data; 3299 3300 PetscFunctionBegin; 3301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3302 if (mesh->tr) { 3303 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3304 } else { 3305 PetscInt off; 3306 if (PetscDefined(USE_DEBUG)) { 3307 PetscInt dof; 3308 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3309 if (dof) { 3310 if (cone) PetscAssertPointer(cone, 3); 3311 if (ornt) PetscAssertPointer(ornt, 4); 3312 } 3313 } 3314 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3315 if (cone) *cone = mesh->cones ? mesh->cones + off : NULL; // NULL + 0 is UB 3316 if (ornt) *ornt = mesh->coneOrientations ? mesh->coneOrientations + off : NULL; 3317 } 3318 PetscFunctionReturn(PETSC_SUCCESS); 3319 } 3320 3321 /*@C 3322 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3323 3324 Not Collective 3325 3326 Input Parameters: 3327 + dm - The DMPlex 3328 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3329 . cone - An array of points which are on the in-edges for point p 3330 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3331 integer giving the prescription for cone traversal. 3332 3333 Level: beginner 3334 3335 Notes: 3336 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3337 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3338 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3339 with the identity. 3340 3341 Fortran Notes: 3342 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3343 `DMPlexRestoreCone()` is not needed/available in C. 3344 3345 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3346 @*/ 3347 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3348 { 3349 DM_Plex *mesh = (DM_Plex *)dm->data; 3350 3351 PetscFunctionBegin; 3352 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3353 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3354 PetscFunctionReturn(PETSC_SUCCESS); 3355 } 3356 3357 /*@ 3358 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3359 3360 Not Collective 3361 3362 Input Parameters: 3363 + dm - The `DMPLEX` 3364 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3365 3366 Output Parameter: 3367 . size - The support size for point `p` 3368 3369 Level: beginner 3370 3371 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3372 @*/ 3373 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3374 { 3375 DM_Plex *mesh = (DM_Plex *)dm->data; 3376 3377 PetscFunctionBegin; 3378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3379 PetscAssertPointer(size, 3); 3380 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3381 PetscFunctionReturn(PETSC_SUCCESS); 3382 } 3383 3384 /*@ 3385 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3386 3387 Not Collective 3388 3389 Input Parameters: 3390 + dm - The `DMPLEX` 3391 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3392 - size - The support size for point `p` 3393 3394 Level: beginner 3395 3396 Note: 3397 This should be called after `DMPlexSetChart()`. 3398 3399 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3400 @*/ 3401 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3402 { 3403 DM_Plex *mesh = (DM_Plex *)dm->data; 3404 3405 PetscFunctionBegin; 3406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3407 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3408 PetscFunctionReturn(PETSC_SUCCESS); 3409 } 3410 3411 /*@C 3412 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3413 3414 Not Collective 3415 3416 Input Parameters: 3417 + dm - The `DMPLEX` 3418 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3419 3420 Output Parameter: 3421 . support - An array of points which are on the out-edges for point `p` 3422 3423 Level: beginner 3424 3425 Fortran Notes: 3426 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3427 `DMPlexRestoreSupport()` is not needed/available in C. 3428 3429 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3430 @*/ 3431 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3432 { 3433 DM_Plex *mesh = (DM_Plex *)dm->data; 3434 PetscInt off; 3435 3436 PetscFunctionBegin; 3437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3438 PetscAssertPointer(support, 3); 3439 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3440 *support = mesh->supports ? mesh->supports + off : NULL; //NULL + 0 is UB 3441 PetscFunctionReturn(PETSC_SUCCESS); 3442 } 3443 3444 /*@ 3445 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3446 3447 Not Collective 3448 3449 Input Parameters: 3450 + dm - The `DMPLEX` 3451 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3452 - support - An array of points which are on the out-edges for point `p` 3453 3454 Level: beginner 3455 3456 Note: 3457 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3458 3459 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3460 @*/ 3461 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3462 { 3463 DM_Plex *mesh = (DM_Plex *)dm->data; 3464 PetscInt pStart, pEnd; 3465 PetscInt dof, off, c; 3466 3467 PetscFunctionBegin; 3468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3469 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3470 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3471 if (dof) PetscAssertPointer(support, 3); 3472 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3473 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3474 for (c = 0; c < dof; ++c) { 3475 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); 3476 mesh->supports[off + c] = support[c]; 3477 } 3478 PetscFunctionReturn(PETSC_SUCCESS); 3479 } 3480 3481 /*@ 3482 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3483 3484 Not Collective 3485 3486 Input Parameters: 3487 + dm - The `DMPLEX` 3488 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3489 . supportPos - The local index in the cone where the point should be put 3490 - supportPoint - The mesh point to insert 3491 3492 Level: beginner 3493 3494 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3495 @*/ 3496 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3497 { 3498 DM_Plex *mesh = (DM_Plex *)dm->data; 3499 PetscInt pStart, pEnd; 3500 PetscInt dof, off; 3501 3502 PetscFunctionBegin; 3503 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3504 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3505 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3506 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3507 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); 3508 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); 3509 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); 3510 mesh->supports[off + supportPos] = supportPoint; 3511 PetscFunctionReturn(PETSC_SUCCESS); 3512 } 3513 3514 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3515 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3516 { 3517 switch (ct) { 3518 case DM_POLYTOPE_SEGMENT: 3519 if (o == -1) return -2; 3520 break; 3521 case DM_POLYTOPE_TRIANGLE: 3522 if (o == -3) return -1; 3523 if (o == -2) return -3; 3524 if (o == -1) return -2; 3525 break; 3526 case DM_POLYTOPE_QUADRILATERAL: 3527 if (o == -4) return -2; 3528 if (o == -3) return -1; 3529 if (o == -2) return -4; 3530 if (o == -1) return -3; 3531 break; 3532 default: 3533 return o; 3534 } 3535 return o; 3536 } 3537 3538 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3539 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3540 { 3541 switch (ct) { 3542 case DM_POLYTOPE_SEGMENT: 3543 if ((o == -2) || (o == 1)) return -1; 3544 if (o == -1) return 0; 3545 break; 3546 case DM_POLYTOPE_TRIANGLE: 3547 if (o == -3) return -2; 3548 if (o == -2) return -1; 3549 if (o == -1) return -3; 3550 break; 3551 case DM_POLYTOPE_QUADRILATERAL: 3552 if (o == -4) return -2; 3553 if (o == -3) return -1; 3554 if (o == -2) return -4; 3555 if (o == -1) return -3; 3556 break; 3557 default: 3558 return o; 3559 } 3560 return o; 3561 } 3562 3563 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3564 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3565 { 3566 PetscInt pStart, pEnd, p; 3567 3568 PetscFunctionBegin; 3569 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3570 for (p = pStart; p < pEnd; ++p) { 3571 const PetscInt *cone, *ornt; 3572 PetscInt coneSize, c; 3573 3574 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3575 PetscCall(DMPlexGetCone(dm, p, &cone)); 3576 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3577 for (c = 0; c < coneSize; ++c) { 3578 DMPolytopeType ct; 3579 const PetscInt o = ornt[c]; 3580 3581 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3582 switch (ct) { 3583 case DM_POLYTOPE_SEGMENT: 3584 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3585 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3586 break; 3587 case DM_POLYTOPE_TRIANGLE: 3588 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3589 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3590 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3591 break; 3592 case DM_POLYTOPE_QUADRILATERAL: 3593 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3594 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3595 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3596 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3597 break; 3598 default: 3599 break; 3600 } 3601 } 3602 } 3603 PetscFunctionReturn(PETSC_SUCCESS); 3604 } 3605 3606 static inline PetscErrorCode DMPlexGetTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3607 { 3608 DM_Plex *mesh = (DM_Plex *)dm->data; 3609 3610 PetscFunctionBeginHot; 3611 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3612 if (useCone) { 3613 PetscCall(DMPlexGetConeSize(dm, p, size)); 3614 PetscCall(DMPlexGetOrientedCone(dm, p, arr, ornt)); 3615 } else { 3616 PetscCall(DMPlexGetSupportSize(dm, p, size)); 3617 PetscCall(DMPlexGetSupport(dm, p, arr)); 3618 } 3619 } else { 3620 if (useCone) { 3621 const PetscSection s = mesh->coneSection; 3622 const PetscInt ps = p - s->pStart; 3623 const PetscInt off = s->atlasOff[ps]; 3624 3625 *size = s->atlasDof[ps]; 3626 *arr = mesh->cones + off; 3627 *ornt = mesh->coneOrientations + off; 3628 } else { 3629 const PetscSection s = mesh->supportSection; 3630 const PetscInt ps = p - s->pStart; 3631 const PetscInt off = s->atlasOff[ps]; 3632 3633 *size = s->atlasDof[ps]; 3634 *arr = mesh->supports + off; 3635 } 3636 } 3637 PetscFunctionReturn(PETSC_SUCCESS); 3638 } 3639 3640 static inline PetscErrorCode DMPlexRestoreTransitiveClosure_Hot_Private(DM dm, PetscInt p, PetscBool useCone, PetscInt *size, const PetscInt *arr[], const PetscInt *ornt[]) 3641 { 3642 DM_Plex *mesh = (DM_Plex *)dm->data; 3643 3644 PetscFunctionBeginHot; 3645 if (PetscDefined(USE_DEBUG) || mesh->tr) { 3646 if (useCone) PetscCall(DMPlexRestoreOrientedCone(dm, p, arr, ornt)); 3647 } 3648 PetscFunctionReturn(PETSC_SUCCESS); 3649 } 3650 3651 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3652 { 3653 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3654 PetscInt *closure; 3655 const PetscInt *tmp = NULL, *tmpO = NULL; 3656 PetscInt off = 0, tmpSize, t; 3657 3658 PetscFunctionBeginHot; 3659 if (ornt) { 3660 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3661 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3662 } 3663 if (*points) { 3664 closure = *points; 3665 } else { 3666 PetscInt maxConeSize, maxSupportSize; 3667 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3668 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3669 } 3670 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3671 if (ct == DM_POLYTOPE_UNKNOWN) { 3672 closure[off++] = p; 3673 closure[off++] = 0; 3674 for (t = 0; t < tmpSize; ++t) { 3675 closure[off++] = tmp[t]; 3676 closure[off++] = tmpO ? tmpO[t] : 0; 3677 } 3678 } else { 3679 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3680 3681 /* We assume that cells with a valid type have faces with a valid type */ 3682 closure[off++] = p; 3683 closure[off++] = ornt; 3684 for (t = 0; t < tmpSize; ++t) { 3685 DMPolytopeType ft; 3686 3687 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3688 closure[off++] = tmp[arr[t]]; 3689 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3690 } 3691 } 3692 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, p, useCone, &tmpSize, &tmp, &tmpO)); 3693 if (numPoints) *numPoints = tmpSize + 1; 3694 if (points) *points = closure; 3695 PetscFunctionReturn(PETSC_SUCCESS); 3696 } 3697 3698 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3699 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3700 { 3701 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3702 const PetscInt *cone, *ornt; 3703 PetscInt *pts, *closure = NULL; 3704 DMPolytopeType ft; 3705 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3706 PetscInt dim, coneSize, c, d, clSize, cl; 3707 3708 PetscFunctionBeginHot; 3709 PetscCall(DMGetDimension(dm, &dim)); 3710 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3711 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3712 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3713 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3714 maxSize = PetscMax(coneSeries, supportSeries); 3715 if (*points) { 3716 pts = *points; 3717 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3718 c = 0; 3719 pts[c++] = point; 3720 pts[c++] = o; 3721 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3722 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3723 for (cl = 0; cl < clSize * 2; cl += 2) { 3724 pts[c++] = closure[cl]; 3725 pts[c++] = closure[cl + 1]; 3726 } 3727 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3728 for (cl = 0; cl < clSize * 2; cl += 2) { 3729 pts[c++] = closure[cl]; 3730 pts[c++] = closure[cl + 1]; 3731 } 3732 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3733 for (d = 2; d < coneSize; ++d) { 3734 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3735 pts[c++] = cone[arr[d * 2 + 0]]; 3736 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3737 } 3738 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, point, PETSC_TRUE, &coneSize, &cone, &ornt)); 3739 if (dim >= 3) { 3740 for (d = 2; d < coneSize; ++d) { 3741 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3742 const PetscInt *fcone, *fornt; 3743 PetscInt fconeSize, fc, i; 3744 3745 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3746 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3747 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3748 for (fc = 0; fc < fconeSize; ++fc) { 3749 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3750 const PetscInt co = farr[fc * 2 + 1]; 3751 3752 for (i = 0; i < c; i += 2) 3753 if (pts[i] == cp) break; 3754 if (i == c) { 3755 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3756 pts[c++] = cp; 3757 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3758 } 3759 } 3760 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, fpoint, PETSC_TRUE, &fconeSize, &fcone, &fornt)); 3761 } 3762 } 3763 *numPoints = c / 2; 3764 *points = pts; 3765 PetscFunctionReturn(PETSC_SUCCESS); 3766 } 3767 3768 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3769 { 3770 DMPolytopeType ct; 3771 PetscInt *closure, *fifo; 3772 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3773 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3774 PetscInt depth, maxSize; 3775 3776 PetscFunctionBeginHot; 3777 PetscCall(DMPlexGetDepth(dm, &depth)); 3778 if (depth == 1) { 3779 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3780 PetscFunctionReturn(PETSC_SUCCESS); 3781 } 3782 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3783 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3784 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3785 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3786 PetscFunctionReturn(PETSC_SUCCESS); 3787 } 3788 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3789 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3790 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3791 maxSize = PetscMax(coneSeries, supportSeries); 3792 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3793 if (*points) { 3794 closure = *points; 3795 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3796 closure[closureSize++] = p; 3797 closure[closureSize++] = ornt; 3798 fifo[fifoSize++] = p; 3799 fifo[fifoSize++] = ornt; 3800 fifo[fifoSize++] = ct; 3801 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3802 while (fifoSize - fifoStart) { 3803 const PetscInt q = fifo[fifoStart++]; 3804 const PetscInt o = fifo[fifoStart++]; 3805 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3806 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3807 const PetscInt *tmp, *tmpO = NULL; 3808 PetscInt tmpSize, t; 3809 3810 if (PetscDefined(USE_DEBUG)) { 3811 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3812 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); 3813 } 3814 PetscCall(DMPlexGetTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3815 for (t = 0; t < tmpSize; ++t) { 3816 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3817 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3818 const PetscInt cp = tmp[ip]; 3819 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3820 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3821 PetscInt c; 3822 3823 /* Check for duplicate */ 3824 for (c = 0; c < closureSize; c += 2) { 3825 if (closure[c] == cp) break; 3826 } 3827 if (c == closureSize) { 3828 closure[closureSize++] = cp; 3829 closure[closureSize++] = co; 3830 fifo[fifoSize++] = cp; 3831 fifo[fifoSize++] = co; 3832 fifo[fifoSize++] = ct; 3833 } 3834 } 3835 PetscCall(DMPlexRestoreTransitiveClosure_Hot_Private(dm, q, useCone, &tmpSize, &tmp, &tmpO)); 3836 } 3837 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3838 if (numPoints) *numPoints = closureSize / 2; 3839 if (points) *points = closure; 3840 PetscFunctionReturn(PETSC_SUCCESS); 3841 } 3842 3843 /*@C 3844 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3845 3846 Not Collective 3847 3848 Input Parameters: 3849 + dm - The `DMPLEX` 3850 . p - The mesh point 3851 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3852 3853 Input/Output Parameter: 3854 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3855 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 3856 3857 Output Parameter: 3858 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3859 3860 Level: beginner 3861 3862 Note: 3863 If using internal storage (points is `NULL` on input), each call overwrites the last output. 3864 3865 Fortran Notes: 3866 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 3867 3868 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3869 @*/ 3870 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3871 { 3872 PetscFunctionBeginHot; 3873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3874 if (numPoints) PetscAssertPointer(numPoints, 4); 3875 if (points) PetscAssertPointer(points, 5); 3876 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3877 PetscFunctionReturn(PETSC_SUCCESS); 3878 } 3879 3880 /*@C 3881 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3882 3883 Not Collective 3884 3885 Input Parameters: 3886 + dm - The `DMPLEX` 3887 . p - The mesh point 3888 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3889 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3890 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3891 3892 Level: beginner 3893 3894 Note: 3895 If not using internal storage (points is not `NULL` on input), this call is unnecessary 3896 3897 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3898 @*/ 3899 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3900 { 3901 PetscFunctionBeginHot; 3902 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3903 if (numPoints) *numPoints = 0; 3904 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3905 PetscFunctionReturn(PETSC_SUCCESS); 3906 } 3907 3908 /*@ 3909 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3910 3911 Not Collective 3912 3913 Input Parameter: 3914 . dm - The `DMPLEX` 3915 3916 Output Parameters: 3917 + maxConeSize - The maximum number of in-edges 3918 - maxSupportSize - The maximum number of out-edges 3919 3920 Level: beginner 3921 3922 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3923 @*/ 3924 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3925 { 3926 DM_Plex *mesh = (DM_Plex *)dm->data; 3927 3928 PetscFunctionBegin; 3929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3930 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3931 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3932 PetscFunctionReturn(PETSC_SUCCESS); 3933 } 3934 3935 PetscErrorCode DMSetUp_Plex(DM dm) 3936 { 3937 DM_Plex *mesh = (DM_Plex *)dm->data; 3938 PetscInt size, maxSupportSize; 3939 3940 PetscFunctionBegin; 3941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3942 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3943 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3944 PetscCall(PetscMalloc1(size, &mesh->cones)); 3945 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3946 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3947 if (maxSupportSize) { 3948 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3949 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3950 PetscCall(PetscMalloc1(size, &mesh->supports)); 3951 } 3952 PetscFunctionReturn(PETSC_SUCCESS); 3953 } 3954 3955 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3956 { 3957 PetscFunctionBegin; 3958 if (subdm) PetscCall(DMClone(dm, subdm)); 3959 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3960 if (subdm) (*subdm)->useNatural = dm->useNatural; 3961 if (dm->useNatural && dm->sfMigration) { 3962 PetscSF sfNatural; 3963 3964 (*subdm)->sfMigration = dm->sfMigration; 3965 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3966 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3967 (*subdm)->sfNatural = sfNatural; 3968 } 3969 PetscFunctionReturn(PETSC_SUCCESS); 3970 } 3971 3972 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3973 { 3974 PetscInt i = 0; 3975 3976 PetscFunctionBegin; 3977 PetscCall(DMClone(dms[0], superdm)); 3978 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3979 (*superdm)->useNatural = PETSC_FALSE; 3980 for (i = 0; i < len; i++) { 3981 if (dms[i]->useNatural && dms[i]->sfMigration) { 3982 PetscSF sfNatural; 3983 3984 (*superdm)->sfMigration = dms[i]->sfMigration; 3985 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3986 (*superdm)->useNatural = PETSC_TRUE; 3987 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3988 (*superdm)->sfNatural = sfNatural; 3989 break; 3990 } 3991 } 3992 PetscFunctionReturn(PETSC_SUCCESS); 3993 } 3994 3995 /*@ 3996 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3997 3998 Not Collective 3999 4000 Input Parameter: 4001 . dm - The `DMPLEX` 4002 4003 Level: beginner 4004 4005 Note: 4006 This should be called after all calls to `DMPlexSetCone()` 4007 4008 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 4009 @*/ 4010 PetscErrorCode DMPlexSymmetrize(DM dm) 4011 { 4012 DM_Plex *mesh = (DM_Plex *)dm->data; 4013 PetscInt *offsets; 4014 PetscInt supportSize; 4015 PetscInt pStart, pEnd, p; 4016 4017 PetscFunctionBegin; 4018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4019 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 4020 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4021 /* Calculate support sizes */ 4022 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4023 for (p = pStart; p < pEnd; ++p) { 4024 PetscInt dof, off, c; 4025 4026 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4027 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4028 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4029 } 4030 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4031 /* Calculate supports */ 4032 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4033 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4034 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4035 for (p = pStart; p < pEnd; ++p) { 4036 PetscInt dof, off, c; 4037 4038 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4039 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4040 for (c = off; c < off + dof; ++c) { 4041 const PetscInt q = mesh->cones[c]; 4042 PetscInt offS; 4043 4044 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4045 4046 mesh->supports[offS + offsets[q]] = p; 4047 ++offsets[q]; 4048 } 4049 } 4050 PetscCall(PetscFree(offsets)); 4051 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4052 PetscFunctionReturn(PETSC_SUCCESS); 4053 } 4054 4055 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4056 { 4057 IS stratumIS; 4058 4059 PetscFunctionBegin; 4060 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4061 if (PetscDefined(USE_DEBUG)) { 4062 PetscInt qStart, qEnd, numLevels, level; 4063 PetscBool overlap = PETSC_FALSE; 4064 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4065 for (level = 0; level < numLevels; level++) { 4066 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4067 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4068 overlap = PETSC_TRUE; 4069 break; 4070 } 4071 } 4072 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); 4073 } 4074 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4075 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4076 PetscCall(ISDestroy(&stratumIS)); 4077 PetscFunctionReturn(PETSC_SUCCESS); 4078 } 4079 4080 /*@ 4081 DMPlexStratify - Computes the strata for all points in the `DMPLEX` 4082 4083 Collective 4084 4085 Input Parameter: 4086 . dm - The `DMPLEX` 4087 4088 Level: beginner 4089 4090 Notes: 4091 The strata group all points of the same grade, and this function calculates the strata. This 4092 grade can be seen as the height (or depth) of the point in the DAG. 4093 4094 The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4095 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). 4096 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4097 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4098 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4099 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4100 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4101 4102 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4103 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4104 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 4105 to interpolate only that one (e0), so that 4106 .vb 4107 cone(c0) = {e0, v2} 4108 cone(e0) = {v0, v1} 4109 .ve 4110 If `DMPlexStratify()` is run on this mesh, it will give depths 4111 .vb 4112 depth 0 = {v0, v1, v2} 4113 depth 1 = {e0, c0} 4114 .ve 4115 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4116 4117 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4118 4119 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4120 @*/ 4121 PetscErrorCode DMPlexStratify(DM dm) 4122 { 4123 DM_Plex *mesh = (DM_Plex *)dm->data; 4124 DMLabel label; 4125 PetscInt pStart, pEnd, p; 4126 PetscInt numRoots = 0, numLeaves = 0; 4127 4128 PetscFunctionBegin; 4129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4130 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4131 4132 /* Create depth label */ 4133 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4134 PetscCall(DMCreateLabel(dm, "depth")); 4135 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4136 4137 { 4138 /* Initialize roots and count leaves */ 4139 PetscInt sMin = PETSC_MAX_INT; 4140 PetscInt sMax = PETSC_MIN_INT; 4141 PetscInt coneSize, supportSize; 4142 4143 for (p = pStart; p < pEnd; ++p) { 4144 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4145 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4146 if (!coneSize && supportSize) { 4147 sMin = PetscMin(p, sMin); 4148 sMax = PetscMax(p, sMax); 4149 ++numRoots; 4150 } else if (!supportSize && coneSize) { 4151 ++numLeaves; 4152 } else if (!supportSize && !coneSize) { 4153 /* Isolated points */ 4154 sMin = PetscMin(p, sMin); 4155 sMax = PetscMax(p, sMax); 4156 } 4157 } 4158 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4159 } 4160 4161 if (numRoots + numLeaves == (pEnd - pStart)) { 4162 PetscInt sMin = PETSC_MAX_INT; 4163 PetscInt sMax = PETSC_MIN_INT; 4164 PetscInt coneSize, supportSize; 4165 4166 for (p = pStart; p < pEnd; ++p) { 4167 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4168 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4169 if (!supportSize && coneSize) { 4170 sMin = PetscMin(p, sMin); 4171 sMax = PetscMax(p, sMax); 4172 } 4173 } 4174 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4175 } else { 4176 PetscInt level = 0; 4177 PetscInt qStart, qEnd, q; 4178 4179 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4180 while (qEnd > qStart) { 4181 PetscInt sMin = PETSC_MAX_INT; 4182 PetscInt sMax = PETSC_MIN_INT; 4183 4184 for (q = qStart; q < qEnd; ++q) { 4185 const PetscInt *support; 4186 PetscInt supportSize, s; 4187 4188 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4189 PetscCall(DMPlexGetSupport(dm, q, &support)); 4190 for (s = 0; s < supportSize; ++s) { 4191 sMin = PetscMin(support[s], sMin); 4192 sMax = PetscMax(support[s], sMax); 4193 } 4194 } 4195 PetscCall(DMLabelGetNumValues(label, &level)); 4196 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4197 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4198 } 4199 } 4200 { /* just in case there is an empty process */ 4201 PetscInt numValues, maxValues = 0, v; 4202 4203 PetscCall(DMLabelGetNumValues(label, &numValues)); 4204 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4205 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4206 } 4207 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4208 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4209 PetscFunctionReturn(PETSC_SUCCESS); 4210 } 4211 4212 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4213 { 4214 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4215 PetscInt dim, depth, pheight, coneSize; 4216 4217 PetscFunctionBeginHot; 4218 PetscCall(DMGetDimension(dm, &dim)); 4219 PetscCall(DMPlexGetDepth(dm, &depth)); 4220 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4221 pheight = depth - pdepth; 4222 if (depth <= 1) { 4223 switch (pdepth) { 4224 case 0: 4225 ct = DM_POLYTOPE_POINT; 4226 break; 4227 case 1: 4228 switch (coneSize) { 4229 case 2: 4230 ct = DM_POLYTOPE_SEGMENT; 4231 break; 4232 case 3: 4233 ct = DM_POLYTOPE_TRIANGLE; 4234 break; 4235 case 4: 4236 switch (dim) { 4237 case 2: 4238 ct = DM_POLYTOPE_QUADRILATERAL; 4239 break; 4240 case 3: 4241 ct = DM_POLYTOPE_TETRAHEDRON; 4242 break; 4243 default: 4244 break; 4245 } 4246 break; 4247 case 5: 4248 ct = DM_POLYTOPE_PYRAMID; 4249 break; 4250 case 6: 4251 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4252 break; 4253 case 8: 4254 ct = DM_POLYTOPE_HEXAHEDRON; 4255 break; 4256 default: 4257 break; 4258 } 4259 } 4260 } else { 4261 if (pdepth == 0) { 4262 ct = DM_POLYTOPE_POINT; 4263 } else if (pheight == 0) { 4264 switch (dim) { 4265 case 1: 4266 switch (coneSize) { 4267 case 2: 4268 ct = DM_POLYTOPE_SEGMENT; 4269 break; 4270 default: 4271 break; 4272 } 4273 break; 4274 case 2: 4275 switch (coneSize) { 4276 case 3: 4277 ct = DM_POLYTOPE_TRIANGLE; 4278 break; 4279 case 4: 4280 ct = DM_POLYTOPE_QUADRILATERAL; 4281 break; 4282 default: 4283 break; 4284 } 4285 break; 4286 case 3: 4287 switch (coneSize) { 4288 case 4: 4289 ct = DM_POLYTOPE_TETRAHEDRON; 4290 break; 4291 case 5: { 4292 const PetscInt *cone; 4293 PetscInt faceConeSize; 4294 4295 PetscCall(DMPlexGetCone(dm, p, &cone)); 4296 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4297 switch (faceConeSize) { 4298 case 3: 4299 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4300 break; 4301 case 4: 4302 ct = DM_POLYTOPE_PYRAMID; 4303 break; 4304 } 4305 } break; 4306 case 6: 4307 ct = DM_POLYTOPE_HEXAHEDRON; 4308 break; 4309 default: 4310 break; 4311 } 4312 break; 4313 default: 4314 break; 4315 } 4316 } else if (pheight > 0) { 4317 switch (coneSize) { 4318 case 2: 4319 ct = DM_POLYTOPE_SEGMENT; 4320 break; 4321 case 3: 4322 ct = DM_POLYTOPE_TRIANGLE; 4323 break; 4324 case 4: 4325 ct = DM_POLYTOPE_QUADRILATERAL; 4326 break; 4327 default: 4328 break; 4329 } 4330 } 4331 } 4332 *pt = ct; 4333 PetscFunctionReturn(PETSC_SUCCESS); 4334 } 4335 4336 /*@ 4337 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4338 4339 Collective 4340 4341 Input Parameter: 4342 . dm - The `DMPLEX` 4343 4344 Level: developer 4345 4346 Note: 4347 This function is normally called automatically when a cell type is requested. It creates an 4348 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4349 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4350 4351 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4352 4353 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4354 @*/ 4355 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4356 { 4357 DM_Plex *mesh; 4358 DMLabel ctLabel; 4359 PetscInt pStart, pEnd, p; 4360 4361 PetscFunctionBegin; 4362 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4363 mesh = (DM_Plex *)dm->data; 4364 PetscCall(DMCreateLabel(dm, "celltype")); 4365 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4366 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4367 PetscCall(PetscFree(mesh->cellTypes)); 4368 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4369 for (p = pStart; p < pEnd; ++p) { 4370 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4371 PetscInt pdepth; 4372 4373 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4374 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4375 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4376 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4377 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4378 } 4379 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4380 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4381 PetscFunctionReturn(PETSC_SUCCESS); 4382 } 4383 4384 /*@C 4385 DMPlexGetJoin - Get an array for the join of the set of points 4386 4387 Not Collective 4388 4389 Input Parameters: 4390 + dm - The `DMPLEX` object 4391 . numPoints - The number of input points for the join 4392 - points - The input points 4393 4394 Output Parameters: 4395 + numCoveredPoints - The number of points in the join 4396 - coveredPoints - The points in the join 4397 4398 Level: intermediate 4399 4400 Note: 4401 Currently, this is restricted to a single level join 4402 4403 Fortran Notes: 4404 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4405 4406 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4407 @*/ 4408 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4409 { 4410 DM_Plex *mesh = (DM_Plex *)dm->data; 4411 PetscInt *join[2]; 4412 PetscInt joinSize, i = 0; 4413 PetscInt dof, off, p, c, m; 4414 PetscInt maxSupportSize; 4415 4416 PetscFunctionBegin; 4417 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4418 PetscAssertPointer(points, 3); 4419 PetscAssertPointer(numCoveredPoints, 4); 4420 PetscAssertPointer(coveredPoints, 5); 4421 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4422 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4423 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4424 /* Copy in support of first point */ 4425 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4426 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4427 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4428 /* Check each successive support */ 4429 for (p = 1; p < numPoints; ++p) { 4430 PetscInt newJoinSize = 0; 4431 4432 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4433 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4434 for (c = 0; c < dof; ++c) { 4435 const PetscInt point = mesh->supports[off + c]; 4436 4437 for (m = 0; m < joinSize; ++m) { 4438 if (point == join[i][m]) { 4439 join[1 - i][newJoinSize++] = point; 4440 break; 4441 } 4442 } 4443 } 4444 joinSize = newJoinSize; 4445 i = 1 - i; 4446 } 4447 *numCoveredPoints = joinSize; 4448 *coveredPoints = join[i]; 4449 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4450 PetscFunctionReturn(PETSC_SUCCESS); 4451 } 4452 4453 /*@C 4454 DMPlexRestoreJoin - Restore an array for the join of the set of points 4455 4456 Not Collective 4457 4458 Input Parameters: 4459 + dm - The `DMPLEX` object 4460 . numPoints - The number of input points for the join 4461 - points - The input points 4462 4463 Output Parameters: 4464 + numCoveredPoints - The number of points in the join 4465 - coveredPoints - The points in the join 4466 4467 Level: intermediate 4468 4469 Fortran Notes: 4470 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4471 4472 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4473 @*/ 4474 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4475 { 4476 PetscFunctionBegin; 4477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4478 if (points) PetscAssertPointer(points, 3); 4479 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4480 PetscAssertPointer(coveredPoints, 5); 4481 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4482 if (numCoveredPoints) *numCoveredPoints = 0; 4483 PetscFunctionReturn(PETSC_SUCCESS); 4484 } 4485 4486 /*@C 4487 DMPlexGetFullJoin - Get an array for the join of the set of points 4488 4489 Not Collective 4490 4491 Input Parameters: 4492 + dm - The `DMPLEX` object 4493 . numPoints - The number of input points for the join 4494 - points - The input points 4495 4496 Output Parameters: 4497 + numCoveredPoints - The number of points in the join 4498 - coveredPoints - The points in the join 4499 4500 Level: intermediate 4501 4502 Fortran Notes: 4503 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4504 4505 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4506 @*/ 4507 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4508 { 4509 PetscInt *offsets, **closures; 4510 PetscInt *join[2]; 4511 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4512 PetscInt p, d, c, m, ms; 4513 4514 PetscFunctionBegin; 4515 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4516 PetscAssertPointer(points, 3); 4517 PetscAssertPointer(numCoveredPoints, 4); 4518 PetscAssertPointer(coveredPoints, 5); 4519 4520 PetscCall(DMPlexGetDepth(dm, &depth)); 4521 PetscCall(PetscCalloc1(numPoints, &closures)); 4522 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4523 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4524 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4525 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4526 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4527 4528 for (p = 0; p < numPoints; ++p) { 4529 PetscInt closureSize; 4530 4531 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4532 4533 offsets[p * (depth + 2) + 0] = 0; 4534 for (d = 0; d < depth + 1; ++d) { 4535 PetscInt pStart, pEnd, i; 4536 4537 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4538 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4539 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4540 offsets[p * (depth + 2) + d + 1] = i; 4541 break; 4542 } 4543 } 4544 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4545 } 4546 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); 4547 } 4548 for (d = 0; d < depth + 1; ++d) { 4549 PetscInt dof; 4550 4551 /* Copy in support of first point */ 4552 dof = offsets[d + 1] - offsets[d]; 4553 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4554 /* Check each successive cone */ 4555 for (p = 1; p < numPoints && joinSize; ++p) { 4556 PetscInt newJoinSize = 0; 4557 4558 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4559 for (c = 0; c < dof; ++c) { 4560 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4561 4562 for (m = 0; m < joinSize; ++m) { 4563 if (point == join[i][m]) { 4564 join[1 - i][newJoinSize++] = point; 4565 break; 4566 } 4567 } 4568 } 4569 joinSize = newJoinSize; 4570 i = 1 - i; 4571 } 4572 if (joinSize) break; 4573 } 4574 *numCoveredPoints = joinSize; 4575 *coveredPoints = join[i]; 4576 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4577 PetscCall(PetscFree(closures)); 4578 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4579 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4580 PetscFunctionReturn(PETSC_SUCCESS); 4581 } 4582 4583 /*@C 4584 DMPlexGetMeet - Get an array for the meet of the set of points 4585 4586 Not Collective 4587 4588 Input Parameters: 4589 + dm - The `DMPLEX` object 4590 . numPoints - The number of input points for the meet 4591 - points - The input points 4592 4593 Output Parameters: 4594 + numCoveringPoints - The number of points in the meet 4595 - coveringPoints - The points in the meet 4596 4597 Level: intermediate 4598 4599 Note: 4600 Currently, this is restricted to a single level meet 4601 4602 Fortran Notes: 4603 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4604 4605 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4606 @*/ 4607 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4608 { 4609 DM_Plex *mesh = (DM_Plex *)dm->data; 4610 PetscInt *meet[2]; 4611 PetscInt meetSize, i = 0; 4612 PetscInt dof, off, p, c, m; 4613 PetscInt maxConeSize; 4614 4615 PetscFunctionBegin; 4616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4617 PetscAssertPointer(points, 3); 4618 PetscAssertPointer(numCoveringPoints, 4); 4619 PetscAssertPointer(coveringPoints, 5); 4620 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4621 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4622 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4623 /* Copy in cone of first point */ 4624 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4625 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4626 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4627 /* Check each successive cone */ 4628 for (p = 1; p < numPoints; ++p) { 4629 PetscInt newMeetSize = 0; 4630 4631 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4632 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4633 for (c = 0; c < dof; ++c) { 4634 const PetscInt point = mesh->cones[off + c]; 4635 4636 for (m = 0; m < meetSize; ++m) { 4637 if (point == meet[i][m]) { 4638 meet[1 - i][newMeetSize++] = point; 4639 break; 4640 } 4641 } 4642 } 4643 meetSize = newMeetSize; 4644 i = 1 - i; 4645 } 4646 *numCoveringPoints = meetSize; 4647 *coveringPoints = meet[i]; 4648 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4649 PetscFunctionReturn(PETSC_SUCCESS); 4650 } 4651 4652 /*@C 4653 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4654 4655 Not Collective 4656 4657 Input Parameters: 4658 + dm - The `DMPLEX` object 4659 . numPoints - The number of input points for the meet 4660 - points - The input points 4661 4662 Output Parameters: 4663 + numCoveredPoints - The number of points in the meet 4664 - coveredPoints - The points in the meet 4665 4666 Level: intermediate 4667 4668 Fortran Notes: 4669 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4670 4671 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4672 @*/ 4673 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4674 { 4675 PetscFunctionBegin; 4676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4677 if (points) PetscAssertPointer(points, 3); 4678 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4679 PetscAssertPointer(coveredPoints, 5); 4680 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4681 if (numCoveredPoints) *numCoveredPoints = 0; 4682 PetscFunctionReturn(PETSC_SUCCESS); 4683 } 4684 4685 /*@C 4686 DMPlexGetFullMeet - Get an array for the meet of the set of points 4687 4688 Not Collective 4689 4690 Input Parameters: 4691 + dm - The `DMPLEX` object 4692 . numPoints - The number of input points for the meet 4693 - points - The input points 4694 4695 Output Parameters: 4696 + numCoveredPoints - The number of points in the meet 4697 - coveredPoints - The points in the meet 4698 4699 Level: intermediate 4700 4701 Fortran Notes: 4702 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4703 4704 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4705 @*/ 4706 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4707 { 4708 PetscInt *offsets, **closures; 4709 PetscInt *meet[2]; 4710 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4711 PetscInt p, h, c, m, mc; 4712 4713 PetscFunctionBegin; 4714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4715 PetscAssertPointer(points, 3); 4716 PetscAssertPointer(numCoveredPoints, 4); 4717 PetscAssertPointer(coveredPoints, 5); 4718 4719 PetscCall(DMPlexGetDepth(dm, &height)); 4720 PetscCall(PetscMalloc1(numPoints, &closures)); 4721 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4722 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4723 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4724 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4725 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4726 4727 for (p = 0; p < numPoints; ++p) { 4728 PetscInt closureSize; 4729 4730 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4731 4732 offsets[p * (height + 2) + 0] = 0; 4733 for (h = 0; h < height + 1; ++h) { 4734 PetscInt pStart, pEnd, i; 4735 4736 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4737 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4738 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4739 offsets[p * (height + 2) + h + 1] = i; 4740 break; 4741 } 4742 } 4743 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4744 } 4745 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); 4746 } 4747 for (h = 0; h < height + 1; ++h) { 4748 PetscInt dof; 4749 4750 /* Copy in cone of first point */ 4751 dof = offsets[h + 1] - offsets[h]; 4752 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4753 /* Check each successive cone */ 4754 for (p = 1; p < numPoints && meetSize; ++p) { 4755 PetscInt newMeetSize = 0; 4756 4757 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4758 for (c = 0; c < dof; ++c) { 4759 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4760 4761 for (m = 0; m < meetSize; ++m) { 4762 if (point == meet[i][m]) { 4763 meet[1 - i][newMeetSize++] = point; 4764 break; 4765 } 4766 } 4767 } 4768 meetSize = newMeetSize; 4769 i = 1 - i; 4770 } 4771 if (meetSize) break; 4772 } 4773 *numCoveredPoints = meetSize; 4774 *coveredPoints = meet[i]; 4775 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4776 PetscCall(PetscFree(closures)); 4777 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4778 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4779 PetscFunctionReturn(PETSC_SUCCESS); 4780 } 4781 4782 /*@C 4783 DMPlexEqual - Determine if two `DM` have the same topology 4784 4785 Not Collective 4786 4787 Input Parameters: 4788 + dmA - A `DMPLEX` object 4789 - dmB - A `DMPLEX` object 4790 4791 Output Parameter: 4792 . equal - `PETSC_TRUE` if the topologies are identical 4793 4794 Level: intermediate 4795 4796 Note: 4797 We are not solving graph isomorphism, so we do not permute. 4798 4799 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4800 @*/ 4801 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4802 { 4803 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4804 4805 PetscFunctionBegin; 4806 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4807 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4808 PetscAssertPointer(equal, 3); 4809 4810 *equal = PETSC_FALSE; 4811 PetscCall(DMPlexGetDepth(dmA, &depth)); 4812 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4813 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4814 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4815 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4816 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4817 for (p = pStart; p < pEnd; ++p) { 4818 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4819 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4820 4821 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4822 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4823 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4824 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4825 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4826 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4827 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4828 for (c = 0; c < coneSize; ++c) { 4829 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4830 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4831 } 4832 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4833 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4834 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4835 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4836 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4837 for (s = 0; s < supportSize; ++s) { 4838 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4839 } 4840 } 4841 *equal = PETSC_TRUE; 4842 PetscFunctionReturn(PETSC_SUCCESS); 4843 } 4844 4845 /*@C 4846 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4847 4848 Not Collective 4849 4850 Input Parameters: 4851 + dm - The `DMPLEX` 4852 . cellDim - The cell dimension 4853 - numCorners - The number of vertices on a cell 4854 4855 Output Parameter: 4856 . numFaceVertices - The number of vertices on a face 4857 4858 Level: developer 4859 4860 Note: 4861 Of course this can only work for a restricted set of symmetric shapes 4862 4863 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4864 @*/ 4865 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4866 { 4867 MPI_Comm comm; 4868 4869 PetscFunctionBegin; 4870 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4871 PetscAssertPointer(numFaceVertices, 4); 4872 switch (cellDim) { 4873 case 0: 4874 *numFaceVertices = 0; 4875 break; 4876 case 1: 4877 *numFaceVertices = 1; 4878 break; 4879 case 2: 4880 switch (numCorners) { 4881 case 3: /* triangle */ 4882 *numFaceVertices = 2; /* Edge has 2 vertices */ 4883 break; 4884 case 4: /* quadrilateral */ 4885 *numFaceVertices = 2; /* Edge has 2 vertices */ 4886 break; 4887 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4888 *numFaceVertices = 3; /* Edge has 3 vertices */ 4889 break; 4890 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4891 *numFaceVertices = 3; /* Edge has 3 vertices */ 4892 break; 4893 default: 4894 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4895 } 4896 break; 4897 case 3: 4898 switch (numCorners) { 4899 case 4: /* tetradehdron */ 4900 *numFaceVertices = 3; /* Face has 3 vertices */ 4901 break; 4902 case 6: /* tet cohesive cells */ 4903 *numFaceVertices = 4; /* Face has 4 vertices */ 4904 break; 4905 case 8: /* hexahedron */ 4906 *numFaceVertices = 4; /* Face has 4 vertices */ 4907 break; 4908 case 9: /* tet cohesive Lagrange cells */ 4909 *numFaceVertices = 6; /* Face has 6 vertices */ 4910 break; 4911 case 10: /* quadratic tetrahedron */ 4912 *numFaceVertices = 6; /* Face has 6 vertices */ 4913 break; 4914 case 12: /* hex cohesive Lagrange cells */ 4915 *numFaceVertices = 6; /* Face has 6 vertices */ 4916 break; 4917 case 18: /* quadratic tet cohesive Lagrange cells */ 4918 *numFaceVertices = 6; /* Face has 6 vertices */ 4919 break; 4920 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4921 *numFaceVertices = 9; /* Face has 9 vertices */ 4922 break; 4923 default: 4924 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4925 } 4926 break; 4927 default: 4928 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4929 } 4930 PetscFunctionReturn(PETSC_SUCCESS); 4931 } 4932 4933 /*@ 4934 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 4935 4936 Not Collective 4937 4938 Input Parameter: 4939 . dm - The `DMPLEX` object 4940 4941 Output Parameter: 4942 . depthLabel - The `DMLabel` recording point depth 4943 4944 Level: developer 4945 4946 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4947 @*/ 4948 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4949 { 4950 PetscFunctionBegin; 4951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4952 PetscAssertPointer(depthLabel, 2); 4953 *depthLabel = dm->depthLabel; 4954 PetscFunctionReturn(PETSC_SUCCESS); 4955 } 4956 4957 /*@ 4958 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4959 4960 Not Collective 4961 4962 Input Parameter: 4963 . dm - The `DMPLEX` object 4964 4965 Output Parameter: 4966 . depth - The number of strata (breadth first levels) in the DAG 4967 4968 Level: developer 4969 4970 Notes: 4971 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 4972 4973 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 4974 4975 An empty mesh gives -1. 4976 4977 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4978 @*/ 4979 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4980 { 4981 DM_Plex *mesh = (DM_Plex *)dm->data; 4982 DMLabel label; 4983 PetscInt d = 0; 4984 4985 PetscFunctionBegin; 4986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4987 PetscAssertPointer(depth, 2); 4988 if (mesh->tr) { 4989 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 4990 } else { 4991 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4992 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4993 *depth = d - 1; 4994 } 4995 PetscFunctionReturn(PETSC_SUCCESS); 4996 } 4997 4998 /*@ 4999 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 5000 5001 Not Collective 5002 5003 Input Parameters: 5004 + dm - The `DMPLEX` object 5005 - depth - The requested depth 5006 5007 Output Parameters: 5008 + start - The first point at this `depth` 5009 - end - One beyond the last point at this `depth` 5010 5011 Level: developer 5012 5013 Notes: 5014 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5015 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5016 higher dimension, e.g., "edges". 5017 5018 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5019 @*/ 5020 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5021 { 5022 DM_Plex *mesh = (DM_Plex *)dm->data; 5023 DMLabel label; 5024 PetscInt pStart, pEnd; 5025 5026 PetscFunctionBegin; 5027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5028 if (start) { 5029 PetscAssertPointer(start, 3); 5030 *start = 0; 5031 } 5032 if (end) { 5033 PetscAssertPointer(end, 4); 5034 *end = 0; 5035 } 5036 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5037 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5038 if (depth < 0) { 5039 if (start) *start = pStart; 5040 if (end) *end = pEnd; 5041 PetscFunctionReturn(PETSC_SUCCESS); 5042 } 5043 if (mesh->tr) { 5044 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5045 } else { 5046 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5047 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5048 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5049 } 5050 PetscFunctionReturn(PETSC_SUCCESS); 5051 } 5052 5053 /*@ 5054 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5055 5056 Not Collective 5057 5058 Input Parameters: 5059 + dm - The `DMPLEX` object 5060 - height - The requested height 5061 5062 Output Parameters: 5063 + start - The first point at this `height` 5064 - end - One beyond the last point at this `height` 5065 5066 Level: developer 5067 5068 Notes: 5069 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5070 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5071 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5072 5073 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5074 @*/ 5075 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5076 { 5077 DMLabel label; 5078 PetscInt depth, pStart, pEnd; 5079 5080 PetscFunctionBegin; 5081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5082 if (start) { 5083 PetscAssertPointer(start, 3); 5084 *start = 0; 5085 } 5086 if (end) { 5087 PetscAssertPointer(end, 4); 5088 *end = 0; 5089 } 5090 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5091 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5092 if (height < 0) { 5093 if (start) *start = pStart; 5094 if (end) *end = pEnd; 5095 PetscFunctionReturn(PETSC_SUCCESS); 5096 } 5097 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5098 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5099 else PetscCall(DMGetDimension(dm, &depth)); 5100 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5101 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5102 PetscFunctionReturn(PETSC_SUCCESS); 5103 } 5104 5105 /*@ 5106 DMPlexGetPointDepth - Get the `depth` of a given point 5107 5108 Not Collective 5109 5110 Input Parameters: 5111 + dm - The `DMPLEX` object 5112 - point - The point 5113 5114 Output Parameter: 5115 . depth - The depth of the `point` 5116 5117 Level: intermediate 5118 5119 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5120 @*/ 5121 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5122 { 5123 PetscFunctionBegin; 5124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5125 PetscAssertPointer(depth, 3); 5126 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5127 PetscFunctionReturn(PETSC_SUCCESS); 5128 } 5129 5130 /*@ 5131 DMPlexGetPointHeight - Get the `height` of a given point 5132 5133 Not Collective 5134 5135 Input Parameters: 5136 + dm - The `DMPLEX` object 5137 - point - The point 5138 5139 Output Parameter: 5140 . height - The height of the `point` 5141 5142 Level: intermediate 5143 5144 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5145 @*/ 5146 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5147 { 5148 PetscInt n, pDepth; 5149 5150 PetscFunctionBegin; 5151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5152 PetscAssertPointer(height, 3); 5153 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5154 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5155 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5156 PetscFunctionReturn(PETSC_SUCCESS); 5157 } 5158 5159 /*@ 5160 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5161 5162 Not Collective 5163 5164 Input Parameter: 5165 . dm - The `DMPLEX` object 5166 5167 Output Parameter: 5168 . celltypeLabel - The `DMLabel` recording cell polytope type 5169 5170 Level: developer 5171 5172 Note: 5173 This function will trigger automatica computation of cell types. This can be disabled by calling 5174 `DMCreateLabel`(dm, "celltype") beforehand. 5175 5176 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5177 @*/ 5178 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5179 { 5180 PetscFunctionBegin; 5181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5182 PetscAssertPointer(celltypeLabel, 2); 5183 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5184 *celltypeLabel = dm->celltypeLabel; 5185 PetscFunctionReturn(PETSC_SUCCESS); 5186 } 5187 5188 /*@ 5189 DMPlexGetCellType - Get the polytope type of a given cell 5190 5191 Not Collective 5192 5193 Input Parameters: 5194 + dm - The `DMPLEX` object 5195 - cell - The cell 5196 5197 Output Parameter: 5198 . celltype - The polytope type of the cell 5199 5200 Level: intermediate 5201 5202 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5203 @*/ 5204 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5205 { 5206 DM_Plex *mesh = (DM_Plex *)dm->data; 5207 DMLabel label; 5208 PetscInt ct; 5209 5210 PetscFunctionBegin; 5211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5212 PetscAssertPointer(celltype, 3); 5213 if (mesh->tr) { 5214 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5215 } else { 5216 PetscInt pStart, pEnd; 5217 5218 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5219 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5220 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5221 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5222 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5223 for (PetscInt p = pStart; p < pEnd; p++) { 5224 PetscCall(DMLabelGetValue(label, p, &ct)); 5225 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5226 } 5227 } 5228 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5229 if (PetscDefined(USE_DEBUG)) { 5230 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5231 PetscCall(DMLabelGetValue(label, cell, &ct)); 5232 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5233 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5234 } 5235 } 5236 PetscFunctionReturn(PETSC_SUCCESS); 5237 } 5238 5239 /*@ 5240 DMPlexSetCellType - Set the polytope type of a given cell 5241 5242 Not Collective 5243 5244 Input Parameters: 5245 + dm - The `DMPLEX` object 5246 . cell - The cell 5247 - celltype - The polytope type of the cell 5248 5249 Level: advanced 5250 5251 Note: 5252 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5253 is executed. This function will override the computed type. However, if automatic classification will not succeed 5254 and a user wants to manually specify all types, the classification must be disabled by calling 5255 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5256 5257 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5258 @*/ 5259 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5260 { 5261 DM_Plex *mesh = (DM_Plex *)dm->data; 5262 DMLabel label; 5263 PetscInt pStart, pEnd; 5264 5265 PetscFunctionBegin; 5266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5267 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5268 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5269 PetscCall(DMLabelSetValue(label, cell, celltype)); 5270 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5271 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5272 PetscFunctionReturn(PETSC_SUCCESS); 5273 } 5274 5275 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5276 { 5277 PetscSection section, s; 5278 Mat m; 5279 PetscInt maxHeight; 5280 const char *prefix; 5281 5282 PetscFunctionBegin; 5283 PetscCall(DMClone(dm, cdm)); 5284 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5285 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5286 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5287 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5288 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5289 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5290 PetscCall(DMSetLocalSection(*cdm, section)); 5291 PetscCall(PetscSectionDestroy(§ion)); 5292 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5293 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5294 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5295 PetscCall(PetscSectionDestroy(&s)); 5296 PetscCall(MatDestroy(&m)); 5297 5298 PetscCall(DMSetNumFields(*cdm, 1)); 5299 PetscCall(DMCreateDS(*cdm)); 5300 (*cdm)->cloneOpts = PETSC_TRUE; 5301 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5302 PetscFunctionReturn(PETSC_SUCCESS); 5303 } 5304 5305 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5306 { 5307 Vec coordsLocal, cellCoordsLocal; 5308 DM coordsDM, cellCoordsDM; 5309 5310 PetscFunctionBegin; 5311 *field = NULL; 5312 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5313 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5314 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5315 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5316 if (coordsLocal && coordsDM) { 5317 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5318 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5319 } 5320 PetscFunctionReturn(PETSC_SUCCESS); 5321 } 5322 5323 /*@C 5324 DMPlexGetConeSection - Return a section which describes the layout of cone data 5325 5326 Not Collective 5327 5328 Input Parameter: 5329 . dm - The `DMPLEX` object 5330 5331 Output Parameter: 5332 . section - The `PetscSection` object 5333 5334 Level: developer 5335 5336 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5337 @*/ 5338 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5339 { 5340 DM_Plex *mesh = (DM_Plex *)dm->data; 5341 5342 PetscFunctionBegin; 5343 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5344 if (section) *section = mesh->coneSection; 5345 PetscFunctionReturn(PETSC_SUCCESS); 5346 } 5347 5348 /*@C 5349 DMPlexGetSupportSection - Return a section which describes the layout of support data 5350 5351 Not Collective 5352 5353 Input Parameter: 5354 . dm - The `DMPLEX` object 5355 5356 Output Parameter: 5357 . section - The `PetscSection` object 5358 5359 Level: developer 5360 5361 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5362 @*/ 5363 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5364 { 5365 DM_Plex *mesh = (DM_Plex *)dm->data; 5366 5367 PetscFunctionBegin; 5368 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5369 if (section) *section = mesh->supportSection; 5370 PetscFunctionReturn(PETSC_SUCCESS); 5371 } 5372 5373 /*@C 5374 DMPlexGetCones - Return cone data 5375 5376 Not Collective 5377 5378 Input Parameter: 5379 . dm - The `DMPLEX` object 5380 5381 Output Parameter: 5382 . cones - The cone for each point 5383 5384 Level: developer 5385 5386 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5387 @*/ 5388 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5389 { 5390 DM_Plex *mesh = (DM_Plex *)dm->data; 5391 5392 PetscFunctionBegin; 5393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5394 if (cones) *cones = mesh->cones; 5395 PetscFunctionReturn(PETSC_SUCCESS); 5396 } 5397 5398 /*@C 5399 DMPlexGetConeOrientations - Return cone orientation data 5400 5401 Not Collective 5402 5403 Input Parameter: 5404 . dm - The `DMPLEX` object 5405 5406 Output Parameter: 5407 . coneOrientations - The array of cone orientations for all points 5408 5409 Level: developer 5410 5411 Notes: 5412 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5413 5414 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5415 5416 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5417 @*/ 5418 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5419 { 5420 DM_Plex *mesh = (DM_Plex *)dm->data; 5421 5422 PetscFunctionBegin; 5423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5424 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5425 PetscFunctionReturn(PETSC_SUCCESS); 5426 } 5427 5428 /******************************** FEM Support **********************************/ 5429 5430 /* 5431 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5432 representing a line in the section. 5433 */ 5434 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5435 { 5436 PetscFunctionBeginHot; 5437 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5438 if (line < 0) { 5439 *k = 0; 5440 *Nc = 0; 5441 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5442 *k = 1; 5443 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5444 /* An order k SEM disc has k-1 dofs on an edge */ 5445 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5446 *k = *k / *Nc + 1; 5447 } 5448 PetscFunctionReturn(PETSC_SUCCESS); 5449 } 5450 5451 /*@ 5452 5453 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5454 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5455 section provided (or the section of the `DM`). 5456 5457 Input Parameters: 5458 + dm - The `DM` 5459 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5460 - section - The `PetscSection` to reorder, or `NULL` for the default section 5461 5462 Example: 5463 A typical interpolated single-quad mesh might order points as 5464 .vb 5465 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5466 5467 v4 -- e6 -- v3 5468 | | 5469 e7 c0 e8 5470 | | 5471 v1 -- e5 -- v2 5472 .ve 5473 5474 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5475 dofs in the order of points, e.g., 5476 .vb 5477 c0 -> [0,1,2,3] 5478 v1 -> [4] 5479 ... 5480 e5 -> [8, 9] 5481 .ve 5482 5483 which corresponds to the dofs 5484 .vb 5485 6 10 11 7 5486 13 2 3 15 5487 12 0 1 14 5488 4 8 9 5 5489 .ve 5490 5491 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5492 .vb 5493 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5494 .ve 5495 5496 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5497 .vb 5498 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5499 .ve 5500 5501 Level: developer 5502 5503 Notes: 5504 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5505 degree of the basis. 5506 5507 This is required to run with libCEED. 5508 5509 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5510 @*/ 5511 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5512 { 5513 DMLabel label; 5514 PetscInt dim, depth = -1, eStart = -1, Nf; 5515 PetscBool vertexchart; 5516 5517 PetscFunctionBegin; 5518 PetscCall(DMGetDimension(dm, &dim)); 5519 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5520 if (point < 0) { 5521 PetscInt sStart, sEnd; 5522 5523 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5524 point = sEnd - sStart ? sStart : point; 5525 } 5526 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5527 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5528 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5529 if (depth == 1) { 5530 eStart = point; 5531 } else if (depth == dim) { 5532 const PetscInt *cone; 5533 5534 PetscCall(DMPlexGetCone(dm, point, &cone)); 5535 if (dim == 2) eStart = cone[0]; 5536 else if (dim == 3) { 5537 const PetscInt *cone2; 5538 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5539 eStart = cone2[0]; 5540 } 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); 5541 } 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); 5542 { /* Determine whether the chart covers all points or just vertices. */ 5543 PetscInt pStart, pEnd, cStart, cEnd; 5544 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5545 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5546 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5547 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5548 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5549 } 5550 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5551 for (PetscInt d = 1; d <= dim; d++) { 5552 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5553 PetscInt *perm; 5554 5555 for (f = 0; f < Nf; ++f) { 5556 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5557 size += PetscPowInt(k + 1, d) * Nc; 5558 } 5559 PetscCall(PetscMalloc1(size, &perm)); 5560 for (f = 0; f < Nf; ++f) { 5561 switch (d) { 5562 case 1: 5563 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5564 /* 5565 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5566 We want [ vtx0; edge of length k-1; vtx1 ] 5567 */ 5568 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5569 for (i = 0; i < k - 1; i++) 5570 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5571 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5572 foffset = offset; 5573 break; 5574 case 2: 5575 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5576 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5577 /* The SEM order is 5578 5579 v_lb, {e_b}, v_rb, 5580 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5581 v_lt, reverse {e_t}, v_rt 5582 */ 5583 { 5584 const PetscInt of = 0; 5585 const PetscInt oeb = of + PetscSqr(k - 1); 5586 const PetscInt oer = oeb + (k - 1); 5587 const PetscInt oet = oer + (k - 1); 5588 const PetscInt oel = oet + (k - 1); 5589 const PetscInt ovlb = oel + (k - 1); 5590 const PetscInt ovrb = ovlb + 1; 5591 const PetscInt ovrt = ovrb + 1; 5592 const PetscInt ovlt = ovrt + 1; 5593 PetscInt o; 5594 5595 /* bottom */ 5596 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5597 for (o = oeb; o < oer; ++o) 5598 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5599 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5600 /* middle */ 5601 for (i = 0; i < k - 1; ++i) { 5602 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5603 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5604 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5605 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5606 } 5607 /* top */ 5608 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5609 for (o = oel - 1; o >= oet; --o) 5610 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5611 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5612 foffset = offset; 5613 } 5614 break; 5615 case 3: 5616 /* The original hex closure is 5617 5618 {c, 5619 f_b, f_t, f_f, f_b, f_r, f_l, 5620 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5621 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5622 */ 5623 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5624 /* The SEM order is 5625 Bottom Slice 5626 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5627 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5628 v_blb, {e_bb}, v_brb, 5629 5630 Middle Slice (j) 5631 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5632 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5633 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5634 5635 Top Slice 5636 v_tlf, {e_tf}, v_trf, 5637 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5638 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5639 */ 5640 { 5641 const PetscInt oc = 0; 5642 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5643 const PetscInt oft = ofb + PetscSqr(k - 1); 5644 const PetscInt off = oft + PetscSqr(k - 1); 5645 const PetscInt ofk = off + PetscSqr(k - 1); 5646 const PetscInt ofr = ofk + PetscSqr(k - 1); 5647 const PetscInt ofl = ofr + PetscSqr(k - 1); 5648 const PetscInt oebl = ofl + PetscSqr(k - 1); 5649 const PetscInt oebb = oebl + (k - 1); 5650 const PetscInt oebr = oebb + (k - 1); 5651 const PetscInt oebf = oebr + (k - 1); 5652 const PetscInt oetf = oebf + (k - 1); 5653 const PetscInt oetr = oetf + (k - 1); 5654 const PetscInt oetb = oetr + (k - 1); 5655 const PetscInt oetl = oetb + (k - 1); 5656 const PetscInt oerf = oetl + (k - 1); 5657 const PetscInt oelf = oerf + (k - 1); 5658 const PetscInt oelb = oelf + (k - 1); 5659 const PetscInt oerb = oelb + (k - 1); 5660 const PetscInt ovblf = oerb + (k - 1); 5661 const PetscInt ovblb = ovblf + 1; 5662 const PetscInt ovbrb = ovblb + 1; 5663 const PetscInt ovbrf = ovbrb + 1; 5664 const PetscInt ovtlf = ovbrf + 1; 5665 const PetscInt ovtrf = ovtlf + 1; 5666 const PetscInt ovtrb = ovtrf + 1; 5667 const PetscInt ovtlb = ovtrb + 1; 5668 PetscInt o, n; 5669 5670 /* Bottom Slice */ 5671 /* bottom */ 5672 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5673 for (o = oetf - 1; o >= oebf; --o) 5674 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5675 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5676 /* middle */ 5677 for (i = 0; i < k - 1; ++i) { 5678 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5679 for (n = 0; n < k - 1; ++n) { 5680 o = ofb + n * (k - 1) + i; 5681 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5682 } 5683 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5684 } 5685 /* top */ 5686 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5687 for (o = oebb; o < oebr; ++o) 5688 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5689 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5690 5691 /* Middle Slice */ 5692 for (j = 0; j < k - 1; ++j) { 5693 /* bottom */ 5694 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5695 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5696 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5697 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5698 /* middle */ 5699 for (i = 0; i < k - 1; ++i) { 5700 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5701 for (n = 0; n < k - 1; ++n) 5702 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5703 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5704 } 5705 /* top */ 5706 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5707 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5708 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5709 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5710 } 5711 5712 /* Top Slice */ 5713 /* bottom */ 5714 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5715 for (o = oetf; o < oetr; ++o) 5716 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5717 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5718 /* middle */ 5719 for (i = 0; i < k - 1; ++i) { 5720 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5721 for (n = 0; n < k - 1; ++n) 5722 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5723 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5724 } 5725 /* top */ 5726 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5727 for (o = oetl - 1; o >= oetb; --o) 5728 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5729 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5730 5731 foffset = offset; 5732 } 5733 break; 5734 default: 5735 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5736 } 5737 } 5738 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5739 /* Check permutation */ 5740 { 5741 PetscInt *check; 5742 5743 PetscCall(PetscMalloc1(size, &check)); 5744 for (i = 0; i < size; ++i) { 5745 check[i] = -1; 5746 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5747 } 5748 for (i = 0; i < size; ++i) check[perm[i]] = i; 5749 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5750 PetscCall(PetscFree(check)); 5751 } 5752 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5753 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5754 PetscInt *loc_perm; 5755 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5756 for (PetscInt i = 0; i < size; i++) { 5757 loc_perm[i] = perm[i]; 5758 loc_perm[size + i] = size + perm[i]; 5759 } 5760 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5761 } 5762 } 5763 PetscFunctionReturn(PETSC_SUCCESS); 5764 } 5765 5766 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5767 { 5768 PetscDS prob; 5769 PetscInt depth, Nf, h; 5770 DMLabel label; 5771 5772 PetscFunctionBeginHot; 5773 PetscCall(DMGetDS(dm, &prob)); 5774 Nf = prob->Nf; 5775 label = dm->depthLabel; 5776 *dspace = NULL; 5777 if (field < Nf) { 5778 PetscObject disc = prob->disc[field]; 5779 5780 if (disc->classid == PETSCFE_CLASSID) { 5781 PetscDualSpace dsp; 5782 5783 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5784 PetscCall(DMLabelGetNumValues(label, &depth)); 5785 PetscCall(DMLabelGetValue(label, point, &h)); 5786 h = depth - 1 - h; 5787 if (h) { 5788 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5789 } else { 5790 *dspace = dsp; 5791 } 5792 } 5793 } 5794 PetscFunctionReturn(PETSC_SUCCESS); 5795 } 5796 5797 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5798 { 5799 PetscScalar *array; 5800 const PetscScalar *vArray; 5801 const PetscInt *cone, *coneO; 5802 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5803 5804 PetscFunctionBeginHot; 5805 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5806 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5807 PetscCall(DMPlexGetCone(dm, point, &cone)); 5808 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5809 if (!values || !*values) { 5810 if ((point >= pStart) && (point < pEnd)) { 5811 PetscInt dof; 5812 5813 PetscCall(PetscSectionGetDof(section, point, &dof)); 5814 size += dof; 5815 } 5816 for (p = 0; p < numPoints; ++p) { 5817 const PetscInt cp = cone[p]; 5818 PetscInt dof; 5819 5820 if ((cp < pStart) || (cp >= pEnd)) continue; 5821 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5822 size += dof; 5823 } 5824 if (!values) { 5825 if (csize) *csize = size; 5826 PetscFunctionReturn(PETSC_SUCCESS); 5827 } 5828 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5829 } else { 5830 array = *values; 5831 } 5832 size = 0; 5833 PetscCall(VecGetArrayRead(v, &vArray)); 5834 if ((point >= pStart) && (point < pEnd)) { 5835 PetscInt dof, off, d; 5836 const PetscScalar *varr; 5837 5838 PetscCall(PetscSectionGetDof(section, point, &dof)); 5839 PetscCall(PetscSectionGetOffset(section, point, &off)); 5840 varr = &vArray[off]; 5841 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5842 size += dof; 5843 } 5844 for (p = 0; p < numPoints; ++p) { 5845 const PetscInt cp = cone[p]; 5846 PetscInt o = coneO[p]; 5847 PetscInt dof, off, d; 5848 const PetscScalar *varr; 5849 5850 if ((cp < pStart) || (cp >= pEnd)) continue; 5851 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5852 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5853 varr = &vArray[off]; 5854 if (o >= 0) { 5855 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5856 } else { 5857 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5858 } 5859 size += dof; 5860 } 5861 PetscCall(VecRestoreArrayRead(v, &vArray)); 5862 if (!*values) { 5863 if (csize) *csize = size; 5864 *values = array; 5865 } else { 5866 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5867 *csize = size; 5868 } 5869 PetscFunctionReturn(PETSC_SUCCESS); 5870 } 5871 5872 /* Compress out points not in the section */ 5873 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5874 { 5875 const PetscInt np = *numPoints; 5876 PetscInt pStart, pEnd, p, q; 5877 5878 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5879 for (p = 0, q = 0; p < np; ++p) { 5880 const PetscInt r = points[p * 2]; 5881 if ((r >= pStart) && (r < pEnd)) { 5882 points[q * 2] = r; 5883 points[q * 2 + 1] = points[p * 2 + 1]; 5884 ++q; 5885 } 5886 } 5887 *numPoints = q; 5888 return PETSC_SUCCESS; 5889 } 5890 5891 /* Compressed closure does not apply closure permutation */ 5892 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5893 { 5894 const PetscInt *cla = NULL; 5895 PetscInt np, *pts = NULL; 5896 5897 PetscFunctionBeginHot; 5898 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5899 if (!ornt && *clPoints) { 5900 PetscInt dof, off; 5901 5902 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5903 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5904 PetscCall(ISGetIndices(*clPoints, &cla)); 5905 np = dof / 2; 5906 pts = (PetscInt *)&cla[off]; 5907 } else { 5908 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 5909 PetscCall(CompressPoints_Private(section, &np, pts)); 5910 } 5911 *numPoints = np; 5912 *points = pts; 5913 *clp = cla; 5914 PetscFunctionReturn(PETSC_SUCCESS); 5915 } 5916 5917 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5918 { 5919 PetscFunctionBeginHot; 5920 if (!*clPoints) { 5921 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5922 } else { 5923 PetscCall(ISRestoreIndices(*clPoints, clp)); 5924 } 5925 *numPoints = 0; 5926 *points = NULL; 5927 *clSec = NULL; 5928 *clPoints = NULL; 5929 *clp = NULL; 5930 PetscFunctionReturn(PETSC_SUCCESS); 5931 } 5932 5933 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5934 { 5935 PetscInt offset = 0, p; 5936 const PetscInt **perms = NULL; 5937 const PetscScalar **flips = NULL; 5938 5939 PetscFunctionBeginHot; 5940 *size = 0; 5941 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5942 for (p = 0; p < numPoints; p++) { 5943 const PetscInt point = points[2 * p]; 5944 const PetscInt *perm = perms ? perms[p] : NULL; 5945 const PetscScalar *flip = flips ? flips[p] : NULL; 5946 PetscInt dof, off, d; 5947 const PetscScalar *varr; 5948 5949 PetscCall(PetscSectionGetDof(section, point, &dof)); 5950 PetscCall(PetscSectionGetOffset(section, point, &off)); 5951 varr = &vArray[off]; 5952 if (clperm) { 5953 if (perm) { 5954 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5955 } else { 5956 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5957 } 5958 if (flip) { 5959 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5960 } 5961 } else { 5962 if (perm) { 5963 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5964 } else { 5965 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5966 } 5967 if (flip) { 5968 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5969 } 5970 } 5971 offset += dof; 5972 } 5973 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5974 *size = offset; 5975 PetscFunctionReturn(PETSC_SUCCESS); 5976 } 5977 5978 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[]) 5979 { 5980 PetscInt offset = 0, f; 5981 5982 PetscFunctionBeginHot; 5983 *size = 0; 5984 for (f = 0; f < numFields; ++f) { 5985 PetscInt p; 5986 const PetscInt **perms = NULL; 5987 const PetscScalar **flips = NULL; 5988 5989 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5990 for (p = 0; p < numPoints; p++) { 5991 const PetscInt point = points[2 * p]; 5992 PetscInt fdof, foff, b; 5993 const PetscScalar *varr; 5994 const PetscInt *perm = perms ? perms[p] : NULL; 5995 const PetscScalar *flip = flips ? flips[p] : NULL; 5996 5997 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5998 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5999 varr = &vArray[foff]; 6000 if (clperm) { 6001 if (perm) { 6002 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6003 } else { 6004 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6005 } 6006 if (flip) { 6007 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6008 } 6009 } else { 6010 if (perm) { 6011 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6012 } else { 6013 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6014 } 6015 if (flip) { 6016 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6017 } 6018 } 6019 offset += fdof; 6020 } 6021 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6022 } 6023 *size = offset; 6024 PetscFunctionReturn(PETSC_SUCCESS); 6025 } 6026 6027 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6028 { 6029 PetscSection clSection; 6030 IS clPoints; 6031 PetscInt *points = NULL; 6032 const PetscInt *clp, *perm; 6033 PetscInt depth, numFields, numPoints, asize; 6034 6035 PetscFunctionBeginHot; 6036 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6037 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6038 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6039 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6040 PetscCall(DMPlexGetDepth(dm, &depth)); 6041 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6042 if (depth == 1 && numFields < 2) { 6043 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6044 PetscFunctionReturn(PETSC_SUCCESS); 6045 } 6046 /* Get points */ 6047 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6048 /* Get sizes */ 6049 asize = 0; 6050 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6051 PetscInt dof; 6052 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6053 asize += dof; 6054 } 6055 if (values) { 6056 const PetscScalar *vArray; 6057 PetscInt size; 6058 6059 if (*values) { 6060 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); 6061 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6062 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6063 PetscCall(VecGetArrayRead(v, &vArray)); 6064 /* Get values */ 6065 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6066 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6067 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6068 /* Cleanup array */ 6069 PetscCall(VecRestoreArrayRead(v, &vArray)); 6070 } 6071 if (csize) *csize = asize; 6072 /* Cleanup points */ 6073 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6074 PetscFunctionReturn(PETSC_SUCCESS); 6075 } 6076 6077 /*@C 6078 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6079 6080 Not collective 6081 6082 Input Parameters: 6083 + dm - The `DM` 6084 . section - The section describing the layout in `v`, or `NULL` to use the default section 6085 . v - The local vector 6086 - point - The point in the `DM` 6087 6088 Input/Output Parameters: 6089 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6090 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6091 if the user provided `NULL`, it is a borrowed array and should not be freed 6092 6093 Level: intermediate 6094 6095 Notes: 6096 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6097 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6098 assembly function, and a user may already have allocated storage for this operation. 6099 6100 A typical use could be 6101 .vb 6102 values = NULL; 6103 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6104 for (cl = 0; cl < clSize; ++cl) { 6105 <Compute on closure> 6106 } 6107 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6108 .ve 6109 or 6110 .vb 6111 PetscMalloc1(clMaxSize, &values); 6112 for (p = pStart; p < pEnd; ++p) { 6113 clSize = clMaxSize; 6114 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6115 for (cl = 0; cl < clSize; ++cl) { 6116 <Compute on closure> 6117 } 6118 } 6119 PetscFree(values); 6120 .ve 6121 6122 Fortran Notes: 6123 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6124 6125 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6126 @*/ 6127 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6128 { 6129 PetscFunctionBeginHot; 6130 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, v, point, 0, csize, values)); 6131 PetscFunctionReturn(PETSC_SUCCESS); 6132 } 6133 6134 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6135 { 6136 DMLabel depthLabel; 6137 PetscSection clSection; 6138 IS clPoints; 6139 PetscScalar *array; 6140 const PetscScalar *vArray; 6141 PetscInt *points = NULL; 6142 const PetscInt *clp, *perm = NULL; 6143 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6144 6145 PetscFunctionBeginHot; 6146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6147 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6148 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6149 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6150 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6151 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6152 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6153 if (mdepth == 1 && numFields < 2) { 6154 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6155 PetscFunctionReturn(PETSC_SUCCESS); 6156 } 6157 /* Get points */ 6158 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6159 for (clsize = 0, p = 0; p < Np; p++) { 6160 PetscInt dof; 6161 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6162 clsize += dof; 6163 } 6164 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6165 /* Filter points */ 6166 for (p = 0; p < numPoints * 2; p += 2) { 6167 PetscInt dep; 6168 6169 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6170 if (dep != depth) continue; 6171 points[Np * 2 + 0] = points[p]; 6172 points[Np * 2 + 1] = points[p + 1]; 6173 ++Np; 6174 } 6175 /* Get array */ 6176 if (!values || !*values) { 6177 PetscInt asize = 0, dof; 6178 6179 for (p = 0; p < Np * 2; p += 2) { 6180 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6181 asize += dof; 6182 } 6183 if (!values) { 6184 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6185 if (csize) *csize = asize; 6186 PetscFunctionReturn(PETSC_SUCCESS); 6187 } 6188 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6189 } else { 6190 array = *values; 6191 } 6192 PetscCall(VecGetArrayRead(v, &vArray)); 6193 /* Get values */ 6194 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6195 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6196 /* Cleanup points */ 6197 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6198 /* Cleanup array */ 6199 PetscCall(VecRestoreArrayRead(v, &vArray)); 6200 if (!*values) { 6201 if (csize) *csize = size; 6202 *values = array; 6203 } else { 6204 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6205 *csize = size; 6206 } 6207 PetscFunctionReturn(PETSC_SUCCESS); 6208 } 6209 6210 /*@C 6211 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6212 6213 Not collective 6214 6215 Input Parameters: 6216 + dm - The `DM` 6217 . section - The section describing the layout in `v`, or `NULL` to use the default section 6218 . v - The local vector 6219 . point - The point in the `DM` 6220 . csize - The number of values in the closure, or `NULL` 6221 - values - The array of values, which is a borrowed array and should not be freed 6222 6223 Level: intermediate 6224 6225 Note: 6226 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6227 6228 Fortran Notes: 6229 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6230 6231 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6232 @*/ 6233 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6234 { 6235 PetscInt size = 0; 6236 6237 PetscFunctionBegin; 6238 /* Should work without recalculating size */ 6239 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6240 *values = NULL; 6241 PetscFunctionReturn(PETSC_SUCCESS); 6242 } 6243 6244 static inline void add(PetscScalar *x, PetscScalar y) 6245 { 6246 *x += y; 6247 } 6248 static inline void insert(PetscScalar *x, PetscScalar y) 6249 { 6250 *x = y; 6251 } 6252 6253 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[]) 6254 { 6255 PetscInt cdof; /* The number of constraints on this point */ 6256 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6257 PetscScalar *a; 6258 PetscInt off, cind = 0, k; 6259 6260 PetscFunctionBegin; 6261 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6262 PetscCall(PetscSectionGetOffset(section, point, &off)); 6263 a = &array[off]; 6264 if (!cdof || setBC) { 6265 if (clperm) { 6266 if (perm) { 6267 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6268 } else { 6269 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6270 } 6271 } else { 6272 if (perm) { 6273 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6274 } else { 6275 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6276 } 6277 } 6278 } else { 6279 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6280 if (clperm) { 6281 if (perm) { 6282 for (k = 0; k < dof; ++k) { 6283 if ((cind < cdof) && (k == cdofs[cind])) { 6284 ++cind; 6285 continue; 6286 } 6287 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6288 } 6289 } else { 6290 for (k = 0; k < dof; ++k) { 6291 if ((cind < cdof) && (k == cdofs[cind])) { 6292 ++cind; 6293 continue; 6294 } 6295 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6296 } 6297 } 6298 } else { 6299 if (perm) { 6300 for (k = 0; k < dof; ++k) { 6301 if ((cind < cdof) && (k == cdofs[cind])) { 6302 ++cind; 6303 continue; 6304 } 6305 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6306 } 6307 } else { 6308 for (k = 0; k < dof; ++k) { 6309 if ((cind < cdof) && (k == cdofs[cind])) { 6310 ++cind; 6311 continue; 6312 } 6313 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6314 } 6315 } 6316 } 6317 } 6318 PetscFunctionReturn(PETSC_SUCCESS); 6319 } 6320 6321 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[]) 6322 { 6323 PetscInt cdof; /* The number of constraints on this point */ 6324 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6325 PetscScalar *a; 6326 PetscInt off, cind = 0, k; 6327 6328 PetscFunctionBegin; 6329 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6330 PetscCall(PetscSectionGetOffset(section, point, &off)); 6331 a = &array[off]; 6332 if (cdof) { 6333 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6334 if (clperm) { 6335 if (perm) { 6336 for (k = 0; k < dof; ++k) { 6337 if ((cind < cdof) && (k == cdofs[cind])) { 6338 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6339 cind++; 6340 } 6341 } 6342 } else { 6343 for (k = 0; k < dof; ++k) { 6344 if ((cind < cdof) && (k == cdofs[cind])) { 6345 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6346 cind++; 6347 } 6348 } 6349 } 6350 } else { 6351 if (perm) { 6352 for (k = 0; k < dof; ++k) { 6353 if ((cind < cdof) && (k == cdofs[cind])) { 6354 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6355 cind++; 6356 } 6357 } 6358 } else { 6359 for (k = 0; k < dof; ++k) { 6360 if ((cind < cdof) && (k == cdofs[cind])) { 6361 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6362 cind++; 6363 } 6364 } 6365 } 6366 } 6367 } 6368 PetscFunctionReturn(PETSC_SUCCESS); 6369 } 6370 6371 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[]) 6372 { 6373 PetscScalar *a; 6374 PetscInt fdof, foff, fcdof, foffset = *offset; 6375 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6376 PetscInt cind = 0, b; 6377 6378 PetscFunctionBegin; 6379 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6380 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6381 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6382 a = &array[foff]; 6383 if (!fcdof || setBC) { 6384 if (clperm) { 6385 if (perm) { 6386 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6387 } else { 6388 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6389 } 6390 } else { 6391 if (perm) { 6392 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6393 } else { 6394 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6395 } 6396 } 6397 } else { 6398 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6399 if (clperm) { 6400 if (perm) { 6401 for (b = 0; b < fdof; b++) { 6402 if ((cind < fcdof) && (b == fcdofs[cind])) { 6403 ++cind; 6404 continue; 6405 } 6406 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6407 } 6408 } else { 6409 for (b = 0; b < fdof; b++) { 6410 if ((cind < fcdof) && (b == fcdofs[cind])) { 6411 ++cind; 6412 continue; 6413 } 6414 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6415 } 6416 } 6417 } else { 6418 if (perm) { 6419 for (b = 0; b < fdof; b++) { 6420 if ((cind < fcdof) && (b == fcdofs[cind])) { 6421 ++cind; 6422 continue; 6423 } 6424 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6425 } 6426 } else { 6427 for (b = 0; b < fdof; b++) { 6428 if ((cind < fcdof) && (b == fcdofs[cind])) { 6429 ++cind; 6430 continue; 6431 } 6432 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6433 } 6434 } 6435 } 6436 } 6437 *offset += fdof; 6438 PetscFunctionReturn(PETSC_SUCCESS); 6439 } 6440 6441 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[]) 6442 { 6443 PetscScalar *a; 6444 PetscInt fdof, foff, fcdof, foffset = *offset; 6445 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6446 PetscInt Nc, cind = 0, ncind = 0, b; 6447 PetscBool ncSet, fcSet; 6448 6449 PetscFunctionBegin; 6450 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6451 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6452 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6453 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6454 a = &array[foff]; 6455 if (fcdof) { 6456 /* We just override fcdof and fcdofs with Ncc and comps */ 6457 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6458 if (clperm) { 6459 if (perm) { 6460 if (comps) { 6461 for (b = 0; b < fdof; b++) { 6462 ncSet = fcSet = PETSC_FALSE; 6463 if (b % Nc == comps[ncind]) { 6464 ncind = (ncind + 1) % Ncc; 6465 ncSet = PETSC_TRUE; 6466 } 6467 if ((cind < fcdof) && (b == fcdofs[cind])) { 6468 ++cind; 6469 fcSet = PETSC_TRUE; 6470 } 6471 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6472 } 6473 } else { 6474 for (b = 0; b < fdof; b++) { 6475 if ((cind < fcdof) && (b == fcdofs[cind])) { 6476 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6477 ++cind; 6478 } 6479 } 6480 } 6481 } else { 6482 if (comps) { 6483 for (b = 0; b < fdof; b++) { 6484 ncSet = fcSet = PETSC_FALSE; 6485 if (b % Nc == comps[ncind]) { 6486 ncind = (ncind + 1) % Ncc; 6487 ncSet = PETSC_TRUE; 6488 } 6489 if ((cind < fcdof) && (b == fcdofs[cind])) { 6490 ++cind; 6491 fcSet = PETSC_TRUE; 6492 } 6493 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6494 } 6495 } else { 6496 for (b = 0; b < fdof; b++) { 6497 if ((cind < fcdof) && (b == fcdofs[cind])) { 6498 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6499 ++cind; 6500 } 6501 } 6502 } 6503 } 6504 } else { 6505 if (perm) { 6506 if (comps) { 6507 for (b = 0; b < fdof; b++) { 6508 ncSet = fcSet = PETSC_FALSE; 6509 if (b % Nc == comps[ncind]) { 6510 ncind = (ncind + 1) % Ncc; 6511 ncSet = PETSC_TRUE; 6512 } 6513 if ((cind < fcdof) && (b == fcdofs[cind])) { 6514 ++cind; 6515 fcSet = PETSC_TRUE; 6516 } 6517 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6518 } 6519 } else { 6520 for (b = 0; b < fdof; b++) { 6521 if ((cind < fcdof) && (b == fcdofs[cind])) { 6522 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6523 ++cind; 6524 } 6525 } 6526 } 6527 } else { 6528 if (comps) { 6529 for (b = 0; b < fdof; b++) { 6530 ncSet = fcSet = PETSC_FALSE; 6531 if (b % Nc == comps[ncind]) { 6532 ncind = (ncind + 1) % Ncc; 6533 ncSet = PETSC_TRUE; 6534 } 6535 if ((cind < fcdof) && (b == fcdofs[cind])) { 6536 ++cind; 6537 fcSet = PETSC_TRUE; 6538 } 6539 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6540 } 6541 } else { 6542 for (b = 0; b < fdof; b++) { 6543 if ((cind < fcdof) && (b == fcdofs[cind])) { 6544 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6545 ++cind; 6546 } 6547 } 6548 } 6549 } 6550 } 6551 } 6552 *offset += fdof; 6553 PetscFunctionReturn(PETSC_SUCCESS); 6554 } 6555 6556 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6557 { 6558 PetscScalar *array; 6559 const PetscInt *cone, *coneO; 6560 PetscInt pStart, pEnd, p, numPoints, off, dof; 6561 6562 PetscFunctionBeginHot; 6563 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6564 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6565 PetscCall(DMPlexGetCone(dm, point, &cone)); 6566 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6567 PetscCall(VecGetArray(v, &array)); 6568 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6569 const PetscInt cp = !p ? point : cone[p - 1]; 6570 const PetscInt o = !p ? 0 : coneO[p - 1]; 6571 6572 if ((cp < pStart) || (cp >= pEnd)) { 6573 dof = 0; 6574 continue; 6575 } 6576 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6577 /* ADD_VALUES */ 6578 { 6579 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6580 PetscScalar *a; 6581 PetscInt cdof, coff, cind = 0, k; 6582 6583 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6584 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6585 a = &array[coff]; 6586 if (!cdof) { 6587 if (o >= 0) { 6588 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6589 } else { 6590 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6591 } 6592 } else { 6593 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6594 if (o >= 0) { 6595 for (k = 0; k < dof; ++k) { 6596 if ((cind < cdof) && (k == cdofs[cind])) { 6597 ++cind; 6598 continue; 6599 } 6600 a[k] += values[off + k]; 6601 } 6602 } else { 6603 for (k = 0; k < dof; ++k) { 6604 if ((cind < cdof) && (k == cdofs[cind])) { 6605 ++cind; 6606 continue; 6607 } 6608 a[k] += values[off + dof - k - 1]; 6609 } 6610 } 6611 } 6612 } 6613 } 6614 PetscCall(VecRestoreArray(v, &array)); 6615 PetscFunctionReturn(PETSC_SUCCESS); 6616 } 6617 6618 /*@C 6619 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6620 6621 Not collective 6622 6623 Input Parameters: 6624 + dm - The `DM` 6625 . section - The section describing the layout in `v`, or `NULL` to use the default section 6626 . v - The local vector 6627 . point - The point in the `DM` 6628 . values - The array of values 6629 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6630 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6631 6632 Level: intermediate 6633 6634 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6635 @*/ 6636 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6637 { 6638 PetscSection clSection; 6639 IS clPoints; 6640 PetscScalar *array; 6641 PetscInt *points = NULL; 6642 const PetscInt *clp, *clperm = NULL; 6643 PetscInt depth, numFields, numPoints, p, clsize; 6644 6645 PetscFunctionBeginHot; 6646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6647 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6648 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6649 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6650 PetscCall(DMPlexGetDepth(dm, &depth)); 6651 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6652 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6653 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6654 PetscFunctionReturn(PETSC_SUCCESS); 6655 } 6656 /* Get points */ 6657 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6658 for (clsize = 0, p = 0; p < numPoints; p++) { 6659 PetscInt dof; 6660 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6661 clsize += dof; 6662 } 6663 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6664 /* Get array */ 6665 PetscCall(VecGetArray(v, &array)); 6666 /* Get values */ 6667 if (numFields > 0) { 6668 PetscInt offset = 0, f; 6669 for (f = 0; f < numFields; ++f) { 6670 const PetscInt **perms = NULL; 6671 const PetscScalar **flips = NULL; 6672 6673 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6674 switch (mode) { 6675 case INSERT_VALUES: 6676 for (p = 0; p < numPoints; p++) { 6677 const PetscInt point = points[2 * p]; 6678 const PetscInt *perm = perms ? perms[p] : NULL; 6679 const PetscScalar *flip = flips ? flips[p] : NULL; 6680 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6681 } 6682 break; 6683 case INSERT_ALL_VALUES: 6684 for (p = 0; p < numPoints; p++) { 6685 const PetscInt point = points[2 * p]; 6686 const PetscInt *perm = perms ? perms[p] : NULL; 6687 const PetscScalar *flip = flips ? flips[p] : NULL; 6688 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6689 } 6690 break; 6691 case INSERT_BC_VALUES: 6692 for (p = 0; p < numPoints; p++) { 6693 const PetscInt point = points[2 * p]; 6694 const PetscInt *perm = perms ? perms[p] : NULL; 6695 const PetscScalar *flip = flips ? flips[p] : NULL; 6696 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6697 } 6698 break; 6699 case ADD_VALUES: 6700 for (p = 0; p < numPoints; p++) { 6701 const PetscInt point = points[2 * p]; 6702 const PetscInt *perm = perms ? perms[p] : NULL; 6703 const PetscScalar *flip = flips ? flips[p] : NULL; 6704 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6705 } 6706 break; 6707 case ADD_ALL_VALUES: 6708 for (p = 0; p < numPoints; p++) { 6709 const PetscInt point = points[2 * p]; 6710 const PetscInt *perm = perms ? perms[p] : NULL; 6711 const PetscScalar *flip = flips ? flips[p] : NULL; 6712 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6713 } 6714 break; 6715 case ADD_BC_VALUES: 6716 for (p = 0; p < numPoints; p++) { 6717 const PetscInt point = points[2 * p]; 6718 const PetscInt *perm = perms ? perms[p] : NULL; 6719 const PetscScalar *flip = flips ? flips[p] : NULL; 6720 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6721 } 6722 break; 6723 default: 6724 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6725 } 6726 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6727 } 6728 } else { 6729 PetscInt dof, off; 6730 const PetscInt **perms = NULL; 6731 const PetscScalar **flips = NULL; 6732 6733 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6734 switch (mode) { 6735 case INSERT_VALUES: 6736 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6737 const PetscInt point = points[2 * p]; 6738 const PetscInt *perm = perms ? perms[p] : NULL; 6739 const PetscScalar *flip = flips ? flips[p] : NULL; 6740 PetscCall(PetscSectionGetDof(section, point, &dof)); 6741 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6742 } 6743 break; 6744 case INSERT_ALL_VALUES: 6745 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6746 const PetscInt point = points[2 * p]; 6747 const PetscInt *perm = perms ? perms[p] : NULL; 6748 const PetscScalar *flip = flips ? flips[p] : NULL; 6749 PetscCall(PetscSectionGetDof(section, point, &dof)); 6750 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6751 } 6752 break; 6753 case INSERT_BC_VALUES: 6754 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6755 const PetscInt point = points[2 * p]; 6756 const PetscInt *perm = perms ? perms[p] : NULL; 6757 const PetscScalar *flip = flips ? flips[p] : NULL; 6758 PetscCall(PetscSectionGetDof(section, point, &dof)); 6759 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6760 } 6761 break; 6762 case ADD_VALUES: 6763 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6764 const PetscInt point = points[2 * p]; 6765 const PetscInt *perm = perms ? perms[p] : NULL; 6766 const PetscScalar *flip = flips ? flips[p] : NULL; 6767 PetscCall(PetscSectionGetDof(section, point, &dof)); 6768 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6769 } 6770 break; 6771 case ADD_ALL_VALUES: 6772 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6773 const PetscInt point = points[2 * p]; 6774 const PetscInt *perm = perms ? perms[p] : NULL; 6775 const PetscScalar *flip = flips ? flips[p] : NULL; 6776 PetscCall(PetscSectionGetDof(section, point, &dof)); 6777 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6778 } 6779 break; 6780 case ADD_BC_VALUES: 6781 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6782 const PetscInt point = points[2 * p]; 6783 const PetscInt *perm = perms ? perms[p] : NULL; 6784 const PetscScalar *flip = flips ? flips[p] : NULL; 6785 PetscCall(PetscSectionGetDof(section, point, &dof)); 6786 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6787 } 6788 break; 6789 default: 6790 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6791 } 6792 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6793 } 6794 /* Cleanup points */ 6795 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6796 /* Cleanup array */ 6797 PetscCall(VecRestoreArray(v, &array)); 6798 PetscFunctionReturn(PETSC_SUCCESS); 6799 } 6800 6801 PetscErrorCode DMPlexVecSetStar(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6802 { 6803 const PetscInt *supp, *cone; 6804 PetscScalar *a; 6805 PetscInt dim, Ns, dof, off, n = 0; 6806 6807 PetscFunctionBegin; 6808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6809 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6810 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6811 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6812 if (PetscDefined(USE_DEBUG)) { 6813 PetscInt vStart, vEnd; 6814 6815 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6816 PetscCheck(point >= vStart && point < vEnd, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " must be a vertex in [%" PetscInt_FMT ", %" PetscInt_FMT "]", point, vStart, vEnd); 6817 } 6818 PetscAssertPointer(values, 5); 6819 6820 PetscCall(DMGetDimension(dm, &dim)); 6821 PetscCall(DMPlexGetSupportSize(dm, point, &Ns)); 6822 PetscCall(DMPlexGetSupport(dm, point, &supp)); 6823 PetscCheck(Ns == 2 * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " has support size %" PetscInt_FMT " != %" PetscInt_FMT, point, Ns, 2 * dim); 6824 PetscCall(VecGetArray(v, &a)); 6825 PetscCall(PetscSectionGetDof(section, point, &dof)); 6826 PetscCall(PetscSectionGetOffset(section, point, &off)); 6827 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6828 for (PetscInt d = 0; d < dim; ++d) { 6829 // Left edge 6830 PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone)); 6831 PetscCall(PetscSectionGetDof(section, cone[0], &dof)); 6832 PetscCall(PetscSectionGetOffset(section, cone[0], &off)); 6833 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6834 // Right edge 6835 PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone)); 6836 PetscCall(PetscSectionGetDof(section, cone[1], &dof)); 6837 PetscCall(PetscSectionGetOffset(section, cone[1], &off)); 6838 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6839 } 6840 PetscCall(VecRestoreArray(v, &a)); 6841 PetscFunctionReturn(PETSC_SUCCESS); 6842 } 6843 6844 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6845 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6846 { 6847 PetscFunctionBegin; 6848 *contains = PETSC_TRUE; 6849 if (label) { 6850 PetscInt fdof; 6851 6852 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6853 if (!*contains) { 6854 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6855 *offset += fdof; 6856 PetscFunctionReturn(PETSC_SUCCESS); 6857 } 6858 } 6859 PetscFunctionReturn(PETSC_SUCCESS); 6860 } 6861 6862 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6863 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) 6864 { 6865 PetscSection clSection; 6866 IS clPoints; 6867 PetscScalar *array; 6868 PetscInt *points = NULL; 6869 const PetscInt *clp; 6870 PetscInt numFields, numPoints, p; 6871 PetscInt offset = 0, f; 6872 6873 PetscFunctionBeginHot; 6874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6875 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6876 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6877 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6878 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6879 /* Get points */ 6880 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6881 /* Get array */ 6882 PetscCall(VecGetArray(v, &array)); 6883 /* Get values */ 6884 for (f = 0; f < numFields; ++f) { 6885 const PetscInt **perms = NULL; 6886 const PetscScalar **flips = NULL; 6887 PetscBool contains; 6888 6889 if (!fieldActive[f]) { 6890 for (p = 0; p < numPoints * 2; p += 2) { 6891 PetscInt fdof; 6892 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6893 offset += fdof; 6894 } 6895 continue; 6896 } 6897 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6898 switch (mode) { 6899 case INSERT_VALUES: 6900 for (p = 0; p < numPoints; p++) { 6901 const PetscInt point = points[2 * p]; 6902 const PetscInt *perm = perms ? perms[p] : NULL; 6903 const PetscScalar *flip = flips ? flips[p] : NULL; 6904 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6905 if (!contains) continue; 6906 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6907 } 6908 break; 6909 case INSERT_ALL_VALUES: 6910 for (p = 0; p < numPoints; p++) { 6911 const PetscInt point = points[2 * p]; 6912 const PetscInt *perm = perms ? perms[p] : NULL; 6913 const PetscScalar *flip = flips ? flips[p] : NULL; 6914 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6915 if (!contains) continue; 6916 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6917 } 6918 break; 6919 case INSERT_BC_VALUES: 6920 for (p = 0; p < numPoints; p++) { 6921 const PetscInt point = points[2 * p]; 6922 const PetscInt *perm = perms ? perms[p] : NULL; 6923 const PetscScalar *flip = flips ? flips[p] : NULL; 6924 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6925 if (!contains) continue; 6926 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6927 } 6928 break; 6929 case ADD_VALUES: 6930 for (p = 0; p < numPoints; p++) { 6931 const PetscInt point = points[2 * p]; 6932 const PetscInt *perm = perms ? perms[p] : NULL; 6933 const PetscScalar *flip = flips ? flips[p] : NULL; 6934 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6935 if (!contains) continue; 6936 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6937 } 6938 break; 6939 case ADD_ALL_VALUES: 6940 for (p = 0; p < numPoints; p++) { 6941 const PetscInt point = points[2 * p]; 6942 const PetscInt *perm = perms ? perms[p] : NULL; 6943 const PetscScalar *flip = flips ? flips[p] : NULL; 6944 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6945 if (!contains) continue; 6946 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6947 } 6948 break; 6949 default: 6950 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6951 } 6952 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6953 } 6954 /* Cleanup points */ 6955 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6956 /* Cleanup array */ 6957 PetscCall(VecRestoreArray(v, &array)); 6958 PetscFunctionReturn(PETSC_SUCCESS); 6959 } 6960 6961 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6962 { 6963 PetscMPIInt rank; 6964 PetscInt i, j; 6965 6966 PetscFunctionBegin; 6967 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6968 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6969 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6970 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6971 numCIndices = numCIndices ? numCIndices : numRIndices; 6972 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6973 for (i = 0; i < numRIndices; i++) { 6974 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6975 for (j = 0; j < numCIndices; j++) { 6976 #if defined(PETSC_USE_COMPLEX) 6977 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6978 #else 6979 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6980 #endif 6981 } 6982 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6983 } 6984 PetscFunctionReturn(PETSC_SUCCESS); 6985 } 6986 6987 /* 6988 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6989 6990 Input Parameters: 6991 + section - The section for this data layout 6992 . islocal - Is the section (and thus indices being requested) local or global? 6993 . point - The point contributing dofs with these indices 6994 . off - The global offset of this point 6995 . loff - The local offset of each field 6996 . setBC - The flag determining whether to include indices of boundary values 6997 . perm - A permutation of the dofs on this point, or NULL 6998 - indperm - A permutation of the entire indices array, or NULL 6999 7000 Output Parameter: 7001 . indices - Indices for dofs on this point 7002 7003 Level: developer 7004 7005 Note: The indices could be local or global, depending on the value of 'off'. 7006 */ 7007 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7008 { 7009 PetscInt dof; /* The number of unknowns on this point */ 7010 PetscInt cdof; /* The number of constraints on this point */ 7011 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7012 PetscInt cind = 0, k; 7013 7014 PetscFunctionBegin; 7015 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7016 PetscCall(PetscSectionGetDof(section, point, &dof)); 7017 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7018 if (!cdof || setBC) { 7019 for (k = 0; k < dof; ++k) { 7020 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7021 const PetscInt ind = indperm ? indperm[preind] : preind; 7022 7023 indices[ind] = off + k; 7024 } 7025 } else { 7026 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7027 for (k = 0; k < dof; ++k) { 7028 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7029 const PetscInt ind = indperm ? indperm[preind] : preind; 7030 7031 if ((cind < cdof) && (k == cdofs[cind])) { 7032 /* Insert check for returning constrained indices */ 7033 indices[ind] = -(off + k + 1); 7034 ++cind; 7035 } else { 7036 indices[ind] = off + k - (islocal ? 0 : cind); 7037 } 7038 } 7039 } 7040 *loff += dof; 7041 PetscFunctionReturn(PETSC_SUCCESS); 7042 } 7043 7044 /* 7045 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7046 7047 Input Parameters: 7048 + section - a section (global or local) 7049 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7050 . point - point within section 7051 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7052 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7053 . setBC - identify constrained (boundary condition) points via involution. 7054 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7055 . permsoff - offset 7056 - indperm - index permutation 7057 7058 Output Parameter: 7059 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7060 . indices - array to hold indices (as defined by section) of each dof associated with point 7061 7062 Notes: 7063 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7064 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7065 in the local vector. 7066 7067 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7068 significant). It is invalid to call with a global section and setBC=true. 7069 7070 Developer Note: 7071 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7072 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7073 offset could be obtained from the section instead of passing it explicitly as we do now. 7074 7075 Example: 7076 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7077 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7078 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7079 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. 7080 7081 Level: developer 7082 */ 7083 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[]) 7084 { 7085 PetscInt numFields, foff, f; 7086 7087 PetscFunctionBegin; 7088 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7089 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7090 for (f = 0, foff = 0; f < numFields; ++f) { 7091 PetscInt fdof, cfdof; 7092 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7093 PetscInt cind = 0, b; 7094 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7095 7096 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7097 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7098 if (!cfdof || setBC) { 7099 for (b = 0; b < fdof; ++b) { 7100 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7101 const PetscInt ind = indperm ? indperm[preind] : preind; 7102 7103 indices[ind] = off + foff + b; 7104 } 7105 } else { 7106 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7107 for (b = 0; b < fdof; ++b) { 7108 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7109 const PetscInt ind = indperm ? indperm[preind] : preind; 7110 7111 if ((cind < cfdof) && (b == fcdofs[cind])) { 7112 indices[ind] = -(off + foff + b + 1); 7113 ++cind; 7114 } else { 7115 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7116 } 7117 } 7118 } 7119 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7120 foffs[f] += fdof; 7121 } 7122 PetscFunctionReturn(PETSC_SUCCESS); 7123 } 7124 7125 /* 7126 This version believes the globalSection offsets for each field, rather than just the point offset 7127 7128 . foffs - The offset into 'indices' for each field, since it is segregated by field 7129 7130 Notes: 7131 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7132 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7133 */ 7134 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7135 { 7136 PetscInt numFields, foff, f; 7137 7138 PetscFunctionBegin; 7139 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7140 for (f = 0; f < numFields; ++f) { 7141 PetscInt fdof, cfdof; 7142 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7143 PetscInt cind = 0, b; 7144 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7145 7146 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7147 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7148 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7149 if (!cfdof) { 7150 for (b = 0; b < fdof; ++b) { 7151 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7152 const PetscInt ind = indperm ? indperm[preind] : preind; 7153 7154 indices[ind] = foff + b; 7155 } 7156 } else { 7157 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7158 for (b = 0; b < fdof; ++b) { 7159 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7160 const PetscInt ind = indperm ? indperm[preind] : preind; 7161 7162 if ((cind < cfdof) && (b == fcdofs[cind])) { 7163 indices[ind] = -(foff + b + 1); 7164 ++cind; 7165 } else { 7166 indices[ind] = foff + b - cind; 7167 } 7168 } 7169 } 7170 foffs[f] += fdof; 7171 } 7172 PetscFunctionReturn(PETSC_SUCCESS); 7173 } 7174 7175 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) 7176 { 7177 Mat cMat; 7178 PetscSection aSec, cSec; 7179 IS aIS; 7180 PetscInt aStart = -1, aEnd = -1; 7181 const PetscInt *anchors; 7182 PetscInt numFields, f, p, q, newP = 0; 7183 PetscInt newNumPoints = 0, newNumIndices = 0; 7184 PetscInt *newPoints, *indices, *newIndices; 7185 PetscInt maxAnchor, maxDof; 7186 PetscInt newOffsets[32]; 7187 PetscInt *pointMatOffsets[32]; 7188 PetscInt *newPointOffsets[32]; 7189 PetscScalar *pointMat[32]; 7190 PetscScalar *newValues = NULL, *tmpValues; 7191 PetscBool anyConstrained = PETSC_FALSE; 7192 7193 PetscFunctionBegin; 7194 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7195 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7196 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7197 7198 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7199 /* if there are point-to-point constraints */ 7200 if (aSec) { 7201 PetscCall(PetscArrayzero(newOffsets, 32)); 7202 PetscCall(ISGetIndices(aIS, &anchors)); 7203 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7204 /* figure out how many points are going to be in the new element matrix 7205 * (we allow double counting, because it's all just going to be summed 7206 * into the global matrix anyway) */ 7207 for (p = 0; p < 2 * numPoints; p += 2) { 7208 PetscInt b = points[p]; 7209 PetscInt bDof = 0, bSecDof; 7210 7211 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7212 if (!bSecDof) continue; 7213 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7214 if (bDof) { 7215 /* this point is constrained */ 7216 /* it is going to be replaced by its anchors */ 7217 PetscInt bOff, q; 7218 7219 anyConstrained = PETSC_TRUE; 7220 newNumPoints += bDof; 7221 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7222 for (q = 0; q < bDof; q++) { 7223 PetscInt a = anchors[bOff + q]; 7224 PetscInt aDof; 7225 7226 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7227 newNumIndices += aDof; 7228 for (f = 0; f < numFields; ++f) { 7229 PetscInt fDof; 7230 7231 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7232 newOffsets[f + 1] += fDof; 7233 } 7234 } 7235 } else { 7236 /* this point is not constrained */ 7237 newNumPoints++; 7238 newNumIndices += bSecDof; 7239 for (f = 0; f < numFields; ++f) { 7240 PetscInt fDof; 7241 7242 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7243 newOffsets[f + 1] += fDof; 7244 } 7245 } 7246 } 7247 } 7248 if (!anyConstrained) { 7249 if (outNumPoints) *outNumPoints = 0; 7250 if (outNumIndices) *outNumIndices = 0; 7251 if (outPoints) *outPoints = NULL; 7252 if (outValues) *outValues = NULL; 7253 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7254 PetscFunctionReturn(PETSC_SUCCESS); 7255 } 7256 7257 if (outNumPoints) *outNumPoints = newNumPoints; 7258 if (outNumIndices) *outNumIndices = newNumIndices; 7259 7260 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7261 7262 if (!outPoints && !outValues) { 7263 if (offsets) { 7264 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7265 } 7266 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7267 PetscFunctionReturn(PETSC_SUCCESS); 7268 } 7269 7270 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7271 7272 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7273 7274 /* workspaces */ 7275 if (numFields) { 7276 for (f = 0; f < numFields; f++) { 7277 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7278 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7279 } 7280 } else { 7281 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7282 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7283 } 7284 7285 /* get workspaces for the point-to-point matrices */ 7286 if (numFields) { 7287 PetscInt totalOffset, totalMatOffset; 7288 7289 for (p = 0; p < numPoints; p++) { 7290 PetscInt b = points[2 * p]; 7291 PetscInt bDof = 0, bSecDof; 7292 7293 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7294 if (!bSecDof) { 7295 for (f = 0; f < numFields; f++) { 7296 newPointOffsets[f][p + 1] = 0; 7297 pointMatOffsets[f][p + 1] = 0; 7298 } 7299 continue; 7300 } 7301 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7302 if (bDof) { 7303 for (f = 0; f < numFields; f++) { 7304 PetscInt fDof, q, bOff, allFDof = 0; 7305 7306 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7307 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7308 for (q = 0; q < bDof; q++) { 7309 PetscInt a = anchors[bOff + q]; 7310 PetscInt aFDof; 7311 7312 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7313 allFDof += aFDof; 7314 } 7315 newPointOffsets[f][p + 1] = allFDof; 7316 pointMatOffsets[f][p + 1] = fDof * allFDof; 7317 } 7318 } else { 7319 for (f = 0; f < numFields; f++) { 7320 PetscInt fDof; 7321 7322 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7323 newPointOffsets[f][p + 1] = fDof; 7324 pointMatOffsets[f][p + 1] = 0; 7325 } 7326 } 7327 } 7328 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7329 newPointOffsets[f][0] = totalOffset; 7330 pointMatOffsets[f][0] = totalMatOffset; 7331 for (p = 0; p < numPoints; p++) { 7332 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7333 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7334 } 7335 totalOffset = newPointOffsets[f][numPoints]; 7336 totalMatOffset = pointMatOffsets[f][numPoints]; 7337 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7338 } 7339 } else { 7340 for (p = 0; p < numPoints; p++) { 7341 PetscInt b = points[2 * p]; 7342 PetscInt bDof = 0, bSecDof; 7343 7344 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7345 if (!bSecDof) { 7346 newPointOffsets[0][p + 1] = 0; 7347 pointMatOffsets[0][p + 1] = 0; 7348 continue; 7349 } 7350 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7351 if (bDof) { 7352 PetscInt bOff, q, allDof = 0; 7353 7354 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7355 for (q = 0; q < bDof; q++) { 7356 PetscInt a = anchors[bOff + q], aDof; 7357 7358 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7359 allDof += aDof; 7360 } 7361 newPointOffsets[0][p + 1] = allDof; 7362 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7363 } else { 7364 newPointOffsets[0][p + 1] = bSecDof; 7365 pointMatOffsets[0][p + 1] = 0; 7366 } 7367 } 7368 newPointOffsets[0][0] = 0; 7369 pointMatOffsets[0][0] = 0; 7370 for (p = 0; p < numPoints; p++) { 7371 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7372 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7373 } 7374 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7375 } 7376 7377 /* output arrays */ 7378 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7379 7380 /* get the point-to-point matrices; construct newPoints */ 7381 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7382 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7383 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7384 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7385 if (numFields) { 7386 for (p = 0, newP = 0; p < numPoints; p++) { 7387 PetscInt b = points[2 * p]; 7388 PetscInt o = points[2 * p + 1]; 7389 PetscInt bDof = 0, bSecDof; 7390 7391 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7392 if (!bSecDof) continue; 7393 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7394 if (bDof) { 7395 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7396 7397 fStart[0] = 0; 7398 fEnd[0] = 0; 7399 for (f = 0; f < numFields; f++) { 7400 PetscInt fDof; 7401 7402 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7403 fStart[f + 1] = fStart[f] + fDof; 7404 fEnd[f + 1] = fStart[f + 1]; 7405 } 7406 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7407 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7408 7409 fAnchorStart[0] = 0; 7410 fAnchorEnd[0] = 0; 7411 for (f = 0; f < numFields; f++) { 7412 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7413 7414 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7415 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7416 } 7417 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7418 for (q = 0; q < bDof; q++) { 7419 PetscInt a = anchors[bOff + q], aOff; 7420 7421 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7422 newPoints[2 * (newP + q)] = a; 7423 newPoints[2 * (newP + q) + 1] = 0; 7424 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7425 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7426 } 7427 newP += bDof; 7428 7429 if (outValues) { 7430 /* get the point-to-point submatrix */ 7431 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])); 7432 } 7433 } else { 7434 newPoints[2 * newP] = b; 7435 newPoints[2 * newP + 1] = o; 7436 newP++; 7437 } 7438 } 7439 } else { 7440 for (p = 0; p < numPoints; p++) { 7441 PetscInt b = points[2 * p]; 7442 PetscInt o = points[2 * p + 1]; 7443 PetscInt bDof = 0, bSecDof; 7444 7445 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7446 if (!bSecDof) continue; 7447 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7448 if (bDof) { 7449 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7450 7451 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7452 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7453 7454 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7455 for (q = 0; q < bDof; q++) { 7456 PetscInt a = anchors[bOff + q], aOff; 7457 7458 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7459 7460 newPoints[2 * (newP + q)] = a; 7461 newPoints[2 * (newP + q) + 1] = 0; 7462 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7463 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7464 } 7465 newP += bDof; 7466 7467 /* get the point-to-point submatrix */ 7468 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7469 } else { 7470 newPoints[2 * newP] = b; 7471 newPoints[2 * newP + 1] = o; 7472 newP++; 7473 } 7474 } 7475 } 7476 7477 if (outValues) { 7478 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7479 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7480 /* multiply constraints on the right */ 7481 if (numFields) { 7482 for (f = 0; f < numFields; f++) { 7483 PetscInt oldOff = offsets[f]; 7484 7485 for (p = 0; p < numPoints; p++) { 7486 PetscInt cStart = newPointOffsets[f][p]; 7487 PetscInt b = points[2 * p]; 7488 PetscInt c, r, k; 7489 PetscInt dof; 7490 7491 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7492 if (!dof) continue; 7493 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7494 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7495 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7496 7497 for (r = 0; r < numIndices; r++) { 7498 for (c = 0; c < nCols; c++) { 7499 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7500 } 7501 } 7502 } else { 7503 /* copy this column as is */ 7504 for (r = 0; r < numIndices; r++) { 7505 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7506 } 7507 } 7508 oldOff += dof; 7509 } 7510 } 7511 } else { 7512 PetscInt oldOff = 0; 7513 for (p = 0; p < numPoints; p++) { 7514 PetscInt cStart = newPointOffsets[0][p]; 7515 PetscInt b = points[2 * p]; 7516 PetscInt c, r, k; 7517 PetscInt dof; 7518 7519 PetscCall(PetscSectionGetDof(section, b, &dof)); 7520 if (!dof) continue; 7521 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7522 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7523 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7524 7525 for (r = 0; r < numIndices; r++) { 7526 for (c = 0; c < nCols; c++) { 7527 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7528 } 7529 } 7530 } else { 7531 /* copy this column as is */ 7532 for (r = 0; r < numIndices; r++) { 7533 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7534 } 7535 } 7536 oldOff += dof; 7537 } 7538 } 7539 7540 if (multiplyLeft) { 7541 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7542 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7543 /* multiply constraints transpose on the left */ 7544 if (numFields) { 7545 for (f = 0; f < numFields; f++) { 7546 PetscInt oldOff = offsets[f]; 7547 7548 for (p = 0; p < numPoints; p++) { 7549 PetscInt rStart = newPointOffsets[f][p]; 7550 PetscInt b = points[2 * p]; 7551 PetscInt c, r, k; 7552 PetscInt dof; 7553 7554 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7555 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7556 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7557 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7558 7559 for (r = 0; r < nRows; r++) { 7560 for (c = 0; c < newNumIndices; c++) { 7561 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7562 } 7563 } 7564 } else { 7565 /* copy this row as is */ 7566 for (r = 0; r < dof; r++) { 7567 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7568 } 7569 } 7570 oldOff += dof; 7571 } 7572 } 7573 } else { 7574 PetscInt oldOff = 0; 7575 7576 for (p = 0; p < numPoints; p++) { 7577 PetscInt rStart = newPointOffsets[0][p]; 7578 PetscInt b = points[2 * p]; 7579 PetscInt c, r, k; 7580 PetscInt dof; 7581 7582 PetscCall(PetscSectionGetDof(section, b, &dof)); 7583 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7584 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7585 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7586 7587 for (r = 0; r < nRows; r++) { 7588 for (c = 0; c < newNumIndices; c++) { 7589 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7590 } 7591 } 7592 } else { 7593 /* copy this row as is */ 7594 for (r = 0; r < dof; r++) { 7595 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7596 } 7597 } 7598 oldOff += dof; 7599 } 7600 } 7601 7602 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7603 } else { 7604 newValues = tmpValues; 7605 } 7606 } 7607 7608 /* clean up */ 7609 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7610 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7611 7612 if (numFields) { 7613 for (f = 0; f < numFields; f++) { 7614 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7615 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7616 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7617 } 7618 } else { 7619 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7620 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7621 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7622 } 7623 PetscCall(ISRestoreIndices(aIS, &anchors)); 7624 7625 /* output */ 7626 if (outPoints) { 7627 *outPoints = newPoints; 7628 } else { 7629 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7630 } 7631 if (outValues) *outValues = newValues; 7632 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7633 PetscFunctionReturn(PETSC_SUCCESS); 7634 } 7635 7636 /*@C 7637 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7638 7639 Not collective 7640 7641 Input Parameters: 7642 + dm - The `DM` 7643 . section - The `PetscSection` describing the points (a local section) 7644 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7645 . point - The point defining the closure 7646 - useClPerm - Use the closure point permutation if available 7647 7648 Output Parameters: 7649 + numIndices - The number of dof indices in the closure of point with the input sections 7650 . indices - The dof indices 7651 . outOffsets - Array to write the field offsets into, or `NULL` 7652 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7653 7654 Level: advanced 7655 7656 Notes: 7657 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7658 7659 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7660 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7661 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7662 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7663 indices (with the above semantics) are implied. 7664 7665 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7666 `PetscSection`, `DMGetGlobalSection()` 7667 @*/ 7668 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7669 { 7670 /* Closure ordering */ 7671 PetscSection clSection; 7672 IS clPoints; 7673 const PetscInt *clp; 7674 PetscInt *points; 7675 const PetscInt *clperm = NULL; 7676 /* Dof permutation and sign flips */ 7677 const PetscInt **perms[32] = {NULL}; 7678 const PetscScalar **flips[32] = {NULL}; 7679 PetscScalar *valCopy = NULL; 7680 /* Hanging node constraints */ 7681 PetscInt *pointsC = NULL; 7682 PetscScalar *valuesC = NULL; 7683 PetscInt NclC, NiC; 7684 7685 PetscInt *idx; 7686 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7687 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7688 7689 PetscFunctionBeginHot; 7690 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7691 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7692 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7693 if (numIndices) PetscAssertPointer(numIndices, 6); 7694 if (indices) PetscAssertPointer(indices, 7); 7695 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7696 if (values) PetscAssertPointer(values, 9); 7697 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7698 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7699 PetscCall(PetscArrayzero(offsets, 32)); 7700 /* 1) Get points in closure */ 7701 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7702 if (useClPerm) { 7703 PetscInt depth, clsize; 7704 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7705 for (clsize = 0, p = 0; p < Ncl; p++) { 7706 PetscInt dof; 7707 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7708 clsize += dof; 7709 } 7710 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7711 } 7712 /* 2) Get number of indices on these points and field offsets from section */ 7713 for (p = 0; p < Ncl * 2; p += 2) { 7714 PetscInt dof, fdof; 7715 7716 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7717 for (f = 0; f < Nf; ++f) { 7718 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7719 offsets[f + 1] += fdof; 7720 } 7721 Ni += dof; 7722 } 7723 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7724 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7725 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7726 for (f = 0; f < PetscMax(1, Nf); ++f) { 7727 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7728 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7729 /* may need to apply sign changes to the element matrix */ 7730 if (values && flips[f]) { 7731 PetscInt foffset = offsets[f]; 7732 7733 for (p = 0; p < Ncl; ++p) { 7734 PetscInt pnt = points[2 * p], fdof; 7735 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7736 7737 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7738 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7739 if (flip) { 7740 PetscInt i, j, k; 7741 7742 if (!valCopy) { 7743 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7744 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7745 *values = valCopy; 7746 } 7747 for (i = 0; i < fdof; ++i) { 7748 PetscScalar fval = flip[i]; 7749 7750 for (k = 0; k < Ni; ++k) { 7751 valCopy[Ni * (foffset + i) + k] *= fval; 7752 valCopy[Ni * k + (foffset + i)] *= fval; 7753 } 7754 } 7755 } 7756 foffset += fdof; 7757 } 7758 } 7759 } 7760 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7761 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7762 if (NclC) { 7763 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7764 for (f = 0; f < PetscMax(1, Nf); ++f) { 7765 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7766 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7767 } 7768 for (f = 0; f < PetscMax(1, Nf); ++f) { 7769 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7770 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7771 } 7772 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7773 Ncl = NclC; 7774 Ni = NiC; 7775 points = pointsC; 7776 if (values) *values = valuesC; 7777 } 7778 /* 5) Calculate indices */ 7779 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7780 if (Nf) { 7781 PetscInt idxOff; 7782 PetscBool useFieldOffsets; 7783 7784 if (outOffsets) { 7785 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7786 } 7787 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7788 if (useFieldOffsets) { 7789 for (p = 0; p < Ncl; ++p) { 7790 const PetscInt pnt = points[p * 2]; 7791 7792 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7793 } 7794 } else { 7795 for (p = 0; p < Ncl; ++p) { 7796 const PetscInt pnt = points[p * 2]; 7797 7798 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7799 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7800 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7801 * global section. */ 7802 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7803 } 7804 } 7805 } else { 7806 PetscInt off = 0, idxOff; 7807 7808 for (p = 0; p < Ncl; ++p) { 7809 const PetscInt pnt = points[p * 2]; 7810 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7811 7812 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7813 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7814 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7815 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7816 } 7817 } 7818 /* 6) Cleanup */ 7819 for (f = 0; f < PetscMax(1, Nf); ++f) { 7820 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7821 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7822 } 7823 if (NclC) { 7824 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7825 } else { 7826 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7827 } 7828 7829 if (numIndices) *numIndices = Ni; 7830 if (indices) *indices = idx; 7831 PetscFunctionReturn(PETSC_SUCCESS); 7832 } 7833 7834 /*@C 7835 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7836 7837 Not collective 7838 7839 Input Parameters: 7840 + dm - The `DM` 7841 . section - The `PetscSection` describing the points (a local section) 7842 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7843 . point - The point defining the closure 7844 - useClPerm - Use the closure point permutation if available 7845 7846 Output Parameters: 7847 + numIndices - The number of dof indices in the closure of point with the input sections 7848 . indices - The dof indices 7849 . outOffsets - Array to write the field offsets into, or `NULL` 7850 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7851 7852 Level: advanced 7853 7854 Notes: 7855 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7856 7857 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7858 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7859 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7860 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7861 indices (with the above semantics) are implied. 7862 7863 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7864 @*/ 7865 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7866 { 7867 PetscFunctionBegin; 7868 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7869 PetscAssertPointer(indices, 7); 7870 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7871 PetscFunctionReturn(PETSC_SUCCESS); 7872 } 7873 7874 /*@C 7875 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7876 7877 Not collective 7878 7879 Input Parameters: 7880 + dm - The `DM` 7881 . section - The section describing the layout in `v`, or `NULL` to use the default section 7882 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 7883 . A - The matrix 7884 . point - The point in the `DM` 7885 . values - The array of values 7886 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7887 7888 Level: intermediate 7889 7890 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7891 @*/ 7892 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7893 { 7894 DM_Plex *mesh = (DM_Plex *)dm->data; 7895 PetscInt *indices; 7896 PetscInt numIndices; 7897 const PetscScalar *valuesOrig = values; 7898 PetscErrorCode ierr; 7899 7900 PetscFunctionBegin; 7901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7902 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7903 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7904 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7905 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7906 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7907 7908 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7909 7910 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7911 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7912 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7913 if (ierr) { 7914 PetscMPIInt rank; 7915 7916 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7917 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7918 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7919 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7920 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7921 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7922 } 7923 if (mesh->printFEM > 1) { 7924 PetscInt i; 7925 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7926 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7927 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7928 } 7929 7930 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7931 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7932 PetscFunctionReturn(PETSC_SUCCESS); 7933 } 7934 7935 /*@C 7936 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 7937 7938 Not collective 7939 7940 Input Parameters: 7941 + dmRow - The `DM` for the row fields 7942 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 7943 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 7944 . dmCol - The `DM` for the column fields 7945 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 7946 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 7947 . A - The matrix 7948 . point - The point in the `DM` 7949 . values - The array of values 7950 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7951 7952 Level: intermediate 7953 7954 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7955 @*/ 7956 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7957 { 7958 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7959 PetscInt *indicesRow, *indicesCol; 7960 PetscInt numIndicesRow, numIndicesCol; 7961 const PetscScalar *valuesOrig = values; 7962 PetscErrorCode ierr; 7963 7964 PetscFunctionBegin; 7965 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7966 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7967 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7968 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7969 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7970 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7971 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7972 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7973 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7974 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7975 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7976 7977 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7978 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7979 7980 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7981 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7982 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7983 if (ierr) { 7984 PetscMPIInt rank; 7985 7986 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7987 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7988 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7989 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7990 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7991 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7992 } 7993 7994 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7995 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7996 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7997 PetscFunctionReturn(PETSC_SUCCESS); 7998 } 7999 8000 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 8001 { 8002 DM_Plex *mesh = (DM_Plex *)dmf->data; 8003 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8004 PetscInt *cpoints = NULL; 8005 PetscInt *findices, *cindices; 8006 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8007 PetscInt foffsets[32], coffsets[32]; 8008 DMPolytopeType ct; 8009 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8010 PetscErrorCode ierr; 8011 8012 PetscFunctionBegin; 8013 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8014 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8015 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8016 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8017 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8018 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8019 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8020 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8021 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8022 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8023 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8024 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8025 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8026 PetscCall(PetscArrayzero(foffsets, 32)); 8027 PetscCall(PetscArrayzero(coffsets, 32)); 8028 /* Column indices */ 8029 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8030 maxFPoints = numCPoints; 8031 /* Compress out points not in the section */ 8032 /* TODO: Squeeze out points with 0 dof as well */ 8033 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8034 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8035 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8036 cpoints[q * 2] = cpoints[p]; 8037 cpoints[q * 2 + 1] = cpoints[p + 1]; 8038 ++q; 8039 } 8040 } 8041 numCPoints = q; 8042 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8043 PetscInt fdof; 8044 8045 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8046 if (!dof) continue; 8047 for (f = 0; f < numFields; ++f) { 8048 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8049 coffsets[f + 1] += fdof; 8050 } 8051 numCIndices += dof; 8052 } 8053 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8054 /* Row indices */ 8055 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8056 { 8057 DMPlexTransform tr; 8058 DMPolytopeType *rct; 8059 PetscInt *rsize, *rcone, *rornt, Nt; 8060 8061 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8062 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8063 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8064 numSubcells = rsize[Nt - 1]; 8065 PetscCall(DMPlexTransformDestroy(&tr)); 8066 } 8067 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8068 for (r = 0, q = 0; r < numSubcells; ++r) { 8069 /* TODO Map from coarse to fine cells */ 8070 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8071 /* Compress out points not in the section */ 8072 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8073 for (p = 0; p < numFPoints * 2; p += 2) { 8074 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8075 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8076 if (!dof) continue; 8077 for (s = 0; s < q; ++s) 8078 if (fpoints[p] == ftotpoints[s * 2]) break; 8079 if (s < q) continue; 8080 ftotpoints[q * 2] = fpoints[p]; 8081 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8082 ++q; 8083 } 8084 } 8085 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8086 } 8087 numFPoints = q; 8088 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8089 PetscInt fdof; 8090 8091 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8092 if (!dof) continue; 8093 for (f = 0; f < numFields; ++f) { 8094 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8095 foffsets[f + 1] += fdof; 8096 } 8097 numFIndices += dof; 8098 } 8099 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8100 8101 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8102 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8103 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8104 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8105 if (numFields) { 8106 const PetscInt **permsF[32] = {NULL}; 8107 const PetscInt **permsC[32] = {NULL}; 8108 8109 for (f = 0; f < numFields; f++) { 8110 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8111 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8112 } 8113 for (p = 0; p < numFPoints; p++) { 8114 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8115 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8116 } 8117 for (p = 0; p < numCPoints; p++) { 8118 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8119 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8120 } 8121 for (f = 0; f < numFields; f++) { 8122 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8123 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8124 } 8125 } else { 8126 const PetscInt **permsF = NULL; 8127 const PetscInt **permsC = NULL; 8128 8129 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8130 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8131 for (p = 0, off = 0; p < numFPoints; p++) { 8132 const PetscInt *perm = permsF ? permsF[p] : NULL; 8133 8134 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8135 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8136 } 8137 for (p = 0, off = 0; p < numCPoints; p++) { 8138 const PetscInt *perm = permsC ? permsC[p] : NULL; 8139 8140 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8141 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8142 } 8143 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8144 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8145 } 8146 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8147 /* TODO: flips */ 8148 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8149 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8150 if (ierr) { 8151 PetscMPIInt rank; 8152 8153 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8154 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8155 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8156 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8157 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8158 } 8159 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8160 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8161 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8162 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8163 PetscFunctionReturn(PETSC_SUCCESS); 8164 } 8165 8166 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8167 { 8168 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8169 PetscInt *cpoints = NULL; 8170 PetscInt foffsets[32], coffsets[32]; 8171 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8172 DMPolytopeType ct; 8173 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8174 8175 PetscFunctionBegin; 8176 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8177 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8178 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8179 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8180 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8181 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8182 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8183 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8184 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8185 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8186 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8187 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8188 PetscCall(PetscArrayzero(foffsets, 32)); 8189 PetscCall(PetscArrayzero(coffsets, 32)); 8190 /* Column indices */ 8191 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8192 maxFPoints = numCPoints; 8193 /* Compress out points not in the section */ 8194 /* TODO: Squeeze out points with 0 dof as well */ 8195 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8196 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8197 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8198 cpoints[q * 2] = cpoints[p]; 8199 cpoints[q * 2 + 1] = cpoints[p + 1]; 8200 ++q; 8201 } 8202 } 8203 numCPoints = q; 8204 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8205 PetscInt fdof; 8206 8207 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8208 if (!dof) continue; 8209 for (f = 0; f < numFields; ++f) { 8210 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8211 coffsets[f + 1] += fdof; 8212 } 8213 numCIndices += dof; 8214 } 8215 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8216 /* Row indices */ 8217 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8218 { 8219 DMPlexTransform tr; 8220 DMPolytopeType *rct; 8221 PetscInt *rsize, *rcone, *rornt, Nt; 8222 8223 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8224 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8225 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8226 numSubcells = rsize[Nt - 1]; 8227 PetscCall(DMPlexTransformDestroy(&tr)); 8228 } 8229 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8230 for (r = 0, q = 0; r < numSubcells; ++r) { 8231 /* TODO Map from coarse to fine cells */ 8232 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8233 /* Compress out points not in the section */ 8234 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8235 for (p = 0; p < numFPoints * 2; p += 2) { 8236 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8237 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8238 if (!dof) continue; 8239 for (s = 0; s < q; ++s) 8240 if (fpoints[p] == ftotpoints[s * 2]) break; 8241 if (s < q) continue; 8242 ftotpoints[q * 2] = fpoints[p]; 8243 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8244 ++q; 8245 } 8246 } 8247 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8248 } 8249 numFPoints = q; 8250 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8251 PetscInt fdof; 8252 8253 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8254 if (!dof) continue; 8255 for (f = 0; f < numFields; ++f) { 8256 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8257 foffsets[f + 1] += fdof; 8258 } 8259 numFIndices += dof; 8260 } 8261 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8262 8263 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8264 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8265 if (numFields) { 8266 const PetscInt **permsF[32] = {NULL}; 8267 const PetscInt **permsC[32] = {NULL}; 8268 8269 for (f = 0; f < numFields; f++) { 8270 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8271 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8272 } 8273 for (p = 0; p < numFPoints; p++) { 8274 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8275 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8276 } 8277 for (p = 0; p < numCPoints; p++) { 8278 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8279 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8280 } 8281 for (f = 0; f < numFields; f++) { 8282 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8283 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8284 } 8285 } else { 8286 const PetscInt **permsF = NULL; 8287 const PetscInt **permsC = NULL; 8288 8289 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8290 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8291 for (p = 0, off = 0; p < numFPoints; p++) { 8292 const PetscInt *perm = permsF ? permsF[p] : NULL; 8293 8294 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8295 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8296 } 8297 for (p = 0, off = 0; p < numCPoints; p++) { 8298 const PetscInt *perm = permsC ? permsC[p] : NULL; 8299 8300 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8301 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8302 } 8303 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8304 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8305 } 8306 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8307 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8308 PetscFunctionReturn(PETSC_SUCCESS); 8309 } 8310 8311 /*@C 8312 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8313 8314 Input Parameter: 8315 . dm - The `DMPLEX` object 8316 8317 Output Parameter: 8318 . cellHeight - The height of a cell 8319 8320 Level: developer 8321 8322 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8323 @*/ 8324 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8325 { 8326 DM_Plex *mesh = (DM_Plex *)dm->data; 8327 8328 PetscFunctionBegin; 8329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8330 PetscAssertPointer(cellHeight, 2); 8331 *cellHeight = mesh->vtkCellHeight; 8332 PetscFunctionReturn(PETSC_SUCCESS); 8333 } 8334 8335 /*@C 8336 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8337 8338 Input Parameters: 8339 + dm - The `DMPLEX` object 8340 - cellHeight - The height of a cell 8341 8342 Level: developer 8343 8344 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8345 @*/ 8346 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8347 { 8348 DM_Plex *mesh = (DM_Plex *)dm->data; 8349 8350 PetscFunctionBegin; 8351 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8352 mesh->vtkCellHeight = cellHeight; 8353 PetscFunctionReturn(PETSC_SUCCESS); 8354 } 8355 8356 /*@ 8357 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8358 8359 Input Parameters: 8360 + dm - The `DMPLEX` object 8361 - ct - The `DMPolytopeType` of the cell 8362 8363 Output Parameters: 8364 + start - The first cell of this type, or `NULL` 8365 - end - The upper bound on this celltype, or `NULL` 8366 8367 Level: advanced 8368 8369 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8370 @*/ 8371 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8372 { 8373 DM_Plex *mesh = (DM_Plex *)dm->data; 8374 DMLabel label; 8375 PetscInt pStart, pEnd; 8376 8377 PetscFunctionBegin; 8378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8379 if (start) { 8380 PetscAssertPointer(start, 3); 8381 *start = 0; 8382 } 8383 if (end) { 8384 PetscAssertPointer(end, 4); 8385 *end = 0; 8386 } 8387 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8388 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8389 if (mesh->tr) { 8390 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8391 } else { 8392 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8393 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8394 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8395 } 8396 PetscFunctionReturn(PETSC_SUCCESS); 8397 } 8398 8399 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8400 { 8401 PetscSection section, globalSection; 8402 PetscInt *numbers, p; 8403 8404 PetscFunctionBegin; 8405 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8406 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8407 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8408 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8409 PetscCall(PetscSectionSetUp(section)); 8410 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8411 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8412 for (p = pStart; p < pEnd; ++p) { 8413 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8414 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8415 else numbers[p - pStart] += shift; 8416 } 8417 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8418 if (globalSize) { 8419 PetscLayout layout; 8420 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8421 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8422 PetscCall(PetscLayoutDestroy(&layout)); 8423 } 8424 PetscCall(PetscSectionDestroy(§ion)); 8425 PetscCall(PetscSectionDestroy(&globalSection)); 8426 PetscFunctionReturn(PETSC_SUCCESS); 8427 } 8428 8429 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8430 { 8431 PetscInt cellHeight, cStart, cEnd; 8432 8433 PetscFunctionBegin; 8434 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8435 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8436 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8437 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8438 PetscFunctionReturn(PETSC_SUCCESS); 8439 } 8440 8441 /*@ 8442 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8443 8444 Input Parameter: 8445 . dm - The `DMPLEX` object 8446 8447 Output Parameter: 8448 . globalCellNumbers - Global cell numbers for all cells on this process 8449 8450 Level: developer 8451 8452 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8453 @*/ 8454 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8455 { 8456 DM_Plex *mesh = (DM_Plex *)dm->data; 8457 8458 PetscFunctionBegin; 8459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8460 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8461 *globalCellNumbers = mesh->globalCellNumbers; 8462 PetscFunctionReturn(PETSC_SUCCESS); 8463 } 8464 8465 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8466 { 8467 PetscInt vStart, vEnd; 8468 8469 PetscFunctionBegin; 8470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8471 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8472 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8473 PetscFunctionReturn(PETSC_SUCCESS); 8474 } 8475 8476 /*@ 8477 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8478 8479 Input Parameter: 8480 . dm - The `DMPLEX` object 8481 8482 Output Parameter: 8483 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8484 8485 Level: developer 8486 8487 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8488 @*/ 8489 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8490 { 8491 DM_Plex *mesh = (DM_Plex *)dm->data; 8492 8493 PetscFunctionBegin; 8494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8495 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8496 *globalVertexNumbers = mesh->globalVertexNumbers; 8497 PetscFunctionReturn(PETSC_SUCCESS); 8498 } 8499 8500 /*@ 8501 DMPlexCreatePointNumbering - Create a global numbering for all points. 8502 8503 Collective 8504 8505 Input Parameter: 8506 . dm - The `DMPLEX` object 8507 8508 Output Parameter: 8509 . globalPointNumbers - Global numbers for all points on this process 8510 8511 Level: developer 8512 8513 Notes: 8514 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8515 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8516 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8517 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8518 8519 The partitioned mesh is 8520 ``` 8521 (2)--0--(3)--1--(4) (1)--0--(2) 8522 ``` 8523 and its global numbering is 8524 ``` 8525 (3)--0--(4)--1--(5)--2--(6) 8526 ``` 8527 Then the global numbering is provided as 8528 ``` 8529 [0] Number of indices in set 5 8530 [0] 0 0 8531 [0] 1 1 8532 [0] 2 3 8533 [0] 3 4 8534 [0] 4 -6 8535 [1] Number of indices in set 3 8536 [1] 0 2 8537 [1] 1 5 8538 [1] 2 6 8539 ``` 8540 8541 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8542 @*/ 8543 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8544 { 8545 IS nums[4]; 8546 PetscInt depths[4], gdepths[4], starts[4]; 8547 PetscInt depth, d, shift = 0; 8548 PetscBool empty = PETSC_FALSE; 8549 8550 PetscFunctionBegin; 8551 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8552 PetscCall(DMPlexGetDepth(dm, &depth)); 8553 // For unstratified meshes use dim instead of depth 8554 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8555 // If any stratum is empty, we must mark all empty 8556 for (d = 0; d <= depth; ++d) { 8557 PetscInt end; 8558 8559 depths[d] = depth - d; 8560 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8561 if (!(starts[d] - end)) empty = PETSC_TRUE; 8562 } 8563 if (empty) 8564 for (d = 0; d <= depth; ++d) { 8565 depths[d] = -1; 8566 starts[d] = -1; 8567 } 8568 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8569 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8570 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]); 8571 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8572 for (d = 0; d <= depth; ++d) { 8573 PetscInt pStart, pEnd, gsize; 8574 8575 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8576 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8577 shift += gsize; 8578 } 8579 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8580 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8581 PetscFunctionReturn(PETSC_SUCCESS); 8582 } 8583 8584 /*@ 8585 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8586 8587 Input Parameter: 8588 . dm - The `DMPLEX` object 8589 8590 Output Parameter: 8591 . ranks - The rank field 8592 8593 Options Database Key: 8594 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8595 8596 Level: intermediate 8597 8598 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8599 @*/ 8600 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8601 { 8602 DM rdm; 8603 PetscFE fe; 8604 PetscScalar *r; 8605 PetscMPIInt rank; 8606 DMPolytopeType ct; 8607 PetscInt dim, cStart, cEnd, c; 8608 PetscBool simplex; 8609 8610 PetscFunctionBeginUser; 8611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8612 PetscAssertPointer(ranks, 2); 8613 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8614 PetscCall(DMClone(dm, &rdm)); 8615 PetscCall(DMGetDimension(rdm, &dim)); 8616 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8617 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8618 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8619 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8620 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8621 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8622 PetscCall(PetscFEDestroy(&fe)); 8623 PetscCall(DMCreateDS(rdm)); 8624 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8625 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8626 PetscCall(VecGetArray(*ranks, &r)); 8627 for (c = cStart; c < cEnd; ++c) { 8628 PetscScalar *lr; 8629 8630 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8631 if (lr) *lr = rank; 8632 } 8633 PetscCall(VecRestoreArray(*ranks, &r)); 8634 PetscCall(DMDestroy(&rdm)); 8635 PetscFunctionReturn(PETSC_SUCCESS); 8636 } 8637 8638 /*@ 8639 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8640 8641 Input Parameters: 8642 + dm - The `DMPLEX` 8643 - label - The `DMLabel` 8644 8645 Output Parameter: 8646 . val - The label value field 8647 8648 Options Database Key: 8649 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8650 8651 Level: intermediate 8652 8653 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8654 @*/ 8655 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8656 { 8657 DM rdm; 8658 PetscFE fe; 8659 PetscScalar *v; 8660 PetscInt dim, cStart, cEnd, c; 8661 8662 PetscFunctionBeginUser; 8663 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8664 PetscAssertPointer(label, 2); 8665 PetscAssertPointer(val, 3); 8666 PetscCall(DMClone(dm, &rdm)); 8667 PetscCall(DMGetDimension(rdm, &dim)); 8668 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8669 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8670 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8671 PetscCall(PetscFEDestroy(&fe)); 8672 PetscCall(DMCreateDS(rdm)); 8673 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8674 PetscCall(DMCreateGlobalVector(rdm, val)); 8675 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8676 PetscCall(VecGetArray(*val, &v)); 8677 for (c = cStart; c < cEnd; ++c) { 8678 PetscScalar *lv; 8679 PetscInt cval; 8680 8681 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8682 PetscCall(DMLabelGetValue(label, c, &cval)); 8683 *lv = cval; 8684 } 8685 PetscCall(VecRestoreArray(*val, &v)); 8686 PetscCall(DMDestroy(&rdm)); 8687 PetscFunctionReturn(PETSC_SUCCESS); 8688 } 8689 8690 /*@ 8691 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8692 8693 Input Parameter: 8694 . dm - The `DMPLEX` object 8695 8696 Level: developer 8697 8698 Notes: 8699 This is a useful diagnostic when creating meshes programmatically. 8700 8701 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8702 8703 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8704 @*/ 8705 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8706 { 8707 PetscSection coneSection, supportSection; 8708 const PetscInt *cone, *support; 8709 PetscInt coneSize, c, supportSize, s; 8710 PetscInt pStart, pEnd, p, pp, csize, ssize; 8711 PetscBool storagecheck = PETSC_TRUE; 8712 8713 PetscFunctionBegin; 8714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8715 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8716 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8717 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8718 /* Check that point p is found in the support of its cone points, and vice versa */ 8719 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8720 for (p = pStart; p < pEnd; ++p) { 8721 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8722 PetscCall(DMPlexGetCone(dm, p, &cone)); 8723 for (c = 0; c < coneSize; ++c) { 8724 PetscBool dup = PETSC_FALSE; 8725 PetscInt d; 8726 for (d = c - 1; d >= 0; --d) { 8727 if (cone[c] == cone[d]) { 8728 dup = PETSC_TRUE; 8729 break; 8730 } 8731 } 8732 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8733 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8734 for (s = 0; s < supportSize; ++s) { 8735 if (support[s] == p) break; 8736 } 8737 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8738 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8739 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8740 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8741 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8742 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8743 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8744 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]); 8745 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8746 } 8747 } 8748 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8749 if (p != pp) { 8750 storagecheck = PETSC_FALSE; 8751 continue; 8752 } 8753 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8754 PetscCall(DMPlexGetSupport(dm, p, &support)); 8755 for (s = 0; s < supportSize; ++s) { 8756 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8757 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8758 for (c = 0; c < coneSize; ++c) { 8759 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8760 if (cone[c] != pp) { 8761 c = 0; 8762 break; 8763 } 8764 if (cone[c] == p) break; 8765 } 8766 if (c >= coneSize) { 8767 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8768 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8769 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8770 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8771 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8772 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8773 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8774 } 8775 } 8776 } 8777 if (storagecheck) { 8778 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8779 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8780 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8781 } 8782 PetscFunctionReturn(PETSC_SUCCESS); 8783 } 8784 8785 /* 8786 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. 8787 */ 8788 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8789 { 8790 DMPolytopeType cct; 8791 PetscInt ptpoints[4]; 8792 const PetscInt *cone, *ccone, *ptcone; 8793 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8794 8795 PetscFunctionBegin; 8796 *unsplit = 0; 8797 switch (ct) { 8798 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8799 ptpoints[npt++] = c; 8800 break; 8801 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8802 PetscCall(DMPlexGetCone(dm, c, &cone)); 8803 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8804 for (cp = 0; cp < coneSize; ++cp) { 8805 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8806 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8807 } 8808 break; 8809 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8810 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8811 PetscCall(DMPlexGetCone(dm, c, &cone)); 8812 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8813 for (cp = 0; cp < coneSize; ++cp) { 8814 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8815 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8816 for (ccp = 0; ccp < cconeSize; ++ccp) { 8817 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8818 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8819 PetscInt p; 8820 for (p = 0; p < npt; ++p) 8821 if (ptpoints[p] == ccone[ccp]) break; 8822 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8823 } 8824 } 8825 } 8826 break; 8827 default: 8828 break; 8829 } 8830 for (pt = 0; pt < npt; ++pt) { 8831 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8832 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8833 } 8834 PetscFunctionReturn(PETSC_SUCCESS); 8835 } 8836 8837 /*@ 8838 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8839 8840 Input Parameters: 8841 + dm - The `DMPLEX` object 8842 - cellHeight - Normally 0 8843 8844 Level: developer 8845 8846 Notes: 8847 This is a useful diagnostic when creating meshes programmatically. 8848 Currently applicable only to homogeneous simplex or tensor meshes. 8849 8850 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8851 8852 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8853 @*/ 8854 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8855 { 8856 DMPlexInterpolatedFlag interp; 8857 DMPolytopeType ct; 8858 PetscInt vStart, vEnd, cStart, cEnd, c; 8859 8860 PetscFunctionBegin; 8861 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8862 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8863 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8864 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8865 for (c = cStart; c < cEnd; ++c) { 8866 PetscInt *closure = NULL; 8867 PetscInt coneSize, closureSize, cl, Nv = 0; 8868 8869 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8870 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8871 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8872 if (interp == DMPLEX_INTERPOLATED_FULL) { 8873 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8874 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)); 8875 } 8876 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8877 for (cl = 0; cl < closureSize * 2; cl += 2) { 8878 const PetscInt p = closure[cl]; 8879 if ((p >= vStart) && (p < vEnd)) ++Nv; 8880 } 8881 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8882 /* Special Case: Tensor faces with identified vertices */ 8883 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8884 PetscInt unsplit; 8885 8886 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8887 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8888 } 8889 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)); 8890 } 8891 PetscFunctionReturn(PETSC_SUCCESS); 8892 } 8893 8894 /*@ 8895 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8896 8897 Collective 8898 8899 Input Parameters: 8900 + dm - The `DMPLEX` object 8901 - cellHeight - Normally 0 8902 8903 Level: developer 8904 8905 Notes: 8906 This is a useful diagnostic when creating meshes programmatically. 8907 This routine is only relevant for meshes that are fully interpolated across all ranks. 8908 It will error out if a partially interpolated mesh is given on some rank. 8909 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8910 8911 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8912 8913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8914 @*/ 8915 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8916 { 8917 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8918 DMPlexInterpolatedFlag interpEnum; 8919 8920 PetscFunctionBegin; 8921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8922 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8923 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8924 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8925 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8926 PetscFunctionReturn(PETSC_SUCCESS); 8927 } 8928 8929 PetscCall(DMGetDimension(dm, &dim)); 8930 PetscCall(DMPlexGetDepth(dm, &depth)); 8931 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8932 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8933 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8934 for (c = cStart; c < cEnd; ++c) { 8935 const PetscInt *cone, *ornt, *faceSizes, *faces; 8936 const DMPolytopeType *faceTypes; 8937 DMPolytopeType ct; 8938 PetscInt numFaces, coneSize, f; 8939 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8940 8941 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8942 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8943 if (unsplit) continue; 8944 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8945 PetscCall(DMPlexGetCone(dm, c, &cone)); 8946 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8947 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8948 for (cl = 0; cl < closureSize * 2; cl += 2) { 8949 const PetscInt p = closure[cl]; 8950 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8951 } 8952 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8953 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); 8954 for (f = 0; f < numFaces; ++f) { 8955 DMPolytopeType fct; 8956 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8957 8958 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8959 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8960 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8961 const PetscInt p = fclosure[cl]; 8962 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8963 } 8964 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]); 8965 for (v = 0; v < fnumCorners; ++v) { 8966 if (fclosure[v] != faces[fOff + v]) { 8967 PetscInt v1; 8968 8969 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8970 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8971 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8972 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8973 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8974 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]); 8975 } 8976 } 8977 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8978 fOff += faceSizes[f]; 8979 } 8980 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8981 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8982 } 8983 } 8984 PetscFunctionReturn(PETSC_SUCCESS); 8985 } 8986 8987 /*@ 8988 DMPlexCheckGeometry - Check the geometry of mesh cells 8989 8990 Input Parameter: 8991 . dm - The `DMPLEX` object 8992 8993 Level: developer 8994 8995 Notes: 8996 This is a useful diagnostic when creating meshes programmatically. 8997 8998 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8999 9000 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9001 @*/ 9002 PetscErrorCode DMPlexCheckGeometry(DM dm) 9003 { 9004 Vec coordinates; 9005 PetscReal detJ, J[9], refVol = 1.0; 9006 PetscReal vol; 9007 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9008 9009 PetscFunctionBegin; 9010 PetscCall(DMGetDimension(dm, &dim)); 9011 PetscCall(DMGetCoordinateDim(dm, &dE)); 9012 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9013 PetscCall(DMPlexGetDepth(dm, &depth)); 9014 for (d = 0; d < dim; ++d) refVol *= 2.0; 9015 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9016 /* Make sure local coordinates are created, because that step is collective */ 9017 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9018 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9019 for (c = cStart; c < cEnd; ++c) { 9020 DMPolytopeType ct; 9021 PetscInt unsplit; 9022 PetscBool ignoreZeroVol = PETSC_FALSE; 9023 9024 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9025 switch (ct) { 9026 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9027 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9028 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9029 ignoreZeroVol = PETSC_TRUE; 9030 break; 9031 default: 9032 break; 9033 } 9034 switch (ct) { 9035 case DM_POLYTOPE_TRI_PRISM: 9036 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9037 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9038 case DM_POLYTOPE_PYRAMID: 9039 continue; 9040 default: 9041 break; 9042 } 9043 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9044 if (unsplit) continue; 9045 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9046 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); 9047 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9048 /* This should work with periodicity since DG coordinates should be used */ 9049 if (depth > 1) { 9050 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9051 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); 9052 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9053 } 9054 } 9055 PetscFunctionReturn(PETSC_SUCCESS); 9056 } 9057 9058 /*@ 9059 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9060 9061 Collective 9062 9063 Input Parameters: 9064 + dm - The `DMPLEX` object 9065 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9066 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9067 9068 Level: developer 9069 9070 Notes: 9071 This is mainly intended for debugging/testing purposes. 9072 9073 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9074 9075 Extra roots can come from priodic cuts, where additional points appear on the boundary 9076 9077 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9078 @*/ 9079 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9080 { 9081 PetscInt l, nleaves, nroots, overlap; 9082 const PetscInt *locals; 9083 const PetscSFNode *remotes; 9084 PetscBool distributed; 9085 MPI_Comm comm; 9086 PetscMPIInt rank; 9087 9088 PetscFunctionBegin; 9089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9090 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9091 else pointSF = dm->sf; 9092 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9093 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9094 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9095 { 9096 PetscMPIInt mpiFlag; 9097 9098 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9099 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9100 } 9101 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9102 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9103 if (!distributed) { 9104 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); 9105 PetscFunctionReturn(PETSC_SUCCESS); 9106 } 9107 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); 9108 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9109 9110 /* Check SF graph is compatible with DMPlex chart */ 9111 { 9112 PetscInt pStart, pEnd, maxLeaf; 9113 9114 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9115 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9116 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9117 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9118 } 9119 9120 /* Check Point SF has no local points referenced */ 9121 for (l = 0; l < nleaves; l++) { 9122 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); 9123 } 9124 9125 /* Check there are no cells in interface */ 9126 if (!overlap) { 9127 PetscInt cellHeight, cStart, cEnd; 9128 9129 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9130 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9131 for (l = 0; l < nleaves; ++l) { 9132 const PetscInt point = locals ? locals[l] : l; 9133 9134 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9135 } 9136 } 9137 9138 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9139 { 9140 const PetscInt *rootdegree; 9141 9142 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9143 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9144 for (l = 0; l < nleaves; ++l) { 9145 const PetscInt point = locals ? locals[l] : l; 9146 const PetscInt *cone; 9147 PetscInt coneSize, c, idx; 9148 9149 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9150 PetscCall(DMPlexGetCone(dm, point, &cone)); 9151 for (c = 0; c < coneSize; ++c) { 9152 if (!rootdegree[cone[c]]) { 9153 if (locals) { 9154 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9155 } else { 9156 idx = (cone[c] < nleaves) ? cone[c] : -1; 9157 } 9158 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9159 } 9160 } 9161 } 9162 } 9163 PetscFunctionReturn(PETSC_SUCCESS); 9164 } 9165 9166 /*@ 9167 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9168 9169 Input Parameter: 9170 . dm - The `DMPLEX` object 9171 9172 Level: developer 9173 9174 Notes: 9175 This is a useful diagnostic when creating meshes programmatically. 9176 9177 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9178 9179 Currently does not include `DMPlexCheckCellShape()`. 9180 9181 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9182 @*/ 9183 PetscErrorCode DMPlexCheck(DM dm) 9184 { 9185 PetscInt cellHeight; 9186 9187 PetscFunctionBegin; 9188 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9189 PetscCall(DMPlexCheckSymmetry(dm)); 9190 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9191 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9192 PetscCall(DMPlexCheckGeometry(dm)); 9193 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9194 PetscCall(DMPlexCheckInterfaceCones(dm)); 9195 PetscFunctionReturn(PETSC_SUCCESS); 9196 } 9197 9198 typedef struct cell_stats { 9199 PetscReal min, max, sum, squaresum; 9200 PetscInt count; 9201 } cell_stats_t; 9202 9203 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9204 { 9205 PetscInt i, N = *len; 9206 9207 for (i = 0; i < N; i++) { 9208 cell_stats_t *A = (cell_stats_t *)a; 9209 cell_stats_t *B = (cell_stats_t *)b; 9210 9211 B->min = PetscMin(A->min, B->min); 9212 B->max = PetscMax(A->max, B->max); 9213 B->sum += A->sum; 9214 B->squaresum += A->squaresum; 9215 B->count += A->count; 9216 } 9217 } 9218 9219 /*@ 9220 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9221 9222 Collective 9223 9224 Input Parameters: 9225 + dm - The `DMPLEX` object 9226 . output - If true, statistics will be displayed on `stdout` 9227 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9228 9229 Level: developer 9230 9231 Notes: 9232 This is mainly intended for debugging/testing purposes. 9233 9234 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9235 9236 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9237 @*/ 9238 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9239 { 9240 DM dmCoarse; 9241 cell_stats_t stats, globalStats; 9242 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9243 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9244 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9245 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9246 PetscMPIInt rank, size; 9247 9248 PetscFunctionBegin; 9249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9250 stats.min = PETSC_MAX_REAL; 9251 stats.max = PETSC_MIN_REAL; 9252 stats.sum = stats.squaresum = 0.; 9253 stats.count = 0; 9254 9255 PetscCallMPI(MPI_Comm_size(comm, &size)); 9256 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9257 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9258 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9259 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9260 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9261 for (c = cStart; c < cEnd; c++) { 9262 PetscInt i; 9263 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9264 9265 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9266 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9267 for (i = 0; i < PetscSqr(cdim); ++i) { 9268 frobJ += J[i] * J[i]; 9269 frobInvJ += invJ[i] * invJ[i]; 9270 } 9271 cond2 = frobJ * frobInvJ; 9272 cond = PetscSqrtReal(cond2); 9273 9274 stats.min = PetscMin(stats.min, cond); 9275 stats.max = PetscMax(stats.max, cond); 9276 stats.sum += cond; 9277 stats.squaresum += cond2; 9278 stats.count++; 9279 if (output && cond > limit) { 9280 PetscSection coordSection; 9281 Vec coordsLocal; 9282 PetscScalar *coords = NULL; 9283 PetscInt Nv, d, clSize, cl, *closure = NULL; 9284 9285 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9286 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9287 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9288 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9289 for (i = 0; i < Nv / cdim; ++i) { 9290 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9291 for (d = 0; d < cdim; ++d) { 9292 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9293 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9294 } 9295 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9296 } 9297 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9298 for (cl = 0; cl < clSize * 2; cl += 2) { 9299 const PetscInt edge = closure[cl]; 9300 9301 if ((edge >= eStart) && (edge < eEnd)) { 9302 PetscReal len; 9303 9304 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9305 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9306 } 9307 } 9308 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9309 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9310 } 9311 } 9312 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9313 9314 if (size > 1) { 9315 PetscMPIInt blockLengths[2] = {4, 1}; 9316 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9317 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9318 MPI_Op statReduce; 9319 9320 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9321 PetscCallMPI(MPI_Type_commit(&statType)); 9322 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9323 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9324 PetscCallMPI(MPI_Op_free(&statReduce)); 9325 PetscCallMPI(MPI_Type_free(&statType)); 9326 } else { 9327 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9328 } 9329 if (rank == 0) { 9330 count = globalStats.count; 9331 min = globalStats.min; 9332 max = globalStats.max; 9333 mean = globalStats.sum / globalStats.count; 9334 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9335 } 9336 9337 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)); 9338 PetscCall(PetscFree2(J, invJ)); 9339 9340 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9341 if (dmCoarse) { 9342 PetscBool isplex; 9343 9344 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9345 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9346 } 9347 PetscFunctionReturn(PETSC_SUCCESS); 9348 } 9349 9350 /*@ 9351 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9352 orthogonal quality below given tolerance. 9353 9354 Collective 9355 9356 Input Parameters: 9357 + dm - The `DMPLEX` object 9358 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9359 - atol - [0, 1] Absolute tolerance for tagging cells. 9360 9361 Output Parameters: 9362 + OrthQual - `Vec` containing orthogonal quality per cell 9363 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9364 9365 Options Database Keys: 9366 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9367 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9368 9369 Level: intermediate 9370 9371 Notes: 9372 Orthogonal quality is given by the following formula\: 9373 9374 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9375 9376 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 9377 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9378 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9379 calculating the cosine of the angle between these vectors. 9380 9381 Orthogonal quality ranges from 1 (best) to 0 (worst). 9382 9383 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9384 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9385 9386 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9387 9388 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9389 @*/ 9390 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9391 { 9392 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9393 PetscInt *idx; 9394 PetscScalar *oqVals; 9395 const PetscScalar *cellGeomArr, *faceGeomArr; 9396 PetscReal *ci, *fi, *Ai; 9397 MPI_Comm comm; 9398 Vec cellgeom, facegeom; 9399 DM dmFace, dmCell; 9400 IS glob; 9401 ISLocalToGlobalMapping ltog; 9402 PetscViewer vwr; 9403 9404 PetscFunctionBegin; 9405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9406 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9407 PetscAssertPointer(OrthQual, 4); 9408 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9409 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9410 PetscCall(DMGetDimension(dm, &nc)); 9411 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9412 { 9413 DMPlexInterpolatedFlag interpFlag; 9414 9415 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9416 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9417 PetscMPIInt rank; 9418 9419 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9420 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9421 } 9422 } 9423 if (OrthQualLabel) { 9424 PetscAssertPointer(OrthQualLabel, 5); 9425 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9426 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9427 } else { 9428 *OrthQualLabel = NULL; 9429 } 9430 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9431 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9432 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9433 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9434 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9435 PetscCall(VecCreate(comm, OrthQual)); 9436 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9437 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9438 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9439 PetscCall(VecSetUp(*OrthQual)); 9440 PetscCall(ISDestroy(&glob)); 9441 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9442 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9443 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9444 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9445 PetscCall(VecGetDM(cellgeom, &dmCell)); 9446 PetscCall(VecGetDM(facegeom, &dmFace)); 9447 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9448 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9449 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9450 PetscInt cellarr[2], *adj = NULL; 9451 PetscScalar *cArr, *fArr; 9452 PetscReal minvalc = 1.0, minvalf = 1.0; 9453 PetscFVCellGeom *cg; 9454 9455 idx[cellIter] = cell - cStart; 9456 cellarr[0] = cell; 9457 /* Make indexing into cellGeom easier */ 9458 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9459 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9460 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9461 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9462 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9463 PetscInt i; 9464 const PetscInt neigh = adj[cellneigh]; 9465 PetscReal normci = 0, normfi = 0, normai = 0; 9466 PetscFVCellGeom *cgneigh; 9467 PetscFVFaceGeom *fg; 9468 9469 /* Don't count ourselves in the neighbor list */ 9470 if (neigh == cell) continue; 9471 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9472 cellarr[1] = neigh; 9473 { 9474 PetscInt numcovpts; 9475 const PetscInt *covpts; 9476 9477 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9478 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9479 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9480 } 9481 9482 /* Compute c_i, f_i and their norms */ 9483 for (i = 0; i < nc; i++) { 9484 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9485 fi[i] = fg->centroid[i] - cg->centroid[i]; 9486 Ai[i] = fg->normal[i]; 9487 normci += PetscPowReal(ci[i], 2); 9488 normfi += PetscPowReal(fi[i], 2); 9489 normai += PetscPowReal(Ai[i], 2); 9490 } 9491 normci = PetscSqrtReal(normci); 9492 normfi = PetscSqrtReal(normfi); 9493 normai = PetscSqrtReal(normai); 9494 9495 /* Normalize and compute for each face-cell-normal pair */ 9496 for (i = 0; i < nc; i++) { 9497 ci[i] = ci[i] / normci; 9498 fi[i] = fi[i] / normfi; 9499 Ai[i] = Ai[i] / normai; 9500 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9501 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9502 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9503 } 9504 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9505 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9506 } 9507 PetscCall(PetscFree(adj)); 9508 PetscCall(PetscFree2(cArr, fArr)); 9509 /* Defer to cell if they're equal */ 9510 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9511 if (OrthQualLabel) { 9512 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9513 } 9514 } 9515 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9516 PetscCall(VecAssemblyBegin(*OrthQual)); 9517 PetscCall(VecAssemblyEnd(*OrthQual)); 9518 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9519 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9520 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9521 if (OrthQualLabel) { 9522 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9523 } 9524 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9525 PetscCall(PetscViewerDestroy(&vwr)); 9526 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9527 PetscFunctionReturn(PETSC_SUCCESS); 9528 } 9529 9530 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9531 * interpolator construction */ 9532 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9533 { 9534 PetscSection section, newSection, gsection; 9535 PetscSF sf; 9536 PetscBool hasConstraints, ghasConstraints; 9537 9538 PetscFunctionBegin; 9539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9540 PetscAssertPointer(odm, 2); 9541 PetscCall(DMGetLocalSection(dm, §ion)); 9542 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9543 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9544 if (!ghasConstraints) { 9545 PetscCall(PetscObjectReference((PetscObject)dm)); 9546 *odm = dm; 9547 PetscFunctionReturn(PETSC_SUCCESS); 9548 } 9549 PetscCall(DMClone(dm, odm)); 9550 PetscCall(DMCopyFields(dm, *odm)); 9551 PetscCall(DMGetLocalSection(*odm, &newSection)); 9552 PetscCall(DMGetPointSF(*odm, &sf)); 9553 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9554 PetscCall(DMSetGlobalSection(*odm, gsection)); 9555 PetscCall(PetscSectionDestroy(&gsection)); 9556 PetscFunctionReturn(PETSC_SUCCESS); 9557 } 9558 9559 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9560 { 9561 DM dmco, dmfo; 9562 Mat interpo; 9563 Vec rscale; 9564 Vec cglobalo, clocal; 9565 Vec fglobal, fglobalo, flocal; 9566 PetscBool regular; 9567 9568 PetscFunctionBegin; 9569 PetscCall(DMGetFullDM(dmc, &dmco)); 9570 PetscCall(DMGetFullDM(dmf, &dmfo)); 9571 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9572 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9573 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9574 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9575 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9576 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9577 PetscCall(VecSet(cglobalo, 0.)); 9578 PetscCall(VecSet(clocal, 0.)); 9579 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9580 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9581 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9582 PetscCall(VecSet(fglobal, 0.)); 9583 PetscCall(VecSet(fglobalo, 0.)); 9584 PetscCall(VecSet(flocal, 0.)); 9585 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9586 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9587 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9588 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9589 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9590 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9591 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9592 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9593 *shift = fglobal; 9594 PetscCall(VecDestroy(&flocal)); 9595 PetscCall(VecDestroy(&fglobalo)); 9596 PetscCall(VecDestroy(&clocal)); 9597 PetscCall(VecDestroy(&cglobalo)); 9598 PetscCall(VecDestroy(&rscale)); 9599 PetscCall(MatDestroy(&interpo)); 9600 PetscCall(DMDestroy(&dmfo)); 9601 PetscCall(DMDestroy(&dmco)); 9602 PetscFunctionReturn(PETSC_SUCCESS); 9603 } 9604 9605 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9606 { 9607 PetscObject shifto; 9608 Vec shift; 9609 9610 PetscFunctionBegin; 9611 if (!interp) { 9612 Vec rscale; 9613 9614 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9615 PetscCall(VecDestroy(&rscale)); 9616 } else { 9617 PetscCall(PetscObjectReference((PetscObject)interp)); 9618 } 9619 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9620 if (!shifto) { 9621 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9622 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9623 shifto = (PetscObject)shift; 9624 PetscCall(VecDestroy(&shift)); 9625 } 9626 shift = (Vec)shifto; 9627 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9628 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9629 PetscCall(MatDestroy(&interp)); 9630 PetscFunctionReturn(PETSC_SUCCESS); 9631 } 9632 9633 /* Pointwise interpolation 9634 Just code FEM for now 9635 u^f = I u^c 9636 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9637 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9638 I_{ij} = psi^f_i phi^c_j 9639 */ 9640 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9641 { 9642 PetscSection gsc, gsf; 9643 PetscInt m, n; 9644 void *ctx; 9645 DM cdm; 9646 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9647 9648 PetscFunctionBegin; 9649 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9650 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9651 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9652 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9653 9654 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9655 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9656 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9657 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9658 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9659 9660 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9661 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9662 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9663 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9664 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9665 if (scaling) { 9666 /* Use naive scaling */ 9667 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9668 } 9669 PetscFunctionReturn(PETSC_SUCCESS); 9670 } 9671 9672 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9673 { 9674 VecScatter ctx; 9675 9676 PetscFunctionBegin; 9677 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9678 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9679 PetscCall(VecScatterDestroy(&ctx)); 9680 PetscFunctionReturn(PETSC_SUCCESS); 9681 } 9682 9683 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[]) 9684 { 9685 const PetscInt Nc = uOff[1] - uOff[0]; 9686 PetscInt c; 9687 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9688 } 9689 9690 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9691 { 9692 DM dmc; 9693 PetscDS ds; 9694 Vec ones, locmass; 9695 IS cellIS; 9696 PetscFormKey key; 9697 PetscInt depth; 9698 9699 PetscFunctionBegin; 9700 PetscCall(DMClone(dm, &dmc)); 9701 PetscCall(DMCopyDisc(dm, dmc)); 9702 PetscCall(DMGetDS(dmc, &ds)); 9703 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9704 PetscCall(DMCreateGlobalVector(dmc, mass)); 9705 PetscCall(DMGetLocalVector(dmc, &ones)); 9706 PetscCall(DMGetLocalVector(dmc, &locmass)); 9707 PetscCall(DMPlexGetDepth(dmc, &depth)); 9708 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9709 PetscCall(VecSet(locmass, 0.0)); 9710 PetscCall(VecSet(ones, 1.0)); 9711 key.label = NULL; 9712 key.value = 0; 9713 key.field = 0; 9714 key.part = 0; 9715 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9716 PetscCall(ISDestroy(&cellIS)); 9717 PetscCall(VecSet(*mass, 0.0)); 9718 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9719 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9720 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9721 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9722 PetscCall(DMDestroy(&dmc)); 9723 PetscFunctionReturn(PETSC_SUCCESS); 9724 } 9725 9726 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9727 { 9728 PetscSection gsc, gsf; 9729 PetscInt m, n; 9730 void *ctx; 9731 DM cdm; 9732 PetscBool regular; 9733 9734 PetscFunctionBegin; 9735 if (dmFine == dmCoarse) { 9736 DM dmc; 9737 PetscDS ds; 9738 PetscWeakForm wf; 9739 Vec u; 9740 IS cellIS; 9741 PetscFormKey key; 9742 PetscInt depth; 9743 9744 PetscCall(DMClone(dmFine, &dmc)); 9745 PetscCall(DMCopyDisc(dmFine, dmc)); 9746 PetscCall(DMGetDS(dmc, &ds)); 9747 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9748 PetscCall(PetscWeakFormClear(wf)); 9749 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9750 PetscCall(DMCreateMatrix(dmc, mass)); 9751 PetscCall(DMGetLocalVector(dmc, &u)); 9752 PetscCall(DMPlexGetDepth(dmc, &depth)); 9753 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9754 PetscCall(MatZeroEntries(*mass)); 9755 key.label = NULL; 9756 key.value = 0; 9757 key.field = 0; 9758 key.part = 0; 9759 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9760 PetscCall(ISDestroy(&cellIS)); 9761 PetscCall(DMRestoreLocalVector(dmc, &u)); 9762 PetscCall(DMDestroy(&dmc)); 9763 } else { 9764 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9765 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9766 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9767 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9768 9769 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9770 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9771 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9772 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9773 9774 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9775 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9776 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9777 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9778 } 9779 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9780 PetscFunctionReturn(PETSC_SUCCESS); 9781 } 9782 9783 /*@ 9784 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9785 9786 Input Parameter: 9787 . dm - The `DMPLEX` object 9788 9789 Output Parameter: 9790 . regular - The flag 9791 9792 Level: intermediate 9793 9794 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9795 @*/ 9796 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9797 { 9798 PetscFunctionBegin; 9799 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9800 PetscAssertPointer(regular, 2); 9801 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9802 PetscFunctionReturn(PETSC_SUCCESS); 9803 } 9804 9805 /*@ 9806 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9807 9808 Input Parameters: 9809 + dm - The `DMPLEX` object 9810 - regular - The flag 9811 9812 Level: intermediate 9813 9814 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9815 @*/ 9816 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9817 { 9818 PetscFunctionBegin; 9819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9820 ((DM_Plex *)dm->data)->regularRefinement = regular; 9821 PetscFunctionReturn(PETSC_SUCCESS); 9822 } 9823 9824 /*@ 9825 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9826 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9827 9828 Not Collective 9829 9830 Input Parameter: 9831 . dm - The `DMPLEX` object 9832 9833 Output Parameters: 9834 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9835 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9836 9837 Level: intermediate 9838 9839 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9840 @*/ 9841 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9842 { 9843 DM_Plex *plex = (DM_Plex *)dm->data; 9844 9845 PetscFunctionBegin; 9846 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9847 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9848 if (anchorSection) *anchorSection = plex->anchorSection; 9849 if (anchorIS) *anchorIS = plex->anchorIS; 9850 PetscFunctionReturn(PETSC_SUCCESS); 9851 } 9852 9853 /*@ 9854 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. 9855 9856 Collective 9857 9858 Input Parameters: 9859 + dm - The `DMPLEX` object 9860 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9861 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9862 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9863 9864 Level: intermediate 9865 9866 Notes: 9867 Unlike boundary conditions, when a point's degrees of freedom in a section are constrained to 9868 an outside value, the anchor constraints set a point's degrees of freedom to be a linear 9869 combination of other points' degrees of freedom. 9870 9871 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9872 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9873 9874 The reference counts of `anchorSection` and `anchorIS` are incremented. 9875 9876 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9877 @*/ 9878 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9879 { 9880 DM_Plex *plex = (DM_Plex *)dm->data; 9881 PetscMPIInt result; 9882 9883 PetscFunctionBegin; 9884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9885 if (anchorSection) { 9886 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9887 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9888 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9889 } 9890 if (anchorIS) { 9891 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9892 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9893 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9894 } 9895 9896 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9897 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9898 plex->anchorSection = anchorSection; 9899 9900 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9901 PetscCall(ISDestroy(&plex->anchorIS)); 9902 plex->anchorIS = anchorIS; 9903 9904 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9905 PetscInt size, a, pStart, pEnd; 9906 const PetscInt *anchors; 9907 9908 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9909 PetscCall(ISGetLocalSize(anchorIS, &size)); 9910 PetscCall(ISGetIndices(anchorIS, &anchors)); 9911 for (a = 0; a < size; a++) { 9912 PetscInt p; 9913 9914 p = anchors[a]; 9915 if (p >= pStart && p < pEnd) { 9916 PetscInt dof; 9917 9918 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9919 if (dof) { 9920 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9921 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9922 } 9923 } 9924 } 9925 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9926 } 9927 /* reset the generic constraints */ 9928 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9929 PetscFunctionReturn(PETSC_SUCCESS); 9930 } 9931 9932 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9933 { 9934 PetscSection anchorSection; 9935 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9936 9937 PetscFunctionBegin; 9938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9939 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9940 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9941 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9942 if (numFields) { 9943 PetscInt f; 9944 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9945 9946 for (f = 0; f < numFields; f++) { 9947 PetscInt numComp; 9948 9949 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9950 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9951 } 9952 } 9953 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9954 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9955 pStart = PetscMax(pStart, sStart); 9956 pEnd = PetscMin(pEnd, sEnd); 9957 pEnd = PetscMax(pStart, pEnd); 9958 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9959 for (p = pStart; p < pEnd; p++) { 9960 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9961 if (dof) { 9962 PetscCall(PetscSectionGetDof(section, p, &dof)); 9963 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9964 for (f = 0; f < numFields; f++) { 9965 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9966 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9967 } 9968 } 9969 } 9970 PetscCall(PetscSectionSetUp(*cSec)); 9971 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9972 PetscFunctionReturn(PETSC_SUCCESS); 9973 } 9974 9975 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9976 { 9977 PetscSection aSec; 9978 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9979 const PetscInt *anchors; 9980 PetscInt numFields, f; 9981 IS aIS; 9982 MatType mtype; 9983 PetscBool iscuda, iskokkos; 9984 9985 PetscFunctionBegin; 9986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9987 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9988 PetscCall(PetscSectionGetStorageSize(section, &n)); 9989 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9990 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9991 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9992 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9993 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9994 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9995 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9996 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9997 else mtype = MATSEQAIJ; 9998 PetscCall(MatSetType(*cMat, mtype)); 9999 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 10000 PetscCall(ISGetIndices(aIS, &anchors)); 10001 /* cSec will be a subset of aSec and section */ 10002 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 10003 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10004 PetscCall(PetscMalloc1(m + 1, &i)); 10005 i[0] = 0; 10006 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10007 for (p = pStart; p < pEnd; p++) { 10008 PetscInt rDof, rOff, r; 10009 10010 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10011 if (!rDof) continue; 10012 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10013 if (numFields) { 10014 for (f = 0; f < numFields; f++) { 10015 annz = 0; 10016 for (r = 0; r < rDof; r++) { 10017 a = anchors[rOff + r]; 10018 if (a < sStart || a >= sEnd) continue; 10019 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10020 annz += aDof; 10021 } 10022 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10023 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10024 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10025 } 10026 } else { 10027 annz = 0; 10028 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10029 for (q = 0; q < dof; q++) { 10030 a = anchors[rOff + q]; 10031 if (a < sStart || a >= sEnd) continue; 10032 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10033 annz += aDof; 10034 } 10035 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10036 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10037 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10038 } 10039 } 10040 nnz = i[m]; 10041 PetscCall(PetscMalloc1(nnz, &j)); 10042 offset = 0; 10043 for (p = pStart; p < pEnd; p++) { 10044 if (numFields) { 10045 for (f = 0; f < numFields; f++) { 10046 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10047 for (q = 0; q < dof; q++) { 10048 PetscInt rDof, rOff, r; 10049 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10050 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10051 for (r = 0; r < rDof; r++) { 10052 PetscInt s; 10053 10054 a = anchors[rOff + r]; 10055 if (a < sStart || a >= sEnd) continue; 10056 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10057 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10058 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10059 } 10060 } 10061 } 10062 } else { 10063 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10064 for (q = 0; q < dof; q++) { 10065 PetscInt rDof, rOff, r; 10066 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10067 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10068 for (r = 0; r < rDof; r++) { 10069 PetscInt s; 10070 10071 a = anchors[rOff + r]; 10072 if (a < sStart || a >= sEnd) continue; 10073 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10074 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10075 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10076 } 10077 } 10078 } 10079 } 10080 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10081 PetscCall(PetscFree(i)); 10082 PetscCall(PetscFree(j)); 10083 PetscCall(ISRestoreIndices(aIS, &anchors)); 10084 PetscFunctionReturn(PETSC_SUCCESS); 10085 } 10086 10087 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10088 { 10089 DM_Plex *plex = (DM_Plex *)dm->data; 10090 PetscSection anchorSection, section, cSec; 10091 Mat cMat; 10092 10093 PetscFunctionBegin; 10094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10095 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10096 if (anchorSection) { 10097 PetscInt Nf; 10098 10099 PetscCall(DMGetLocalSection(dm, §ion)); 10100 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10101 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10102 PetscCall(DMGetNumFields(dm, &Nf)); 10103 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10104 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10105 PetscCall(PetscSectionDestroy(&cSec)); 10106 PetscCall(MatDestroy(&cMat)); 10107 } 10108 PetscFunctionReturn(PETSC_SUCCESS); 10109 } 10110 10111 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10112 { 10113 IS subis; 10114 PetscSection section, subsection; 10115 10116 PetscFunctionBegin; 10117 PetscCall(DMGetLocalSection(dm, §ion)); 10118 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10119 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10120 /* Create subdomain */ 10121 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10122 /* Create submodel */ 10123 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10124 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10125 PetscCall(DMSetLocalSection(*subdm, subsection)); 10126 PetscCall(PetscSectionDestroy(&subsection)); 10127 PetscCall(DMCopyDisc(dm, *subdm)); 10128 /* Create map from submodel to global model */ 10129 if (is) { 10130 PetscSection sectionGlobal, subsectionGlobal; 10131 IS spIS; 10132 const PetscInt *spmap; 10133 PetscInt *subIndices; 10134 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10135 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10136 10137 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10138 PetscCall(ISGetIndices(spIS, &spmap)); 10139 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10140 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10141 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10142 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10143 for (p = pStart; p < pEnd; ++p) { 10144 PetscInt gdof, pSubSize = 0; 10145 10146 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10147 if (gdof > 0) { 10148 for (f = 0; f < Nf; ++f) { 10149 PetscInt fdof, fcdof; 10150 10151 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10152 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10153 pSubSize += fdof - fcdof; 10154 } 10155 subSize += pSubSize; 10156 if (pSubSize) { 10157 if (bs < 0) { 10158 bs = pSubSize; 10159 } else if (bs != pSubSize) { 10160 /* Layout does not admit a pointwise block size */ 10161 bs = 1; 10162 } 10163 } 10164 } 10165 } 10166 /* Must have same blocksize on all procs (some might have no points) */ 10167 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10168 bsLocal[1] = bs; 10169 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10170 if (bsMinMax[0] != bsMinMax[1]) { 10171 bs = 1; 10172 } else { 10173 bs = bsMinMax[0]; 10174 } 10175 PetscCall(PetscMalloc1(subSize, &subIndices)); 10176 for (p = pStart; p < pEnd; ++p) { 10177 PetscInt gdof, goff; 10178 10179 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10180 if (gdof > 0) { 10181 const PetscInt point = spmap[p]; 10182 10183 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10184 for (f = 0; f < Nf; ++f) { 10185 PetscInt fdof, fcdof, fc, f2, poff = 0; 10186 10187 /* Can get rid of this loop by storing field information in the global section */ 10188 for (f2 = 0; f2 < f; ++f2) { 10189 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10190 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10191 poff += fdof - fcdof; 10192 } 10193 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10194 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10195 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10196 } 10197 } 10198 } 10199 PetscCall(ISRestoreIndices(spIS, &spmap)); 10200 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10201 if (bs > 1) { 10202 /* We need to check that the block size does not come from non-contiguous fields */ 10203 PetscInt i, j, set = 1; 10204 for (i = 0; i < subSize; i += bs) { 10205 for (j = 0; j < bs; ++j) { 10206 if (subIndices[i + j] != subIndices[i] + j) { 10207 set = 0; 10208 break; 10209 } 10210 } 10211 } 10212 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10213 } 10214 /* Attach nullspace */ 10215 for (f = 0; f < Nf; ++f) { 10216 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10217 if ((*subdm)->nullspaceConstructors[f]) break; 10218 } 10219 if (f < Nf) { 10220 MatNullSpace nullSpace; 10221 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10222 10223 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10224 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10225 } 10226 } 10227 PetscFunctionReturn(PETSC_SUCCESS); 10228 } 10229 10230 /*@ 10231 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10232 10233 Input Parameters: 10234 + dm - The `DM` 10235 - dummy - unused argument 10236 10237 Options Database Key: 10238 . -dm_plex_monitor_throughput - Activate the monitor 10239 10240 Level: developer 10241 10242 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10243 @*/ 10244 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10245 { 10246 PetscLogHandler default_handler; 10247 10248 PetscFunctionBegin; 10249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10250 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10251 if (default_handler) { 10252 PetscLogEvent event; 10253 PetscEventPerfInfo eventInfo; 10254 PetscReal cellRate, flopRate; 10255 PetscInt cStart, cEnd, Nf, N; 10256 const char *name; 10257 10258 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10259 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10260 PetscCall(DMGetNumFields(dm, &Nf)); 10261 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10262 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10263 N = (cEnd - cStart) * Nf * eventInfo.count; 10264 flopRate = eventInfo.flops / eventInfo.time; 10265 cellRate = N / eventInfo.time; 10266 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))); 10267 } else { 10268 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."); 10269 } 10270 PetscFunctionReturn(PETSC_SUCCESS); 10271 } 10272