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 - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4082 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 4083 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 4084 the DAG. 4085 4086 Collective 4087 4088 Input Parameter: 4089 . dm - The `DMPLEX` 4090 4091 Level: beginner 4092 4093 Notes: 4094 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4095 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4096 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4097 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4098 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4099 4100 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4101 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4102 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 4103 to interpolate only that one (e0), so that 4104 .vb 4105 cone(c0) = {e0, v2} 4106 cone(e0) = {v0, v1} 4107 .ve 4108 If `DMPlexStratify()` is run on this mesh, it will give depths 4109 .vb 4110 depth 0 = {v0, v1, v2} 4111 depth 1 = {e0, c0} 4112 .ve 4113 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4114 4115 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4116 4117 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4118 @*/ 4119 PetscErrorCode DMPlexStratify(DM dm) 4120 { 4121 DM_Plex *mesh = (DM_Plex *)dm->data; 4122 DMLabel label; 4123 PetscInt pStart, pEnd, p; 4124 PetscInt numRoots = 0, numLeaves = 0; 4125 4126 PetscFunctionBegin; 4127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4128 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4129 4130 /* Create depth label */ 4131 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4132 PetscCall(DMCreateLabel(dm, "depth")); 4133 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4134 4135 { 4136 /* Initialize roots and count leaves */ 4137 PetscInt sMin = PETSC_MAX_INT; 4138 PetscInt sMax = PETSC_MIN_INT; 4139 PetscInt coneSize, supportSize; 4140 4141 for (p = pStart; p < pEnd; ++p) { 4142 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4143 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4144 if (!coneSize && supportSize) { 4145 sMin = PetscMin(p, sMin); 4146 sMax = PetscMax(p, sMax); 4147 ++numRoots; 4148 } else if (!supportSize && coneSize) { 4149 ++numLeaves; 4150 } else if (!supportSize && !coneSize) { 4151 /* Isolated points */ 4152 sMin = PetscMin(p, sMin); 4153 sMax = PetscMax(p, sMax); 4154 } 4155 } 4156 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4157 } 4158 4159 if (numRoots + numLeaves == (pEnd - pStart)) { 4160 PetscInt sMin = PETSC_MAX_INT; 4161 PetscInt sMax = PETSC_MIN_INT; 4162 PetscInt coneSize, supportSize; 4163 4164 for (p = pStart; p < pEnd; ++p) { 4165 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4166 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4167 if (!supportSize && coneSize) { 4168 sMin = PetscMin(p, sMin); 4169 sMax = PetscMax(p, sMax); 4170 } 4171 } 4172 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4173 } else { 4174 PetscInt level = 0; 4175 PetscInt qStart, qEnd, q; 4176 4177 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4178 while (qEnd > qStart) { 4179 PetscInt sMin = PETSC_MAX_INT; 4180 PetscInt sMax = PETSC_MIN_INT; 4181 4182 for (q = qStart; q < qEnd; ++q) { 4183 const PetscInt *support; 4184 PetscInt supportSize, s; 4185 4186 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4187 PetscCall(DMPlexGetSupport(dm, q, &support)); 4188 for (s = 0; s < supportSize; ++s) { 4189 sMin = PetscMin(support[s], sMin); 4190 sMax = PetscMax(support[s], sMax); 4191 } 4192 } 4193 PetscCall(DMLabelGetNumValues(label, &level)); 4194 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4195 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4196 } 4197 } 4198 { /* just in case there is an empty process */ 4199 PetscInt numValues, maxValues = 0, v; 4200 4201 PetscCall(DMLabelGetNumValues(label, &numValues)); 4202 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4203 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4204 } 4205 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4206 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4207 PetscFunctionReturn(PETSC_SUCCESS); 4208 } 4209 4210 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4211 { 4212 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4213 PetscInt dim, depth, pheight, coneSize; 4214 4215 PetscFunctionBeginHot; 4216 PetscCall(DMGetDimension(dm, &dim)); 4217 PetscCall(DMPlexGetDepth(dm, &depth)); 4218 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4219 pheight = depth - pdepth; 4220 if (depth <= 1) { 4221 switch (pdepth) { 4222 case 0: 4223 ct = DM_POLYTOPE_POINT; 4224 break; 4225 case 1: 4226 switch (coneSize) { 4227 case 2: 4228 ct = DM_POLYTOPE_SEGMENT; 4229 break; 4230 case 3: 4231 ct = DM_POLYTOPE_TRIANGLE; 4232 break; 4233 case 4: 4234 switch (dim) { 4235 case 2: 4236 ct = DM_POLYTOPE_QUADRILATERAL; 4237 break; 4238 case 3: 4239 ct = DM_POLYTOPE_TETRAHEDRON; 4240 break; 4241 default: 4242 break; 4243 } 4244 break; 4245 case 5: 4246 ct = DM_POLYTOPE_PYRAMID; 4247 break; 4248 case 6: 4249 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4250 break; 4251 case 8: 4252 ct = DM_POLYTOPE_HEXAHEDRON; 4253 break; 4254 default: 4255 break; 4256 } 4257 } 4258 } else { 4259 if (pdepth == 0) { 4260 ct = DM_POLYTOPE_POINT; 4261 } else if (pheight == 0) { 4262 switch (dim) { 4263 case 1: 4264 switch (coneSize) { 4265 case 2: 4266 ct = DM_POLYTOPE_SEGMENT; 4267 break; 4268 default: 4269 break; 4270 } 4271 break; 4272 case 2: 4273 switch (coneSize) { 4274 case 3: 4275 ct = DM_POLYTOPE_TRIANGLE; 4276 break; 4277 case 4: 4278 ct = DM_POLYTOPE_QUADRILATERAL; 4279 break; 4280 default: 4281 break; 4282 } 4283 break; 4284 case 3: 4285 switch (coneSize) { 4286 case 4: 4287 ct = DM_POLYTOPE_TETRAHEDRON; 4288 break; 4289 case 5: { 4290 const PetscInt *cone; 4291 PetscInt faceConeSize; 4292 4293 PetscCall(DMPlexGetCone(dm, p, &cone)); 4294 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4295 switch (faceConeSize) { 4296 case 3: 4297 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4298 break; 4299 case 4: 4300 ct = DM_POLYTOPE_PYRAMID; 4301 break; 4302 } 4303 } break; 4304 case 6: 4305 ct = DM_POLYTOPE_HEXAHEDRON; 4306 break; 4307 default: 4308 break; 4309 } 4310 break; 4311 default: 4312 break; 4313 } 4314 } else if (pheight > 0) { 4315 switch (coneSize) { 4316 case 2: 4317 ct = DM_POLYTOPE_SEGMENT; 4318 break; 4319 case 3: 4320 ct = DM_POLYTOPE_TRIANGLE; 4321 break; 4322 case 4: 4323 ct = DM_POLYTOPE_QUADRILATERAL; 4324 break; 4325 default: 4326 break; 4327 } 4328 } 4329 } 4330 *pt = ct; 4331 PetscFunctionReturn(PETSC_SUCCESS); 4332 } 4333 4334 /*@ 4335 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4336 4337 Collective 4338 4339 Input Parameter: 4340 . dm - The `DMPLEX` 4341 4342 Level: developer 4343 4344 Note: 4345 This function is normally called automatically when a cell type is requested. It creates an 4346 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4347 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4348 4349 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4350 4351 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4352 @*/ 4353 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4354 { 4355 DM_Plex *mesh; 4356 DMLabel ctLabel; 4357 PetscInt pStart, pEnd, p; 4358 4359 PetscFunctionBegin; 4360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4361 mesh = (DM_Plex *)dm->data; 4362 PetscCall(DMCreateLabel(dm, "celltype")); 4363 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4364 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4365 PetscCall(PetscFree(mesh->cellTypes)); 4366 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4367 for (p = pStart; p < pEnd; ++p) { 4368 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4369 PetscInt pdepth; 4370 4371 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4372 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4373 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4374 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4375 mesh->cellTypes[p - pStart].value_as_uint8 = ct; 4376 } 4377 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4378 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4379 PetscFunctionReturn(PETSC_SUCCESS); 4380 } 4381 4382 /*@C 4383 DMPlexGetJoin - Get an array for the join of the set of points 4384 4385 Not Collective 4386 4387 Input Parameters: 4388 + dm - The `DMPLEX` object 4389 . numPoints - The number of input points for the join 4390 - points - The input points 4391 4392 Output Parameters: 4393 + numCoveredPoints - The number of points in the join 4394 - coveredPoints - The points in the join 4395 4396 Level: intermediate 4397 4398 Note: 4399 Currently, this is restricted to a single level join 4400 4401 Fortran Notes: 4402 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4403 4404 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4405 @*/ 4406 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4407 { 4408 DM_Plex *mesh = (DM_Plex *)dm->data; 4409 PetscInt *join[2]; 4410 PetscInt joinSize, i = 0; 4411 PetscInt dof, off, p, c, m; 4412 PetscInt maxSupportSize; 4413 4414 PetscFunctionBegin; 4415 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4416 PetscAssertPointer(points, 3); 4417 PetscAssertPointer(numCoveredPoints, 4); 4418 PetscAssertPointer(coveredPoints, 5); 4419 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4420 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4421 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4422 /* Copy in support of first point */ 4423 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4424 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4425 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4426 /* Check each successive support */ 4427 for (p = 1; p < numPoints; ++p) { 4428 PetscInt newJoinSize = 0; 4429 4430 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4431 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4432 for (c = 0; c < dof; ++c) { 4433 const PetscInt point = mesh->supports[off + c]; 4434 4435 for (m = 0; m < joinSize; ++m) { 4436 if (point == join[i][m]) { 4437 join[1 - i][newJoinSize++] = point; 4438 break; 4439 } 4440 } 4441 } 4442 joinSize = newJoinSize; 4443 i = 1 - i; 4444 } 4445 *numCoveredPoints = joinSize; 4446 *coveredPoints = join[i]; 4447 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4448 PetscFunctionReturn(PETSC_SUCCESS); 4449 } 4450 4451 /*@C 4452 DMPlexRestoreJoin - Restore an array for the join of the set of points 4453 4454 Not Collective 4455 4456 Input Parameters: 4457 + dm - The `DMPLEX` object 4458 . numPoints - The number of input points for the join 4459 - points - The input points 4460 4461 Output Parameters: 4462 + numCoveredPoints - The number of points in the join 4463 - coveredPoints - The points in the join 4464 4465 Level: intermediate 4466 4467 Fortran Notes: 4468 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4469 4470 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4471 @*/ 4472 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4473 { 4474 PetscFunctionBegin; 4475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4476 if (points) PetscAssertPointer(points, 3); 4477 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4478 PetscAssertPointer(coveredPoints, 5); 4479 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4480 if (numCoveredPoints) *numCoveredPoints = 0; 4481 PetscFunctionReturn(PETSC_SUCCESS); 4482 } 4483 4484 /*@C 4485 DMPlexGetFullJoin - Get an array for the join of the set of points 4486 4487 Not Collective 4488 4489 Input Parameters: 4490 + dm - The `DMPLEX` object 4491 . numPoints - The number of input points for the join 4492 - points - The input points 4493 4494 Output Parameters: 4495 + numCoveredPoints - The number of points in the join 4496 - coveredPoints - The points in the join 4497 4498 Level: intermediate 4499 4500 Fortran Notes: 4501 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4502 4503 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4504 @*/ 4505 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4506 { 4507 PetscInt *offsets, **closures; 4508 PetscInt *join[2]; 4509 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4510 PetscInt p, d, c, m, ms; 4511 4512 PetscFunctionBegin; 4513 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4514 PetscAssertPointer(points, 3); 4515 PetscAssertPointer(numCoveredPoints, 4); 4516 PetscAssertPointer(coveredPoints, 5); 4517 4518 PetscCall(DMPlexGetDepth(dm, &depth)); 4519 PetscCall(PetscCalloc1(numPoints, &closures)); 4520 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4521 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4522 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4523 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4524 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4525 4526 for (p = 0; p < numPoints; ++p) { 4527 PetscInt closureSize; 4528 4529 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4530 4531 offsets[p * (depth + 2) + 0] = 0; 4532 for (d = 0; d < depth + 1; ++d) { 4533 PetscInt pStart, pEnd, i; 4534 4535 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4536 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4537 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4538 offsets[p * (depth + 2) + d + 1] = i; 4539 break; 4540 } 4541 } 4542 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4543 } 4544 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); 4545 } 4546 for (d = 0; d < depth + 1; ++d) { 4547 PetscInt dof; 4548 4549 /* Copy in support of first point */ 4550 dof = offsets[d + 1] - offsets[d]; 4551 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4552 /* Check each successive cone */ 4553 for (p = 1; p < numPoints && joinSize; ++p) { 4554 PetscInt newJoinSize = 0; 4555 4556 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4557 for (c = 0; c < dof; ++c) { 4558 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4559 4560 for (m = 0; m < joinSize; ++m) { 4561 if (point == join[i][m]) { 4562 join[1 - i][newJoinSize++] = point; 4563 break; 4564 } 4565 } 4566 } 4567 joinSize = newJoinSize; 4568 i = 1 - i; 4569 } 4570 if (joinSize) break; 4571 } 4572 *numCoveredPoints = joinSize; 4573 *coveredPoints = join[i]; 4574 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4575 PetscCall(PetscFree(closures)); 4576 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4577 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4578 PetscFunctionReturn(PETSC_SUCCESS); 4579 } 4580 4581 /*@C 4582 DMPlexGetMeet - Get an array for the meet of the set of points 4583 4584 Not Collective 4585 4586 Input Parameters: 4587 + dm - The `DMPLEX` object 4588 . numPoints - The number of input points for the meet 4589 - points - The input points 4590 4591 Output Parameters: 4592 + numCoveringPoints - The number of points in the meet 4593 - coveringPoints - The points in the meet 4594 4595 Level: intermediate 4596 4597 Note: 4598 Currently, this is restricted to a single level meet 4599 4600 Fortran Notes: 4601 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4602 4603 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4604 @*/ 4605 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4606 { 4607 DM_Plex *mesh = (DM_Plex *)dm->data; 4608 PetscInt *meet[2]; 4609 PetscInt meetSize, i = 0; 4610 PetscInt dof, off, p, c, m; 4611 PetscInt maxConeSize; 4612 4613 PetscFunctionBegin; 4614 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4615 PetscAssertPointer(points, 3); 4616 PetscAssertPointer(numCoveringPoints, 4); 4617 PetscAssertPointer(coveringPoints, 5); 4618 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4619 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4620 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4621 /* Copy in cone of first point */ 4622 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4623 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4624 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4625 /* Check each successive cone */ 4626 for (p = 1; p < numPoints; ++p) { 4627 PetscInt newMeetSize = 0; 4628 4629 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4630 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4631 for (c = 0; c < dof; ++c) { 4632 const PetscInt point = mesh->cones[off + c]; 4633 4634 for (m = 0; m < meetSize; ++m) { 4635 if (point == meet[i][m]) { 4636 meet[1 - i][newMeetSize++] = point; 4637 break; 4638 } 4639 } 4640 } 4641 meetSize = newMeetSize; 4642 i = 1 - i; 4643 } 4644 *numCoveringPoints = meetSize; 4645 *coveringPoints = meet[i]; 4646 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4647 PetscFunctionReturn(PETSC_SUCCESS); 4648 } 4649 4650 /*@C 4651 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4652 4653 Not Collective 4654 4655 Input Parameters: 4656 + dm - The `DMPLEX` object 4657 . numPoints - The number of input points for the meet 4658 - points - The input points 4659 4660 Output Parameters: 4661 + numCoveredPoints - The number of points in the meet 4662 - coveredPoints - The points in the meet 4663 4664 Level: intermediate 4665 4666 Fortran Notes: 4667 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4668 4669 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4670 @*/ 4671 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4672 { 4673 PetscFunctionBegin; 4674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4675 if (points) PetscAssertPointer(points, 3); 4676 if (numCoveredPoints) PetscAssertPointer(numCoveredPoints, 4); 4677 PetscAssertPointer(coveredPoints, 5); 4678 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4679 if (numCoveredPoints) *numCoveredPoints = 0; 4680 PetscFunctionReturn(PETSC_SUCCESS); 4681 } 4682 4683 /*@C 4684 DMPlexGetFullMeet - Get an array for the meet of the set of points 4685 4686 Not Collective 4687 4688 Input Parameters: 4689 + dm - The `DMPLEX` object 4690 . numPoints - The number of input points for the meet 4691 - points - The input points 4692 4693 Output Parameters: 4694 + numCoveredPoints - The number of points in the meet 4695 - coveredPoints - The points in the meet 4696 4697 Level: intermediate 4698 4699 Fortran Notes: 4700 The `numCoveredPoints` argument is not present in the Fortran binding since it is internal to the array. 4701 4702 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4703 @*/ 4704 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4705 { 4706 PetscInt *offsets, **closures; 4707 PetscInt *meet[2]; 4708 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4709 PetscInt p, h, c, m, mc; 4710 4711 PetscFunctionBegin; 4712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4713 PetscAssertPointer(points, 3); 4714 PetscAssertPointer(numCoveredPoints, 4); 4715 PetscAssertPointer(coveredPoints, 5); 4716 4717 PetscCall(DMPlexGetDepth(dm, &height)); 4718 PetscCall(PetscMalloc1(numPoints, &closures)); 4719 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4720 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4721 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4722 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4723 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4724 4725 for (p = 0; p < numPoints; ++p) { 4726 PetscInt closureSize; 4727 4728 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4729 4730 offsets[p * (height + 2) + 0] = 0; 4731 for (h = 0; h < height + 1; ++h) { 4732 PetscInt pStart, pEnd, i; 4733 4734 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4735 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4736 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4737 offsets[p * (height + 2) + h + 1] = i; 4738 break; 4739 } 4740 } 4741 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4742 } 4743 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); 4744 } 4745 for (h = 0; h < height + 1; ++h) { 4746 PetscInt dof; 4747 4748 /* Copy in cone of first point */ 4749 dof = offsets[h + 1] - offsets[h]; 4750 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4751 /* Check each successive cone */ 4752 for (p = 1; p < numPoints && meetSize; ++p) { 4753 PetscInt newMeetSize = 0; 4754 4755 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4756 for (c = 0; c < dof; ++c) { 4757 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4758 4759 for (m = 0; m < meetSize; ++m) { 4760 if (point == meet[i][m]) { 4761 meet[1 - i][newMeetSize++] = point; 4762 break; 4763 } 4764 } 4765 } 4766 meetSize = newMeetSize; 4767 i = 1 - i; 4768 } 4769 if (meetSize) break; 4770 } 4771 *numCoveredPoints = meetSize; 4772 *coveredPoints = meet[i]; 4773 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4774 PetscCall(PetscFree(closures)); 4775 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4776 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4777 PetscFunctionReturn(PETSC_SUCCESS); 4778 } 4779 4780 /*@C 4781 DMPlexEqual - Determine if two `DM` have the same topology 4782 4783 Not Collective 4784 4785 Input Parameters: 4786 + dmA - A `DMPLEX` object 4787 - dmB - A `DMPLEX` object 4788 4789 Output Parameter: 4790 . equal - `PETSC_TRUE` if the topologies are identical 4791 4792 Level: intermediate 4793 4794 Note: 4795 We are not solving graph isomorphism, so we do not permute. 4796 4797 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4798 @*/ 4799 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4800 { 4801 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4802 4803 PetscFunctionBegin; 4804 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4805 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4806 PetscAssertPointer(equal, 3); 4807 4808 *equal = PETSC_FALSE; 4809 PetscCall(DMPlexGetDepth(dmA, &depth)); 4810 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4811 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4812 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4813 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4814 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4815 for (p = pStart; p < pEnd; ++p) { 4816 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4817 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4818 4819 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4820 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4821 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4822 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4823 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4824 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4825 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4826 for (c = 0; c < coneSize; ++c) { 4827 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4828 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4829 } 4830 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4831 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4832 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4833 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4834 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4835 for (s = 0; s < supportSize; ++s) { 4836 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4837 } 4838 } 4839 *equal = PETSC_TRUE; 4840 PetscFunctionReturn(PETSC_SUCCESS); 4841 } 4842 4843 /*@C 4844 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4845 4846 Not Collective 4847 4848 Input Parameters: 4849 + dm - The `DMPLEX` 4850 . cellDim - The cell dimension 4851 - numCorners - The number of vertices on a cell 4852 4853 Output Parameter: 4854 . numFaceVertices - The number of vertices on a face 4855 4856 Level: developer 4857 4858 Note: 4859 Of course this can only work for a restricted set of symmetric shapes 4860 4861 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4862 @*/ 4863 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4864 { 4865 MPI_Comm comm; 4866 4867 PetscFunctionBegin; 4868 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4869 PetscAssertPointer(numFaceVertices, 4); 4870 switch (cellDim) { 4871 case 0: 4872 *numFaceVertices = 0; 4873 break; 4874 case 1: 4875 *numFaceVertices = 1; 4876 break; 4877 case 2: 4878 switch (numCorners) { 4879 case 3: /* triangle */ 4880 *numFaceVertices = 2; /* Edge has 2 vertices */ 4881 break; 4882 case 4: /* quadrilateral */ 4883 *numFaceVertices = 2; /* Edge has 2 vertices */ 4884 break; 4885 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4886 *numFaceVertices = 3; /* Edge has 3 vertices */ 4887 break; 4888 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4889 *numFaceVertices = 3; /* Edge has 3 vertices */ 4890 break; 4891 default: 4892 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4893 } 4894 break; 4895 case 3: 4896 switch (numCorners) { 4897 case 4: /* tetradehdron */ 4898 *numFaceVertices = 3; /* Face has 3 vertices */ 4899 break; 4900 case 6: /* tet cohesive cells */ 4901 *numFaceVertices = 4; /* Face has 4 vertices */ 4902 break; 4903 case 8: /* hexahedron */ 4904 *numFaceVertices = 4; /* Face has 4 vertices */ 4905 break; 4906 case 9: /* tet cohesive Lagrange cells */ 4907 *numFaceVertices = 6; /* Face has 6 vertices */ 4908 break; 4909 case 10: /* quadratic tetrahedron */ 4910 *numFaceVertices = 6; /* Face has 6 vertices */ 4911 break; 4912 case 12: /* hex cohesive Lagrange cells */ 4913 *numFaceVertices = 6; /* Face has 6 vertices */ 4914 break; 4915 case 18: /* quadratic tet cohesive Lagrange cells */ 4916 *numFaceVertices = 6; /* Face has 6 vertices */ 4917 break; 4918 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4919 *numFaceVertices = 9; /* Face has 9 vertices */ 4920 break; 4921 default: 4922 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4923 } 4924 break; 4925 default: 4926 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4927 } 4928 PetscFunctionReturn(PETSC_SUCCESS); 4929 } 4930 4931 /*@ 4932 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 4933 4934 Not Collective 4935 4936 Input Parameter: 4937 . dm - The `DMPLEX` object 4938 4939 Output Parameter: 4940 . depthLabel - The `DMLabel` recording point depth 4941 4942 Level: developer 4943 4944 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4945 @*/ 4946 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4947 { 4948 PetscFunctionBegin; 4949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4950 PetscAssertPointer(depthLabel, 2); 4951 *depthLabel = dm->depthLabel; 4952 PetscFunctionReturn(PETSC_SUCCESS); 4953 } 4954 4955 /*@ 4956 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4957 4958 Not Collective 4959 4960 Input Parameter: 4961 . dm - The `DMPLEX` object 4962 4963 Output Parameter: 4964 . depth - The number of strata (breadth first levels) in the DAG 4965 4966 Level: developer 4967 4968 Notes: 4969 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 4970 4971 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 4972 4973 An empty mesh gives -1. 4974 4975 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4976 @*/ 4977 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4978 { 4979 DM_Plex *mesh = (DM_Plex *)dm->data; 4980 DMLabel label; 4981 PetscInt d = 0; 4982 4983 PetscFunctionBegin; 4984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4985 PetscAssertPointer(depth, 2); 4986 if (mesh->tr) { 4987 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 4988 } else { 4989 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4990 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4991 *depth = d - 1; 4992 } 4993 PetscFunctionReturn(PETSC_SUCCESS); 4994 } 4995 4996 /*@ 4997 DMPlexGetDepthStratum - Get the bounds [`start`, `end`) for all points at a certain depth. 4998 4999 Not Collective 5000 5001 Input Parameters: 5002 + dm - The `DMPLEX` object 5003 - depth - The requested depth 5004 5005 Output Parameters: 5006 + start - The first point at this `depth` 5007 - end - One beyond the last point at this `depth` 5008 5009 Level: developer 5010 5011 Notes: 5012 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 5013 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 5014 higher dimension, e.g., "edges". 5015 5016 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 5017 @*/ 5018 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 5019 { 5020 DM_Plex *mesh = (DM_Plex *)dm->data; 5021 DMLabel label; 5022 PetscInt pStart, pEnd; 5023 5024 PetscFunctionBegin; 5025 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5026 if (start) { 5027 PetscAssertPointer(start, 3); 5028 *start = 0; 5029 } 5030 if (end) { 5031 PetscAssertPointer(end, 4); 5032 *end = 0; 5033 } 5034 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5035 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5036 if (depth < 0) { 5037 if (start) *start = pStart; 5038 if (end) *end = pEnd; 5039 PetscFunctionReturn(PETSC_SUCCESS); 5040 } 5041 if (mesh->tr) { 5042 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5043 } else { 5044 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5045 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5046 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5047 } 5048 PetscFunctionReturn(PETSC_SUCCESS); 5049 } 5050 5051 /*@ 5052 DMPlexGetHeightStratum - Get the bounds [`start`, `end`) for all points at a certain height. 5053 5054 Not Collective 5055 5056 Input Parameters: 5057 + dm - The `DMPLEX` object 5058 - height - The requested height 5059 5060 Output Parameters: 5061 + start - The first point at this `height` 5062 - end - One beyond the last point at this `height` 5063 5064 Level: developer 5065 5066 Notes: 5067 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5068 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5069 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5070 5071 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetCellTypeStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5072 @*/ 5073 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5074 { 5075 DMLabel label; 5076 PetscInt depth, pStart, pEnd; 5077 5078 PetscFunctionBegin; 5079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5080 if (start) { 5081 PetscAssertPointer(start, 3); 5082 *start = 0; 5083 } 5084 if (end) { 5085 PetscAssertPointer(end, 4); 5086 *end = 0; 5087 } 5088 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5089 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5090 if (height < 0) { 5091 if (start) *start = pStart; 5092 if (end) *end = pEnd; 5093 PetscFunctionReturn(PETSC_SUCCESS); 5094 } 5095 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5096 if (label) PetscCall(DMLabelGetNumValues(label, &depth)); 5097 else PetscCall(DMGetDimension(dm, &depth)); 5098 PetscCheck(depth >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Depth not yet computed"); 5099 PetscCall(DMPlexGetDepthStratum(dm, depth - 1 - height, start, end)); 5100 PetscFunctionReturn(PETSC_SUCCESS); 5101 } 5102 5103 /*@ 5104 DMPlexGetPointDepth - Get the `depth` of a given point 5105 5106 Not Collective 5107 5108 Input Parameters: 5109 + dm - The `DMPLEX` object 5110 - point - The point 5111 5112 Output Parameter: 5113 . depth - The depth of the `point` 5114 5115 Level: intermediate 5116 5117 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5118 @*/ 5119 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5120 { 5121 PetscFunctionBegin; 5122 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5123 PetscAssertPointer(depth, 3); 5124 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5125 PetscFunctionReturn(PETSC_SUCCESS); 5126 } 5127 5128 /*@ 5129 DMPlexGetPointHeight - Get the `height` of a given point 5130 5131 Not Collective 5132 5133 Input Parameters: 5134 + dm - The `DMPLEX` object 5135 - point - The point 5136 5137 Output Parameter: 5138 . height - The height of the `point` 5139 5140 Level: intermediate 5141 5142 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5143 @*/ 5144 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5145 { 5146 PetscInt n, pDepth; 5147 5148 PetscFunctionBegin; 5149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5150 PetscAssertPointer(height, 3); 5151 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5152 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5153 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5154 PetscFunctionReturn(PETSC_SUCCESS); 5155 } 5156 5157 /*@ 5158 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5159 5160 Not Collective 5161 5162 Input Parameter: 5163 . dm - The `DMPLEX` object 5164 5165 Output Parameter: 5166 . celltypeLabel - The `DMLabel` recording cell polytope type 5167 5168 Level: developer 5169 5170 Note: 5171 This function will trigger automatica computation of cell types. This can be disabled by calling 5172 `DMCreateLabel`(dm, "celltype") beforehand. 5173 5174 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5175 @*/ 5176 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5177 { 5178 PetscFunctionBegin; 5179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5180 PetscAssertPointer(celltypeLabel, 2); 5181 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5182 *celltypeLabel = dm->celltypeLabel; 5183 PetscFunctionReturn(PETSC_SUCCESS); 5184 } 5185 5186 /*@ 5187 DMPlexGetCellType - Get the polytope type of a given cell 5188 5189 Not Collective 5190 5191 Input Parameters: 5192 + dm - The `DMPLEX` object 5193 - cell - The cell 5194 5195 Output Parameter: 5196 . celltype - The polytope type of the cell 5197 5198 Level: intermediate 5199 5200 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5201 @*/ 5202 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5203 { 5204 DM_Plex *mesh = (DM_Plex *)dm->data; 5205 DMLabel label; 5206 PetscInt ct; 5207 5208 PetscFunctionBegin; 5209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5210 PetscAssertPointer(celltype, 3); 5211 if (mesh->tr) { 5212 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5213 } else { 5214 PetscInt pStart, pEnd; 5215 5216 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5217 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5218 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5219 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5220 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5221 for (PetscInt p = pStart; p < pEnd; p++) { 5222 PetscCall(DMLabelGetValue(label, p, &ct)); 5223 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5224 } 5225 } 5226 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5227 if (PetscDefined(USE_DEBUG)) { 5228 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5229 PetscCall(DMLabelGetValue(label, cell, &ct)); 5230 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5231 PetscCheck(ct == (PetscInt)*celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5232 } 5233 } 5234 PetscFunctionReturn(PETSC_SUCCESS); 5235 } 5236 5237 /*@ 5238 DMPlexSetCellType - Set the polytope type of a given cell 5239 5240 Not Collective 5241 5242 Input Parameters: 5243 + dm - The `DMPLEX` object 5244 . cell - The cell 5245 - celltype - The polytope type of the cell 5246 5247 Level: advanced 5248 5249 Note: 5250 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5251 is executed. This function will override the computed type. However, if automatic classification will not succeed 5252 and a user wants to manually specify all types, the classification must be disabled by calling 5253 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5254 5255 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5256 @*/ 5257 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5258 { 5259 DM_Plex *mesh = (DM_Plex *)dm->data; 5260 DMLabel label; 5261 PetscInt pStart, pEnd; 5262 5263 PetscFunctionBegin; 5264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5265 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5266 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5267 PetscCall(DMLabelSetValue(label, cell, celltype)); 5268 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5269 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5270 PetscFunctionReturn(PETSC_SUCCESS); 5271 } 5272 5273 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5274 { 5275 PetscSection section, s; 5276 Mat m; 5277 PetscInt maxHeight; 5278 const char *prefix; 5279 5280 PetscFunctionBegin; 5281 PetscCall(DMClone(dm, cdm)); 5282 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5283 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5284 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5285 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5286 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5287 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5288 PetscCall(DMSetLocalSection(*cdm, section)); 5289 PetscCall(PetscSectionDestroy(§ion)); 5290 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5291 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5292 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5293 PetscCall(PetscSectionDestroy(&s)); 5294 PetscCall(MatDestroy(&m)); 5295 5296 PetscCall(DMSetNumFields(*cdm, 1)); 5297 PetscCall(DMCreateDS(*cdm)); 5298 (*cdm)->cloneOpts = PETSC_TRUE; 5299 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5300 PetscFunctionReturn(PETSC_SUCCESS); 5301 } 5302 5303 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5304 { 5305 Vec coordsLocal, cellCoordsLocal; 5306 DM coordsDM, cellCoordsDM; 5307 5308 PetscFunctionBegin; 5309 *field = NULL; 5310 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5311 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5312 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5313 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5314 if (coordsLocal && coordsDM) { 5315 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5316 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5317 } 5318 PetscFunctionReturn(PETSC_SUCCESS); 5319 } 5320 5321 /*@C 5322 DMPlexGetConeSection - Return a section which describes the layout of cone data 5323 5324 Not Collective 5325 5326 Input Parameter: 5327 . dm - The `DMPLEX` object 5328 5329 Output Parameter: 5330 . section - The `PetscSection` object 5331 5332 Level: developer 5333 5334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5335 @*/ 5336 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5337 { 5338 DM_Plex *mesh = (DM_Plex *)dm->data; 5339 5340 PetscFunctionBegin; 5341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5342 if (section) *section = mesh->coneSection; 5343 PetscFunctionReturn(PETSC_SUCCESS); 5344 } 5345 5346 /*@C 5347 DMPlexGetSupportSection - Return a section which describes the layout of support data 5348 5349 Not Collective 5350 5351 Input Parameter: 5352 . dm - The `DMPLEX` object 5353 5354 Output Parameter: 5355 . section - The `PetscSection` object 5356 5357 Level: developer 5358 5359 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5360 @*/ 5361 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5362 { 5363 DM_Plex *mesh = (DM_Plex *)dm->data; 5364 5365 PetscFunctionBegin; 5366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5367 if (section) *section = mesh->supportSection; 5368 PetscFunctionReturn(PETSC_SUCCESS); 5369 } 5370 5371 /*@C 5372 DMPlexGetCones - Return cone data 5373 5374 Not Collective 5375 5376 Input Parameter: 5377 . dm - The `DMPLEX` object 5378 5379 Output Parameter: 5380 . cones - The cone for each point 5381 5382 Level: developer 5383 5384 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5385 @*/ 5386 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5387 { 5388 DM_Plex *mesh = (DM_Plex *)dm->data; 5389 5390 PetscFunctionBegin; 5391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5392 if (cones) *cones = mesh->cones; 5393 PetscFunctionReturn(PETSC_SUCCESS); 5394 } 5395 5396 /*@C 5397 DMPlexGetConeOrientations - Return cone orientation data 5398 5399 Not Collective 5400 5401 Input Parameter: 5402 . dm - The `DMPLEX` object 5403 5404 Output Parameter: 5405 . coneOrientations - The array of cone orientations for all points 5406 5407 Level: developer 5408 5409 Notes: 5410 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5411 5412 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5413 5414 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5415 @*/ 5416 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5417 { 5418 DM_Plex *mesh = (DM_Plex *)dm->data; 5419 5420 PetscFunctionBegin; 5421 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5422 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5423 PetscFunctionReturn(PETSC_SUCCESS); 5424 } 5425 5426 /******************************** FEM Support **********************************/ 5427 5428 /* 5429 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5430 representing a line in the section. 5431 */ 5432 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5433 { 5434 PetscFunctionBeginHot; 5435 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5436 if (line < 0) { 5437 *k = 0; 5438 *Nc = 0; 5439 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5440 *k = 1; 5441 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5442 /* An order k SEM disc has k-1 dofs on an edge */ 5443 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5444 *k = *k / *Nc + 1; 5445 } 5446 PetscFunctionReturn(PETSC_SUCCESS); 5447 } 5448 5449 /*@ 5450 5451 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5452 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5453 section provided (or the section of the `DM`). 5454 5455 Input Parameters: 5456 + dm - The `DM` 5457 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5458 - section - The `PetscSection` to reorder, or `NULL` for the default section 5459 5460 Example: 5461 A typical interpolated single-quad mesh might order points as 5462 .vb 5463 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5464 5465 v4 -- e6 -- v3 5466 | | 5467 e7 c0 e8 5468 | | 5469 v1 -- e5 -- v2 5470 .ve 5471 5472 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5473 dofs in the order of points, e.g., 5474 .vb 5475 c0 -> [0,1,2,3] 5476 v1 -> [4] 5477 ... 5478 e5 -> [8, 9] 5479 .ve 5480 5481 which corresponds to the dofs 5482 .vb 5483 6 10 11 7 5484 13 2 3 15 5485 12 0 1 14 5486 4 8 9 5 5487 .ve 5488 5489 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5490 .vb 5491 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5492 .ve 5493 5494 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5495 .vb 5496 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5497 .ve 5498 5499 Level: developer 5500 5501 Notes: 5502 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5503 degree of the basis. 5504 5505 This is required to run with libCEED. 5506 5507 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5508 @*/ 5509 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5510 { 5511 DMLabel label; 5512 PetscInt dim, depth = -1, eStart = -1, Nf; 5513 PetscBool vertexchart; 5514 5515 PetscFunctionBegin; 5516 PetscCall(DMGetDimension(dm, &dim)); 5517 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5518 if (point < 0) { 5519 PetscInt sStart, sEnd; 5520 5521 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5522 point = sEnd - sStart ? sStart : point; 5523 } 5524 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5525 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5526 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5527 if (depth == 1) { 5528 eStart = point; 5529 } else if (depth == dim) { 5530 const PetscInt *cone; 5531 5532 PetscCall(DMPlexGetCone(dm, point, &cone)); 5533 if (dim == 2) eStart = cone[0]; 5534 else if (dim == 3) { 5535 const PetscInt *cone2; 5536 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5537 eStart = cone2[0]; 5538 } 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); 5539 } 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); 5540 { /* Determine whether the chart covers all points or just vertices. */ 5541 PetscInt pStart, pEnd, cStart, cEnd; 5542 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5543 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5544 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5545 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5546 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5547 } 5548 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5549 for (PetscInt d = 1; d <= dim; d++) { 5550 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5551 PetscInt *perm; 5552 5553 for (f = 0; f < Nf; ++f) { 5554 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5555 size += PetscPowInt(k + 1, d) * Nc; 5556 } 5557 PetscCall(PetscMalloc1(size, &perm)); 5558 for (f = 0; f < Nf; ++f) { 5559 switch (d) { 5560 case 1: 5561 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5562 /* 5563 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5564 We want [ vtx0; edge of length k-1; vtx1 ] 5565 */ 5566 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5567 for (i = 0; i < k - 1; i++) 5568 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5569 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5570 foffset = offset; 5571 break; 5572 case 2: 5573 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5574 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5575 /* The SEM order is 5576 5577 v_lb, {e_b}, v_rb, 5578 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5579 v_lt, reverse {e_t}, v_rt 5580 */ 5581 { 5582 const PetscInt of = 0; 5583 const PetscInt oeb = of + PetscSqr(k - 1); 5584 const PetscInt oer = oeb + (k - 1); 5585 const PetscInt oet = oer + (k - 1); 5586 const PetscInt oel = oet + (k - 1); 5587 const PetscInt ovlb = oel + (k - 1); 5588 const PetscInt ovrb = ovlb + 1; 5589 const PetscInt ovrt = ovrb + 1; 5590 const PetscInt ovlt = ovrt + 1; 5591 PetscInt o; 5592 5593 /* bottom */ 5594 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5595 for (o = oeb; o < oer; ++o) 5596 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5597 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5598 /* middle */ 5599 for (i = 0; i < k - 1; ++i) { 5600 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5601 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5602 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5603 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5604 } 5605 /* top */ 5606 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5607 for (o = oel - 1; o >= oet; --o) 5608 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5609 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5610 foffset = offset; 5611 } 5612 break; 5613 case 3: 5614 /* The original hex closure is 5615 5616 {c, 5617 f_b, f_t, f_f, f_b, f_r, f_l, 5618 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5619 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5620 */ 5621 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5622 /* The SEM order is 5623 Bottom Slice 5624 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5625 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5626 v_blb, {e_bb}, v_brb, 5627 5628 Middle Slice (j) 5629 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5630 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5631 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5632 5633 Top Slice 5634 v_tlf, {e_tf}, v_trf, 5635 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5636 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5637 */ 5638 { 5639 const PetscInt oc = 0; 5640 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5641 const PetscInt oft = ofb + PetscSqr(k - 1); 5642 const PetscInt off = oft + PetscSqr(k - 1); 5643 const PetscInt ofk = off + PetscSqr(k - 1); 5644 const PetscInt ofr = ofk + PetscSqr(k - 1); 5645 const PetscInt ofl = ofr + PetscSqr(k - 1); 5646 const PetscInt oebl = ofl + PetscSqr(k - 1); 5647 const PetscInt oebb = oebl + (k - 1); 5648 const PetscInt oebr = oebb + (k - 1); 5649 const PetscInt oebf = oebr + (k - 1); 5650 const PetscInt oetf = oebf + (k - 1); 5651 const PetscInt oetr = oetf + (k - 1); 5652 const PetscInt oetb = oetr + (k - 1); 5653 const PetscInt oetl = oetb + (k - 1); 5654 const PetscInt oerf = oetl + (k - 1); 5655 const PetscInt oelf = oerf + (k - 1); 5656 const PetscInt oelb = oelf + (k - 1); 5657 const PetscInt oerb = oelb + (k - 1); 5658 const PetscInt ovblf = oerb + (k - 1); 5659 const PetscInt ovblb = ovblf + 1; 5660 const PetscInt ovbrb = ovblb + 1; 5661 const PetscInt ovbrf = ovbrb + 1; 5662 const PetscInt ovtlf = ovbrf + 1; 5663 const PetscInt ovtrf = ovtlf + 1; 5664 const PetscInt ovtrb = ovtrf + 1; 5665 const PetscInt ovtlb = ovtrb + 1; 5666 PetscInt o, n; 5667 5668 /* Bottom Slice */ 5669 /* bottom */ 5670 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5671 for (o = oetf - 1; o >= oebf; --o) 5672 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5673 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5674 /* middle */ 5675 for (i = 0; i < k - 1; ++i) { 5676 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5677 for (n = 0; n < k - 1; ++n) { 5678 o = ofb + n * (k - 1) + i; 5679 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5680 } 5681 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5682 } 5683 /* top */ 5684 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5685 for (o = oebb; o < oebr; ++o) 5686 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5687 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5688 5689 /* Middle Slice */ 5690 for (j = 0; j < k - 1; ++j) { 5691 /* bottom */ 5692 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5693 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5694 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5695 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5696 /* middle */ 5697 for (i = 0; i < k - 1; ++i) { 5698 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5699 for (n = 0; n < k - 1; ++n) 5700 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5701 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5702 } 5703 /* top */ 5704 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5705 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5706 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5707 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5708 } 5709 5710 /* Top Slice */ 5711 /* bottom */ 5712 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5713 for (o = oetf; o < oetr; ++o) 5714 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5715 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5716 /* middle */ 5717 for (i = 0; i < k - 1; ++i) { 5718 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5719 for (n = 0; n < k - 1; ++n) 5720 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5721 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5722 } 5723 /* top */ 5724 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5725 for (o = oetl - 1; o >= oetb; --o) 5726 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5727 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5728 5729 foffset = offset; 5730 } 5731 break; 5732 default: 5733 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5734 } 5735 } 5736 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5737 /* Check permutation */ 5738 { 5739 PetscInt *check; 5740 5741 PetscCall(PetscMalloc1(size, &check)); 5742 for (i = 0; i < size; ++i) { 5743 check[i] = -1; 5744 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5745 } 5746 for (i = 0; i < size; ++i) check[perm[i]] = i; 5747 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5748 PetscCall(PetscFree(check)); 5749 } 5750 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5751 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5752 PetscInt *loc_perm; 5753 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5754 for (PetscInt i = 0; i < size; i++) { 5755 loc_perm[i] = perm[i]; 5756 loc_perm[size + i] = size + perm[i]; 5757 } 5758 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5759 } 5760 } 5761 PetscFunctionReturn(PETSC_SUCCESS); 5762 } 5763 5764 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5765 { 5766 PetscDS prob; 5767 PetscInt depth, Nf, h; 5768 DMLabel label; 5769 5770 PetscFunctionBeginHot; 5771 PetscCall(DMGetDS(dm, &prob)); 5772 Nf = prob->Nf; 5773 label = dm->depthLabel; 5774 *dspace = NULL; 5775 if (field < Nf) { 5776 PetscObject disc = prob->disc[field]; 5777 5778 if (disc->classid == PETSCFE_CLASSID) { 5779 PetscDualSpace dsp; 5780 5781 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5782 PetscCall(DMLabelGetNumValues(label, &depth)); 5783 PetscCall(DMLabelGetValue(label, point, &h)); 5784 h = depth - 1 - h; 5785 if (h) { 5786 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5787 } else { 5788 *dspace = dsp; 5789 } 5790 } 5791 } 5792 PetscFunctionReturn(PETSC_SUCCESS); 5793 } 5794 5795 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5796 { 5797 PetscScalar *array; 5798 const PetscScalar *vArray; 5799 const PetscInt *cone, *coneO; 5800 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5801 5802 PetscFunctionBeginHot; 5803 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5804 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5805 PetscCall(DMPlexGetCone(dm, point, &cone)); 5806 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5807 if (!values || !*values) { 5808 if ((point >= pStart) && (point < pEnd)) { 5809 PetscInt dof; 5810 5811 PetscCall(PetscSectionGetDof(section, point, &dof)); 5812 size += dof; 5813 } 5814 for (p = 0; p < numPoints; ++p) { 5815 const PetscInt cp = cone[p]; 5816 PetscInt dof; 5817 5818 if ((cp < pStart) || (cp >= pEnd)) continue; 5819 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5820 size += dof; 5821 } 5822 if (!values) { 5823 if (csize) *csize = size; 5824 PetscFunctionReturn(PETSC_SUCCESS); 5825 } 5826 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5827 } else { 5828 array = *values; 5829 } 5830 size = 0; 5831 PetscCall(VecGetArrayRead(v, &vArray)); 5832 if ((point >= pStart) && (point < pEnd)) { 5833 PetscInt dof, off, d; 5834 const PetscScalar *varr; 5835 5836 PetscCall(PetscSectionGetDof(section, point, &dof)); 5837 PetscCall(PetscSectionGetOffset(section, point, &off)); 5838 varr = &vArray[off]; 5839 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5840 size += dof; 5841 } 5842 for (p = 0; p < numPoints; ++p) { 5843 const PetscInt cp = cone[p]; 5844 PetscInt o = coneO[p]; 5845 PetscInt dof, off, d; 5846 const PetscScalar *varr; 5847 5848 if ((cp < pStart) || (cp >= pEnd)) continue; 5849 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5850 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5851 varr = &vArray[off]; 5852 if (o >= 0) { 5853 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5854 } else { 5855 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5856 } 5857 size += dof; 5858 } 5859 PetscCall(VecRestoreArrayRead(v, &vArray)); 5860 if (!*values) { 5861 if (csize) *csize = size; 5862 *values = array; 5863 } else { 5864 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5865 *csize = size; 5866 } 5867 PetscFunctionReturn(PETSC_SUCCESS); 5868 } 5869 5870 /* Compress out points not in the section */ 5871 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5872 { 5873 const PetscInt np = *numPoints; 5874 PetscInt pStart, pEnd, p, q; 5875 5876 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5877 for (p = 0, q = 0; p < np; ++p) { 5878 const PetscInt r = points[p * 2]; 5879 if ((r >= pStart) && (r < pEnd)) { 5880 points[q * 2] = r; 5881 points[q * 2 + 1] = points[p * 2 + 1]; 5882 ++q; 5883 } 5884 } 5885 *numPoints = q; 5886 return PETSC_SUCCESS; 5887 } 5888 5889 /* Compressed closure does not apply closure permutation */ 5890 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5891 { 5892 const PetscInt *cla = NULL; 5893 PetscInt np, *pts = NULL; 5894 5895 PetscFunctionBeginHot; 5896 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5897 if (!ornt && *clPoints) { 5898 PetscInt dof, off; 5899 5900 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5901 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5902 PetscCall(ISGetIndices(*clPoints, &cla)); 5903 np = dof / 2; 5904 pts = (PetscInt *)&cla[off]; 5905 } else { 5906 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 5907 PetscCall(CompressPoints_Private(section, &np, pts)); 5908 } 5909 *numPoints = np; 5910 *points = pts; 5911 *clp = cla; 5912 PetscFunctionReturn(PETSC_SUCCESS); 5913 } 5914 5915 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5916 { 5917 PetscFunctionBeginHot; 5918 if (!*clPoints) { 5919 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5920 } else { 5921 PetscCall(ISRestoreIndices(*clPoints, clp)); 5922 } 5923 *numPoints = 0; 5924 *points = NULL; 5925 *clSec = NULL; 5926 *clPoints = NULL; 5927 *clp = NULL; 5928 PetscFunctionReturn(PETSC_SUCCESS); 5929 } 5930 5931 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5932 { 5933 PetscInt offset = 0, p; 5934 const PetscInt **perms = NULL; 5935 const PetscScalar **flips = NULL; 5936 5937 PetscFunctionBeginHot; 5938 *size = 0; 5939 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5940 for (p = 0; p < numPoints; p++) { 5941 const PetscInt point = points[2 * p]; 5942 const PetscInt *perm = perms ? perms[p] : NULL; 5943 const PetscScalar *flip = flips ? flips[p] : NULL; 5944 PetscInt dof, off, d; 5945 const PetscScalar *varr; 5946 5947 PetscCall(PetscSectionGetDof(section, point, &dof)); 5948 PetscCall(PetscSectionGetOffset(section, point, &off)); 5949 varr = &vArray[off]; 5950 if (clperm) { 5951 if (perm) { 5952 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5953 } else { 5954 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5955 } 5956 if (flip) { 5957 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5958 } 5959 } else { 5960 if (perm) { 5961 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5962 } else { 5963 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5964 } 5965 if (flip) { 5966 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5967 } 5968 } 5969 offset += dof; 5970 } 5971 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5972 *size = offset; 5973 PetscFunctionReturn(PETSC_SUCCESS); 5974 } 5975 5976 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[]) 5977 { 5978 PetscInt offset = 0, f; 5979 5980 PetscFunctionBeginHot; 5981 *size = 0; 5982 for (f = 0; f < numFields; ++f) { 5983 PetscInt p; 5984 const PetscInt **perms = NULL; 5985 const PetscScalar **flips = NULL; 5986 5987 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5988 for (p = 0; p < numPoints; p++) { 5989 const PetscInt point = points[2 * p]; 5990 PetscInt fdof, foff, b; 5991 const PetscScalar *varr; 5992 const PetscInt *perm = perms ? perms[p] : NULL; 5993 const PetscScalar *flip = flips ? flips[p] : NULL; 5994 5995 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5996 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5997 varr = &vArray[foff]; 5998 if (clperm) { 5999 if (perm) { 6000 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 6001 } else { 6002 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 6003 } 6004 if (flip) { 6005 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 6006 } 6007 } else { 6008 if (perm) { 6009 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 6010 } else { 6011 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 6012 } 6013 if (flip) { 6014 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 6015 } 6016 } 6017 offset += fdof; 6018 } 6019 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6020 } 6021 *size = offset; 6022 PetscFunctionReturn(PETSC_SUCCESS); 6023 } 6024 6025 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 6026 { 6027 PetscSection clSection; 6028 IS clPoints; 6029 PetscInt *points = NULL; 6030 const PetscInt *clp, *perm; 6031 PetscInt depth, numFields, numPoints, asize; 6032 6033 PetscFunctionBeginHot; 6034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6035 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6036 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6037 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6038 PetscCall(DMPlexGetDepth(dm, &depth)); 6039 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6040 if (depth == 1 && numFields < 2) { 6041 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6042 PetscFunctionReturn(PETSC_SUCCESS); 6043 } 6044 /* Get points */ 6045 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6046 /* Get sizes */ 6047 asize = 0; 6048 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6049 PetscInt dof; 6050 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6051 asize += dof; 6052 } 6053 if (values) { 6054 const PetscScalar *vArray; 6055 PetscInt size; 6056 6057 if (*values) { 6058 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); 6059 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6060 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6061 PetscCall(VecGetArrayRead(v, &vArray)); 6062 /* Get values */ 6063 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6064 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6065 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6066 /* Cleanup array */ 6067 PetscCall(VecRestoreArrayRead(v, &vArray)); 6068 } 6069 if (csize) *csize = asize; 6070 /* Cleanup points */ 6071 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6072 PetscFunctionReturn(PETSC_SUCCESS); 6073 } 6074 6075 /*@C 6076 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6077 6078 Not collective 6079 6080 Input Parameters: 6081 + dm - The `DM` 6082 . section - The section describing the layout in `v`, or `NULL` to use the default section 6083 . v - The local vector 6084 - point - The point in the `DM` 6085 6086 Input/Output Parameters: 6087 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6088 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6089 if the user provided `NULL`, it is a borrowed array and should not be freed 6090 6091 Level: intermediate 6092 6093 Notes: 6094 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6095 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6096 assembly function, and a user may already have allocated storage for this operation. 6097 6098 A typical use could be 6099 .vb 6100 values = NULL; 6101 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6102 for (cl = 0; cl < clSize; ++cl) { 6103 <Compute on closure> 6104 } 6105 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6106 .ve 6107 or 6108 .vb 6109 PetscMalloc1(clMaxSize, &values); 6110 for (p = pStart; p < pEnd; ++p) { 6111 clSize = clMaxSize; 6112 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6113 for (cl = 0; cl < clSize; ++cl) { 6114 <Compute on closure> 6115 } 6116 } 6117 PetscFree(values); 6118 .ve 6119 6120 Fortran Notes: 6121 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6122 6123 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6124 @*/ 6125 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6126 { 6127 PetscFunctionBeginHot; 6128 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, v, point, 0, csize, values)); 6129 PetscFunctionReturn(PETSC_SUCCESS); 6130 } 6131 6132 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6133 { 6134 DMLabel depthLabel; 6135 PetscSection clSection; 6136 IS clPoints; 6137 PetscScalar *array; 6138 const PetscScalar *vArray; 6139 PetscInt *points = NULL; 6140 const PetscInt *clp, *perm = NULL; 6141 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6142 6143 PetscFunctionBeginHot; 6144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6145 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6146 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6147 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6148 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6149 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6150 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6151 if (mdepth == 1 && numFields < 2) { 6152 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6153 PetscFunctionReturn(PETSC_SUCCESS); 6154 } 6155 /* Get points */ 6156 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6157 for (clsize = 0, p = 0; p < Np; p++) { 6158 PetscInt dof; 6159 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6160 clsize += dof; 6161 } 6162 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6163 /* Filter points */ 6164 for (p = 0; p < numPoints * 2; p += 2) { 6165 PetscInt dep; 6166 6167 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6168 if (dep != depth) continue; 6169 points[Np * 2 + 0] = points[p]; 6170 points[Np * 2 + 1] = points[p + 1]; 6171 ++Np; 6172 } 6173 /* Get array */ 6174 if (!values || !*values) { 6175 PetscInt asize = 0, dof; 6176 6177 for (p = 0; p < Np * 2; p += 2) { 6178 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6179 asize += dof; 6180 } 6181 if (!values) { 6182 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6183 if (csize) *csize = asize; 6184 PetscFunctionReturn(PETSC_SUCCESS); 6185 } 6186 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6187 } else { 6188 array = *values; 6189 } 6190 PetscCall(VecGetArrayRead(v, &vArray)); 6191 /* Get values */ 6192 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6193 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6194 /* Cleanup points */ 6195 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6196 /* Cleanup array */ 6197 PetscCall(VecRestoreArrayRead(v, &vArray)); 6198 if (!*values) { 6199 if (csize) *csize = size; 6200 *values = array; 6201 } else { 6202 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6203 *csize = size; 6204 } 6205 PetscFunctionReturn(PETSC_SUCCESS); 6206 } 6207 6208 /*@C 6209 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6210 6211 Not collective 6212 6213 Input Parameters: 6214 + dm - The `DM` 6215 . section - The section describing the layout in `v`, or `NULL` to use the default section 6216 . v - The local vector 6217 . point - The point in the `DM` 6218 . csize - The number of values in the closure, or `NULL` 6219 - values - The array of values, which is a borrowed array and should not be freed 6220 6221 Level: intermediate 6222 6223 Note: 6224 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6225 6226 Fortran Notes: 6227 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6228 6229 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6230 @*/ 6231 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6232 { 6233 PetscInt size = 0; 6234 6235 PetscFunctionBegin; 6236 /* Should work without recalculating size */ 6237 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6238 *values = NULL; 6239 PetscFunctionReturn(PETSC_SUCCESS); 6240 } 6241 6242 static inline void add(PetscScalar *x, PetscScalar y) 6243 { 6244 *x += y; 6245 } 6246 static inline void insert(PetscScalar *x, PetscScalar y) 6247 { 6248 *x = y; 6249 } 6250 6251 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[]) 6252 { 6253 PetscInt cdof; /* The number of constraints on this point */ 6254 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6255 PetscScalar *a; 6256 PetscInt off, cind = 0, k; 6257 6258 PetscFunctionBegin; 6259 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6260 PetscCall(PetscSectionGetOffset(section, point, &off)); 6261 a = &array[off]; 6262 if (!cdof || setBC) { 6263 if (clperm) { 6264 if (perm) { 6265 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6266 } else { 6267 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6268 } 6269 } else { 6270 if (perm) { 6271 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6272 } else { 6273 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6274 } 6275 } 6276 } else { 6277 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6278 if (clperm) { 6279 if (perm) { 6280 for (k = 0; k < dof; ++k) { 6281 if ((cind < cdof) && (k == cdofs[cind])) { 6282 ++cind; 6283 continue; 6284 } 6285 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6286 } 6287 } else { 6288 for (k = 0; k < dof; ++k) { 6289 if ((cind < cdof) && (k == cdofs[cind])) { 6290 ++cind; 6291 continue; 6292 } 6293 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6294 } 6295 } 6296 } else { 6297 if (perm) { 6298 for (k = 0; k < dof; ++k) { 6299 if ((cind < cdof) && (k == cdofs[cind])) { 6300 ++cind; 6301 continue; 6302 } 6303 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6304 } 6305 } else { 6306 for (k = 0; k < dof; ++k) { 6307 if ((cind < cdof) && (k == cdofs[cind])) { 6308 ++cind; 6309 continue; 6310 } 6311 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6312 } 6313 } 6314 } 6315 } 6316 PetscFunctionReturn(PETSC_SUCCESS); 6317 } 6318 6319 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[]) 6320 { 6321 PetscInt cdof; /* The number of constraints on this point */ 6322 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6323 PetscScalar *a; 6324 PetscInt off, cind = 0, k; 6325 6326 PetscFunctionBegin; 6327 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6328 PetscCall(PetscSectionGetOffset(section, point, &off)); 6329 a = &array[off]; 6330 if (cdof) { 6331 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6332 if (clperm) { 6333 if (perm) { 6334 for (k = 0; k < dof; ++k) { 6335 if ((cind < cdof) && (k == cdofs[cind])) { 6336 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6337 cind++; 6338 } 6339 } 6340 } else { 6341 for (k = 0; k < dof; ++k) { 6342 if ((cind < cdof) && (k == cdofs[cind])) { 6343 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6344 cind++; 6345 } 6346 } 6347 } 6348 } else { 6349 if (perm) { 6350 for (k = 0; k < dof; ++k) { 6351 if ((cind < cdof) && (k == cdofs[cind])) { 6352 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6353 cind++; 6354 } 6355 } 6356 } else { 6357 for (k = 0; k < dof; ++k) { 6358 if ((cind < cdof) && (k == cdofs[cind])) { 6359 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6360 cind++; 6361 } 6362 } 6363 } 6364 } 6365 } 6366 PetscFunctionReturn(PETSC_SUCCESS); 6367 } 6368 6369 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[]) 6370 { 6371 PetscScalar *a; 6372 PetscInt fdof, foff, fcdof, foffset = *offset; 6373 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6374 PetscInt cind = 0, b; 6375 6376 PetscFunctionBegin; 6377 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6378 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6379 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6380 a = &array[foff]; 6381 if (!fcdof || setBC) { 6382 if (clperm) { 6383 if (perm) { 6384 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6385 } else { 6386 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6387 } 6388 } else { 6389 if (perm) { 6390 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6391 } else { 6392 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6393 } 6394 } 6395 } else { 6396 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6397 if (clperm) { 6398 if (perm) { 6399 for (b = 0; b < fdof; b++) { 6400 if ((cind < fcdof) && (b == fcdofs[cind])) { 6401 ++cind; 6402 continue; 6403 } 6404 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6405 } 6406 } else { 6407 for (b = 0; b < fdof; b++) { 6408 if ((cind < fcdof) && (b == fcdofs[cind])) { 6409 ++cind; 6410 continue; 6411 } 6412 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6413 } 6414 } 6415 } else { 6416 if (perm) { 6417 for (b = 0; b < fdof; b++) { 6418 if ((cind < fcdof) && (b == fcdofs[cind])) { 6419 ++cind; 6420 continue; 6421 } 6422 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6423 } 6424 } else { 6425 for (b = 0; b < fdof; b++) { 6426 if ((cind < fcdof) && (b == fcdofs[cind])) { 6427 ++cind; 6428 continue; 6429 } 6430 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6431 } 6432 } 6433 } 6434 } 6435 *offset += fdof; 6436 PetscFunctionReturn(PETSC_SUCCESS); 6437 } 6438 6439 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[]) 6440 { 6441 PetscScalar *a; 6442 PetscInt fdof, foff, fcdof, foffset = *offset; 6443 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6444 PetscInt Nc, cind = 0, ncind = 0, b; 6445 PetscBool ncSet, fcSet; 6446 6447 PetscFunctionBegin; 6448 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6449 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6450 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6451 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6452 a = &array[foff]; 6453 if (fcdof) { 6454 /* We just override fcdof and fcdofs with Ncc and comps */ 6455 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6456 if (clperm) { 6457 if (perm) { 6458 if (comps) { 6459 for (b = 0; b < fdof; b++) { 6460 ncSet = fcSet = PETSC_FALSE; 6461 if (b % Nc == comps[ncind]) { 6462 ncind = (ncind + 1) % Ncc; 6463 ncSet = PETSC_TRUE; 6464 } 6465 if ((cind < fcdof) && (b == fcdofs[cind])) { 6466 ++cind; 6467 fcSet = PETSC_TRUE; 6468 } 6469 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6470 } 6471 } else { 6472 for (b = 0; b < fdof; b++) { 6473 if ((cind < fcdof) && (b == fcdofs[cind])) { 6474 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6475 ++cind; 6476 } 6477 } 6478 } 6479 } else { 6480 if (comps) { 6481 for (b = 0; b < fdof; b++) { 6482 ncSet = fcSet = PETSC_FALSE; 6483 if (b % Nc == comps[ncind]) { 6484 ncind = (ncind + 1) % Ncc; 6485 ncSet = PETSC_TRUE; 6486 } 6487 if ((cind < fcdof) && (b == fcdofs[cind])) { 6488 ++cind; 6489 fcSet = PETSC_TRUE; 6490 } 6491 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6492 } 6493 } else { 6494 for (b = 0; b < fdof; b++) { 6495 if ((cind < fcdof) && (b == fcdofs[cind])) { 6496 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6497 ++cind; 6498 } 6499 } 6500 } 6501 } 6502 } else { 6503 if (perm) { 6504 if (comps) { 6505 for (b = 0; b < fdof; b++) { 6506 ncSet = fcSet = PETSC_FALSE; 6507 if (b % Nc == comps[ncind]) { 6508 ncind = (ncind + 1) % Ncc; 6509 ncSet = PETSC_TRUE; 6510 } 6511 if ((cind < fcdof) && (b == fcdofs[cind])) { 6512 ++cind; 6513 fcSet = PETSC_TRUE; 6514 } 6515 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6516 } 6517 } else { 6518 for (b = 0; b < fdof; b++) { 6519 if ((cind < fcdof) && (b == fcdofs[cind])) { 6520 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6521 ++cind; 6522 } 6523 } 6524 } 6525 } else { 6526 if (comps) { 6527 for (b = 0; b < fdof; b++) { 6528 ncSet = fcSet = PETSC_FALSE; 6529 if (b % Nc == comps[ncind]) { 6530 ncind = (ncind + 1) % Ncc; 6531 ncSet = PETSC_TRUE; 6532 } 6533 if ((cind < fcdof) && (b == fcdofs[cind])) { 6534 ++cind; 6535 fcSet = PETSC_TRUE; 6536 } 6537 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6538 } 6539 } else { 6540 for (b = 0; b < fdof; b++) { 6541 if ((cind < fcdof) && (b == fcdofs[cind])) { 6542 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6543 ++cind; 6544 } 6545 } 6546 } 6547 } 6548 } 6549 } 6550 *offset += fdof; 6551 PetscFunctionReturn(PETSC_SUCCESS); 6552 } 6553 6554 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6555 { 6556 PetscScalar *array; 6557 const PetscInt *cone, *coneO; 6558 PetscInt pStart, pEnd, p, numPoints, off, dof; 6559 6560 PetscFunctionBeginHot; 6561 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6562 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6563 PetscCall(DMPlexGetCone(dm, point, &cone)); 6564 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6565 PetscCall(VecGetArray(v, &array)); 6566 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6567 const PetscInt cp = !p ? point : cone[p - 1]; 6568 const PetscInt o = !p ? 0 : coneO[p - 1]; 6569 6570 if ((cp < pStart) || (cp >= pEnd)) { 6571 dof = 0; 6572 continue; 6573 } 6574 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6575 /* ADD_VALUES */ 6576 { 6577 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6578 PetscScalar *a; 6579 PetscInt cdof, coff, cind = 0, k; 6580 6581 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6582 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6583 a = &array[coff]; 6584 if (!cdof) { 6585 if (o >= 0) { 6586 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6587 } else { 6588 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6589 } 6590 } else { 6591 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6592 if (o >= 0) { 6593 for (k = 0; k < dof; ++k) { 6594 if ((cind < cdof) && (k == cdofs[cind])) { 6595 ++cind; 6596 continue; 6597 } 6598 a[k] += values[off + k]; 6599 } 6600 } else { 6601 for (k = 0; k < dof; ++k) { 6602 if ((cind < cdof) && (k == cdofs[cind])) { 6603 ++cind; 6604 continue; 6605 } 6606 a[k] += values[off + dof - k - 1]; 6607 } 6608 } 6609 } 6610 } 6611 } 6612 PetscCall(VecRestoreArray(v, &array)); 6613 PetscFunctionReturn(PETSC_SUCCESS); 6614 } 6615 6616 /*@C 6617 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6618 6619 Not collective 6620 6621 Input Parameters: 6622 + dm - The `DM` 6623 . section - The section describing the layout in `v`, or `NULL` to use the default section 6624 . v - The local vector 6625 . point - The point in the `DM` 6626 . values - The array of values 6627 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6628 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6629 6630 Level: intermediate 6631 6632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6633 @*/ 6634 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6635 { 6636 PetscSection clSection; 6637 IS clPoints; 6638 PetscScalar *array; 6639 PetscInt *points = NULL; 6640 const PetscInt *clp, *clperm = NULL; 6641 PetscInt depth, numFields, numPoints, p, clsize; 6642 6643 PetscFunctionBeginHot; 6644 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6645 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6646 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6647 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6648 PetscCall(DMPlexGetDepth(dm, &depth)); 6649 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6650 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6651 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6652 PetscFunctionReturn(PETSC_SUCCESS); 6653 } 6654 /* Get points */ 6655 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6656 for (clsize = 0, p = 0; p < numPoints; p++) { 6657 PetscInt dof; 6658 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6659 clsize += dof; 6660 } 6661 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6662 /* Get array */ 6663 PetscCall(VecGetArray(v, &array)); 6664 /* Get values */ 6665 if (numFields > 0) { 6666 PetscInt offset = 0, f; 6667 for (f = 0; f < numFields; ++f) { 6668 const PetscInt **perms = NULL; 6669 const PetscScalar **flips = NULL; 6670 6671 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6672 switch (mode) { 6673 case INSERT_VALUES: 6674 for (p = 0; p < numPoints; p++) { 6675 const PetscInt point = points[2 * p]; 6676 const PetscInt *perm = perms ? perms[p] : NULL; 6677 const PetscScalar *flip = flips ? flips[p] : NULL; 6678 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6679 } 6680 break; 6681 case INSERT_ALL_VALUES: 6682 for (p = 0; p < numPoints; p++) { 6683 const PetscInt point = points[2 * p]; 6684 const PetscInt *perm = perms ? perms[p] : NULL; 6685 const PetscScalar *flip = flips ? flips[p] : NULL; 6686 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6687 } 6688 break; 6689 case INSERT_BC_VALUES: 6690 for (p = 0; p < numPoints; p++) { 6691 const PetscInt point = points[2 * p]; 6692 const PetscInt *perm = perms ? perms[p] : NULL; 6693 const PetscScalar *flip = flips ? flips[p] : NULL; 6694 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6695 } 6696 break; 6697 case ADD_VALUES: 6698 for (p = 0; p < numPoints; p++) { 6699 const PetscInt point = points[2 * p]; 6700 const PetscInt *perm = perms ? perms[p] : NULL; 6701 const PetscScalar *flip = flips ? flips[p] : NULL; 6702 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6703 } 6704 break; 6705 case ADD_ALL_VALUES: 6706 for (p = 0; p < numPoints; p++) { 6707 const PetscInt point = points[2 * p]; 6708 const PetscInt *perm = perms ? perms[p] : NULL; 6709 const PetscScalar *flip = flips ? flips[p] : NULL; 6710 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6711 } 6712 break; 6713 case ADD_BC_VALUES: 6714 for (p = 0; p < numPoints; p++) { 6715 const PetscInt point = points[2 * p]; 6716 const PetscInt *perm = perms ? perms[p] : NULL; 6717 const PetscScalar *flip = flips ? flips[p] : NULL; 6718 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6719 } 6720 break; 6721 default: 6722 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6723 } 6724 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6725 } 6726 } else { 6727 PetscInt dof, off; 6728 const PetscInt **perms = NULL; 6729 const PetscScalar **flips = NULL; 6730 6731 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6732 switch (mode) { 6733 case INSERT_VALUES: 6734 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6735 const PetscInt point = points[2 * p]; 6736 const PetscInt *perm = perms ? perms[p] : NULL; 6737 const PetscScalar *flip = flips ? flips[p] : NULL; 6738 PetscCall(PetscSectionGetDof(section, point, &dof)); 6739 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6740 } 6741 break; 6742 case INSERT_ALL_VALUES: 6743 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6744 const PetscInt point = points[2 * p]; 6745 const PetscInt *perm = perms ? perms[p] : NULL; 6746 const PetscScalar *flip = flips ? flips[p] : NULL; 6747 PetscCall(PetscSectionGetDof(section, point, &dof)); 6748 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6749 } 6750 break; 6751 case INSERT_BC_VALUES: 6752 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6753 const PetscInt point = points[2 * p]; 6754 const PetscInt *perm = perms ? perms[p] : NULL; 6755 const PetscScalar *flip = flips ? flips[p] : NULL; 6756 PetscCall(PetscSectionGetDof(section, point, &dof)); 6757 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6758 } 6759 break; 6760 case ADD_VALUES: 6761 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6762 const PetscInt point = points[2 * p]; 6763 const PetscInt *perm = perms ? perms[p] : NULL; 6764 const PetscScalar *flip = flips ? flips[p] : NULL; 6765 PetscCall(PetscSectionGetDof(section, point, &dof)); 6766 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6767 } 6768 break; 6769 case ADD_ALL_VALUES: 6770 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6771 const PetscInt point = points[2 * p]; 6772 const PetscInt *perm = perms ? perms[p] : NULL; 6773 const PetscScalar *flip = flips ? flips[p] : NULL; 6774 PetscCall(PetscSectionGetDof(section, point, &dof)); 6775 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6776 } 6777 break; 6778 case ADD_BC_VALUES: 6779 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6780 const PetscInt point = points[2 * p]; 6781 const PetscInt *perm = perms ? perms[p] : NULL; 6782 const PetscScalar *flip = flips ? flips[p] : NULL; 6783 PetscCall(PetscSectionGetDof(section, point, &dof)); 6784 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6785 } 6786 break; 6787 default: 6788 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6789 } 6790 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6791 } 6792 /* Cleanup points */ 6793 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6794 /* Cleanup array */ 6795 PetscCall(VecRestoreArray(v, &array)); 6796 PetscFunctionReturn(PETSC_SUCCESS); 6797 } 6798 6799 PetscErrorCode DMPlexVecSetStar(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6800 { 6801 const PetscInt *supp, *cone; 6802 PetscScalar *a; 6803 PetscInt dim, Ns, dof, off, n = 0; 6804 6805 PetscFunctionBegin; 6806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6807 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6808 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6809 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6810 if (PetscDefined(USE_DEBUG)) { 6811 PetscInt vStart, vEnd; 6812 6813 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6814 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); 6815 } 6816 PetscAssertPointer(values, 5); 6817 6818 PetscCall(DMGetDimension(dm, &dim)); 6819 PetscCall(DMPlexGetSupportSize(dm, point, &Ns)); 6820 PetscCall(DMPlexGetSupport(dm, point, &supp)); 6821 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); 6822 PetscCall(VecGetArray(v, &a)); 6823 PetscCall(PetscSectionGetDof(section, point, &dof)); 6824 PetscCall(PetscSectionGetOffset(section, point, &off)); 6825 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6826 for (PetscInt d = 0; d < dim; ++d) { 6827 // Left edge 6828 PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone)); 6829 PetscCall(PetscSectionGetDof(section, cone[0], &dof)); 6830 PetscCall(PetscSectionGetOffset(section, cone[0], &off)); 6831 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6832 // Right edge 6833 PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone)); 6834 PetscCall(PetscSectionGetDof(section, cone[1], &dof)); 6835 PetscCall(PetscSectionGetOffset(section, cone[1], &off)); 6836 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6837 } 6838 PetscCall(VecRestoreArray(v, &a)); 6839 PetscFunctionReturn(PETSC_SUCCESS); 6840 } 6841 6842 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6843 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6844 { 6845 PetscFunctionBegin; 6846 *contains = PETSC_TRUE; 6847 if (label) { 6848 PetscInt fdof; 6849 6850 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6851 if (!*contains) { 6852 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6853 *offset += fdof; 6854 PetscFunctionReturn(PETSC_SUCCESS); 6855 } 6856 } 6857 PetscFunctionReturn(PETSC_SUCCESS); 6858 } 6859 6860 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6861 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) 6862 { 6863 PetscSection clSection; 6864 IS clPoints; 6865 PetscScalar *array; 6866 PetscInt *points = NULL; 6867 const PetscInt *clp; 6868 PetscInt numFields, numPoints, p; 6869 PetscInt offset = 0, f; 6870 6871 PetscFunctionBeginHot; 6872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6873 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6874 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6875 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6876 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6877 /* Get points */ 6878 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6879 /* Get array */ 6880 PetscCall(VecGetArray(v, &array)); 6881 /* Get values */ 6882 for (f = 0; f < numFields; ++f) { 6883 const PetscInt **perms = NULL; 6884 const PetscScalar **flips = NULL; 6885 PetscBool contains; 6886 6887 if (!fieldActive[f]) { 6888 for (p = 0; p < numPoints * 2; p += 2) { 6889 PetscInt fdof; 6890 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6891 offset += fdof; 6892 } 6893 continue; 6894 } 6895 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6896 switch (mode) { 6897 case INSERT_VALUES: 6898 for (p = 0; p < numPoints; p++) { 6899 const PetscInt point = points[2 * p]; 6900 const PetscInt *perm = perms ? perms[p] : NULL; 6901 const PetscScalar *flip = flips ? flips[p] : NULL; 6902 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6903 if (!contains) continue; 6904 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6905 } 6906 break; 6907 case INSERT_ALL_VALUES: 6908 for (p = 0; p < numPoints; p++) { 6909 const PetscInt point = points[2 * p]; 6910 const PetscInt *perm = perms ? perms[p] : NULL; 6911 const PetscScalar *flip = flips ? flips[p] : NULL; 6912 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6913 if (!contains) continue; 6914 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6915 } 6916 break; 6917 case INSERT_BC_VALUES: 6918 for (p = 0; p < numPoints; p++) { 6919 const PetscInt point = points[2 * p]; 6920 const PetscInt *perm = perms ? perms[p] : NULL; 6921 const PetscScalar *flip = flips ? flips[p] : NULL; 6922 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6923 if (!contains) continue; 6924 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6925 } 6926 break; 6927 case ADD_VALUES: 6928 for (p = 0; p < numPoints; p++) { 6929 const PetscInt point = points[2 * p]; 6930 const PetscInt *perm = perms ? perms[p] : NULL; 6931 const PetscScalar *flip = flips ? flips[p] : NULL; 6932 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6933 if (!contains) continue; 6934 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6935 } 6936 break; 6937 case ADD_ALL_VALUES: 6938 for (p = 0; p < numPoints; p++) { 6939 const PetscInt point = points[2 * p]; 6940 const PetscInt *perm = perms ? perms[p] : NULL; 6941 const PetscScalar *flip = flips ? flips[p] : NULL; 6942 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6943 if (!contains) continue; 6944 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6945 } 6946 break; 6947 default: 6948 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6949 } 6950 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6951 } 6952 /* Cleanup points */ 6953 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6954 /* Cleanup array */ 6955 PetscCall(VecRestoreArray(v, &array)); 6956 PetscFunctionReturn(PETSC_SUCCESS); 6957 } 6958 6959 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6960 { 6961 PetscMPIInt rank; 6962 PetscInt i, j; 6963 6964 PetscFunctionBegin; 6965 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6966 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6967 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6968 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6969 numCIndices = numCIndices ? numCIndices : numRIndices; 6970 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6971 for (i = 0; i < numRIndices; i++) { 6972 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6973 for (j = 0; j < numCIndices; j++) { 6974 #if defined(PETSC_USE_COMPLEX) 6975 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6976 #else 6977 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6978 #endif 6979 } 6980 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6981 } 6982 PetscFunctionReturn(PETSC_SUCCESS); 6983 } 6984 6985 /* 6986 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6987 6988 Input Parameters: 6989 + section - The section for this data layout 6990 . islocal - Is the section (and thus indices being requested) local or global? 6991 . point - The point contributing dofs with these indices 6992 . off - The global offset of this point 6993 . loff - The local offset of each field 6994 . setBC - The flag determining whether to include indices of boundary values 6995 . perm - A permutation of the dofs on this point, or NULL 6996 - indperm - A permutation of the entire indices array, or NULL 6997 6998 Output Parameter: 6999 . indices - Indices for dofs on this point 7000 7001 Level: developer 7002 7003 Note: The indices could be local or global, depending on the value of 'off'. 7004 */ 7005 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 7006 { 7007 PetscInt dof; /* The number of unknowns on this point */ 7008 PetscInt cdof; /* The number of constraints on this point */ 7009 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 7010 PetscInt cind = 0, k; 7011 7012 PetscFunctionBegin; 7013 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7014 PetscCall(PetscSectionGetDof(section, point, &dof)); 7015 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 7016 if (!cdof || setBC) { 7017 for (k = 0; k < dof; ++k) { 7018 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7019 const PetscInt ind = indperm ? indperm[preind] : preind; 7020 7021 indices[ind] = off + k; 7022 } 7023 } else { 7024 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 7025 for (k = 0; k < dof; ++k) { 7026 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 7027 const PetscInt ind = indperm ? indperm[preind] : preind; 7028 7029 if ((cind < cdof) && (k == cdofs[cind])) { 7030 /* Insert check for returning constrained indices */ 7031 indices[ind] = -(off + k + 1); 7032 ++cind; 7033 } else { 7034 indices[ind] = off + k - (islocal ? 0 : cind); 7035 } 7036 } 7037 } 7038 *loff += dof; 7039 PetscFunctionReturn(PETSC_SUCCESS); 7040 } 7041 7042 /* 7043 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7044 7045 Input Parameters: 7046 + section - a section (global or local) 7047 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7048 . point - point within section 7049 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7050 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7051 . setBC - identify constrained (boundary condition) points via involution. 7052 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7053 . permsoff - offset 7054 - indperm - index permutation 7055 7056 Output Parameter: 7057 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7058 . indices - array to hold indices (as defined by section) of each dof associated with point 7059 7060 Notes: 7061 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7062 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7063 in the local vector. 7064 7065 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7066 significant). It is invalid to call with a global section and setBC=true. 7067 7068 Developer Note: 7069 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7070 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7071 offset could be obtained from the section instead of passing it explicitly as we do now. 7072 7073 Example: 7074 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7075 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7076 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7077 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. 7078 7079 Level: developer 7080 */ 7081 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[]) 7082 { 7083 PetscInt numFields, foff, f; 7084 7085 PetscFunctionBegin; 7086 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7087 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7088 for (f = 0, foff = 0; f < numFields; ++f) { 7089 PetscInt fdof, cfdof; 7090 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7091 PetscInt cind = 0, b; 7092 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7093 7094 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7095 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7096 if (!cfdof || setBC) { 7097 for (b = 0; b < fdof; ++b) { 7098 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7099 const PetscInt ind = indperm ? indperm[preind] : preind; 7100 7101 indices[ind] = off + foff + b; 7102 } 7103 } else { 7104 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7105 for (b = 0; b < fdof; ++b) { 7106 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7107 const PetscInt ind = indperm ? indperm[preind] : preind; 7108 7109 if ((cind < cfdof) && (b == fcdofs[cind])) { 7110 indices[ind] = -(off + foff + b + 1); 7111 ++cind; 7112 } else { 7113 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7114 } 7115 } 7116 } 7117 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7118 foffs[f] += fdof; 7119 } 7120 PetscFunctionReturn(PETSC_SUCCESS); 7121 } 7122 7123 /* 7124 This version believes the globalSection offsets for each field, rather than just the point offset 7125 7126 . foffs - The offset into 'indices' for each field, since it is segregated by field 7127 7128 Notes: 7129 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7130 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7131 */ 7132 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7133 { 7134 PetscInt numFields, foff, f; 7135 7136 PetscFunctionBegin; 7137 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7138 for (f = 0; f < numFields; ++f) { 7139 PetscInt fdof, cfdof; 7140 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7141 PetscInt cind = 0, b; 7142 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7143 7144 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7145 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7146 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7147 if (!cfdof) { 7148 for (b = 0; b < fdof; ++b) { 7149 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7150 const PetscInt ind = indperm ? indperm[preind] : preind; 7151 7152 indices[ind] = foff + b; 7153 } 7154 } else { 7155 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7156 for (b = 0; b < fdof; ++b) { 7157 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7158 const PetscInt ind = indperm ? indperm[preind] : preind; 7159 7160 if ((cind < cfdof) && (b == fcdofs[cind])) { 7161 indices[ind] = -(foff + b + 1); 7162 ++cind; 7163 } else { 7164 indices[ind] = foff + b - cind; 7165 } 7166 } 7167 } 7168 foffs[f] += fdof; 7169 } 7170 PetscFunctionReturn(PETSC_SUCCESS); 7171 } 7172 7173 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) 7174 { 7175 Mat cMat; 7176 PetscSection aSec, cSec; 7177 IS aIS; 7178 PetscInt aStart = -1, aEnd = -1; 7179 const PetscInt *anchors; 7180 PetscInt numFields, f, p, q, newP = 0; 7181 PetscInt newNumPoints = 0, newNumIndices = 0; 7182 PetscInt *newPoints, *indices, *newIndices; 7183 PetscInt maxAnchor, maxDof; 7184 PetscInt newOffsets[32]; 7185 PetscInt *pointMatOffsets[32]; 7186 PetscInt *newPointOffsets[32]; 7187 PetscScalar *pointMat[32]; 7188 PetscScalar *newValues = NULL, *tmpValues; 7189 PetscBool anyConstrained = PETSC_FALSE; 7190 7191 PetscFunctionBegin; 7192 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7193 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7194 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7195 7196 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7197 /* if there are point-to-point constraints */ 7198 if (aSec) { 7199 PetscCall(PetscArrayzero(newOffsets, 32)); 7200 PetscCall(ISGetIndices(aIS, &anchors)); 7201 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7202 /* figure out how many points are going to be in the new element matrix 7203 * (we allow double counting, because it's all just going to be summed 7204 * into the global matrix anyway) */ 7205 for (p = 0; p < 2 * numPoints; p += 2) { 7206 PetscInt b = points[p]; 7207 PetscInt bDof = 0, bSecDof; 7208 7209 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7210 if (!bSecDof) continue; 7211 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7212 if (bDof) { 7213 /* this point is constrained */ 7214 /* it is going to be replaced by its anchors */ 7215 PetscInt bOff, q; 7216 7217 anyConstrained = PETSC_TRUE; 7218 newNumPoints += bDof; 7219 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7220 for (q = 0; q < bDof; q++) { 7221 PetscInt a = anchors[bOff + q]; 7222 PetscInt aDof; 7223 7224 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7225 newNumIndices += aDof; 7226 for (f = 0; f < numFields; ++f) { 7227 PetscInt fDof; 7228 7229 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7230 newOffsets[f + 1] += fDof; 7231 } 7232 } 7233 } else { 7234 /* this point is not constrained */ 7235 newNumPoints++; 7236 newNumIndices += bSecDof; 7237 for (f = 0; f < numFields; ++f) { 7238 PetscInt fDof; 7239 7240 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7241 newOffsets[f + 1] += fDof; 7242 } 7243 } 7244 } 7245 } 7246 if (!anyConstrained) { 7247 if (outNumPoints) *outNumPoints = 0; 7248 if (outNumIndices) *outNumIndices = 0; 7249 if (outPoints) *outPoints = NULL; 7250 if (outValues) *outValues = NULL; 7251 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7252 PetscFunctionReturn(PETSC_SUCCESS); 7253 } 7254 7255 if (outNumPoints) *outNumPoints = newNumPoints; 7256 if (outNumIndices) *outNumIndices = newNumIndices; 7257 7258 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7259 7260 if (!outPoints && !outValues) { 7261 if (offsets) { 7262 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7263 } 7264 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7265 PetscFunctionReturn(PETSC_SUCCESS); 7266 } 7267 7268 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7269 7270 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7271 7272 /* workspaces */ 7273 if (numFields) { 7274 for (f = 0; f < numFields; f++) { 7275 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7276 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7277 } 7278 } else { 7279 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7280 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7281 } 7282 7283 /* get workspaces for the point-to-point matrices */ 7284 if (numFields) { 7285 PetscInt totalOffset, totalMatOffset; 7286 7287 for (p = 0; p < numPoints; p++) { 7288 PetscInt b = points[2 * p]; 7289 PetscInt bDof = 0, bSecDof; 7290 7291 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7292 if (!bSecDof) { 7293 for (f = 0; f < numFields; f++) { 7294 newPointOffsets[f][p + 1] = 0; 7295 pointMatOffsets[f][p + 1] = 0; 7296 } 7297 continue; 7298 } 7299 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7300 if (bDof) { 7301 for (f = 0; f < numFields; f++) { 7302 PetscInt fDof, q, bOff, allFDof = 0; 7303 7304 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7305 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7306 for (q = 0; q < bDof; q++) { 7307 PetscInt a = anchors[bOff + q]; 7308 PetscInt aFDof; 7309 7310 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7311 allFDof += aFDof; 7312 } 7313 newPointOffsets[f][p + 1] = allFDof; 7314 pointMatOffsets[f][p + 1] = fDof * allFDof; 7315 } 7316 } else { 7317 for (f = 0; f < numFields; f++) { 7318 PetscInt fDof; 7319 7320 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7321 newPointOffsets[f][p + 1] = fDof; 7322 pointMatOffsets[f][p + 1] = 0; 7323 } 7324 } 7325 } 7326 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7327 newPointOffsets[f][0] = totalOffset; 7328 pointMatOffsets[f][0] = totalMatOffset; 7329 for (p = 0; p < numPoints; p++) { 7330 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7331 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7332 } 7333 totalOffset = newPointOffsets[f][numPoints]; 7334 totalMatOffset = pointMatOffsets[f][numPoints]; 7335 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7336 } 7337 } else { 7338 for (p = 0; p < numPoints; p++) { 7339 PetscInt b = points[2 * p]; 7340 PetscInt bDof = 0, bSecDof; 7341 7342 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7343 if (!bSecDof) { 7344 newPointOffsets[0][p + 1] = 0; 7345 pointMatOffsets[0][p + 1] = 0; 7346 continue; 7347 } 7348 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7349 if (bDof) { 7350 PetscInt bOff, q, allDof = 0; 7351 7352 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7353 for (q = 0; q < bDof; q++) { 7354 PetscInt a = anchors[bOff + q], aDof; 7355 7356 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7357 allDof += aDof; 7358 } 7359 newPointOffsets[0][p + 1] = allDof; 7360 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7361 } else { 7362 newPointOffsets[0][p + 1] = bSecDof; 7363 pointMatOffsets[0][p + 1] = 0; 7364 } 7365 } 7366 newPointOffsets[0][0] = 0; 7367 pointMatOffsets[0][0] = 0; 7368 for (p = 0; p < numPoints; p++) { 7369 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7370 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7371 } 7372 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7373 } 7374 7375 /* output arrays */ 7376 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7377 7378 /* get the point-to-point matrices; construct newPoints */ 7379 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7380 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7381 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7382 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7383 if (numFields) { 7384 for (p = 0, newP = 0; p < numPoints; p++) { 7385 PetscInt b = points[2 * p]; 7386 PetscInt o = points[2 * p + 1]; 7387 PetscInt bDof = 0, bSecDof; 7388 7389 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7390 if (!bSecDof) continue; 7391 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7392 if (bDof) { 7393 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7394 7395 fStart[0] = 0; 7396 fEnd[0] = 0; 7397 for (f = 0; f < numFields; f++) { 7398 PetscInt fDof; 7399 7400 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7401 fStart[f + 1] = fStart[f] + fDof; 7402 fEnd[f + 1] = fStart[f + 1]; 7403 } 7404 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7405 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7406 7407 fAnchorStart[0] = 0; 7408 fAnchorEnd[0] = 0; 7409 for (f = 0; f < numFields; f++) { 7410 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7411 7412 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7413 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7414 } 7415 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7416 for (q = 0; q < bDof; q++) { 7417 PetscInt a = anchors[bOff + q], aOff; 7418 7419 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7420 newPoints[2 * (newP + q)] = a; 7421 newPoints[2 * (newP + q) + 1] = 0; 7422 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7423 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7424 } 7425 newP += bDof; 7426 7427 if (outValues) { 7428 /* get the point-to-point submatrix */ 7429 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])); 7430 } 7431 } else { 7432 newPoints[2 * newP] = b; 7433 newPoints[2 * newP + 1] = o; 7434 newP++; 7435 } 7436 } 7437 } else { 7438 for (p = 0; p < numPoints; p++) { 7439 PetscInt b = points[2 * p]; 7440 PetscInt o = points[2 * p + 1]; 7441 PetscInt bDof = 0, bSecDof; 7442 7443 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7444 if (!bSecDof) continue; 7445 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7446 if (bDof) { 7447 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7448 7449 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7450 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7451 7452 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7453 for (q = 0; q < bDof; q++) { 7454 PetscInt a = anchors[bOff + q], aOff; 7455 7456 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7457 7458 newPoints[2 * (newP + q)] = a; 7459 newPoints[2 * (newP + q) + 1] = 0; 7460 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7461 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7462 } 7463 newP += bDof; 7464 7465 /* get the point-to-point submatrix */ 7466 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7467 } else { 7468 newPoints[2 * newP] = b; 7469 newPoints[2 * newP + 1] = o; 7470 newP++; 7471 } 7472 } 7473 } 7474 7475 if (outValues) { 7476 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7477 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7478 /* multiply constraints on the right */ 7479 if (numFields) { 7480 for (f = 0; f < numFields; f++) { 7481 PetscInt oldOff = offsets[f]; 7482 7483 for (p = 0; p < numPoints; p++) { 7484 PetscInt cStart = newPointOffsets[f][p]; 7485 PetscInt b = points[2 * p]; 7486 PetscInt c, r, k; 7487 PetscInt dof; 7488 7489 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7490 if (!dof) continue; 7491 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7492 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7493 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7494 7495 for (r = 0; r < numIndices; r++) { 7496 for (c = 0; c < nCols; c++) { 7497 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7498 } 7499 } 7500 } else { 7501 /* copy this column as is */ 7502 for (r = 0; r < numIndices; r++) { 7503 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7504 } 7505 } 7506 oldOff += dof; 7507 } 7508 } 7509 } else { 7510 PetscInt oldOff = 0; 7511 for (p = 0; p < numPoints; p++) { 7512 PetscInt cStart = newPointOffsets[0][p]; 7513 PetscInt b = points[2 * p]; 7514 PetscInt c, r, k; 7515 PetscInt dof; 7516 7517 PetscCall(PetscSectionGetDof(section, b, &dof)); 7518 if (!dof) continue; 7519 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7520 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7521 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7522 7523 for (r = 0; r < numIndices; r++) { 7524 for (c = 0; c < nCols; c++) { 7525 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7526 } 7527 } 7528 } else { 7529 /* copy this column as is */ 7530 for (r = 0; r < numIndices; r++) { 7531 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7532 } 7533 } 7534 oldOff += dof; 7535 } 7536 } 7537 7538 if (multiplyLeft) { 7539 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7540 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7541 /* multiply constraints transpose on the left */ 7542 if (numFields) { 7543 for (f = 0; f < numFields; f++) { 7544 PetscInt oldOff = offsets[f]; 7545 7546 for (p = 0; p < numPoints; p++) { 7547 PetscInt rStart = newPointOffsets[f][p]; 7548 PetscInt b = points[2 * p]; 7549 PetscInt c, r, k; 7550 PetscInt dof; 7551 7552 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7553 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7554 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7555 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7556 7557 for (r = 0; r < nRows; r++) { 7558 for (c = 0; c < newNumIndices; c++) { 7559 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7560 } 7561 } 7562 } else { 7563 /* copy this row as is */ 7564 for (r = 0; r < dof; r++) { 7565 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7566 } 7567 } 7568 oldOff += dof; 7569 } 7570 } 7571 } else { 7572 PetscInt oldOff = 0; 7573 7574 for (p = 0; p < numPoints; p++) { 7575 PetscInt rStart = newPointOffsets[0][p]; 7576 PetscInt b = points[2 * p]; 7577 PetscInt c, r, k; 7578 PetscInt dof; 7579 7580 PetscCall(PetscSectionGetDof(section, b, &dof)); 7581 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7582 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7583 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7584 7585 for (r = 0; r < nRows; r++) { 7586 for (c = 0; c < newNumIndices; c++) { 7587 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7588 } 7589 } 7590 } else { 7591 /* copy this row as is */ 7592 for (r = 0; r < dof; r++) { 7593 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7594 } 7595 } 7596 oldOff += dof; 7597 } 7598 } 7599 7600 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7601 } else { 7602 newValues = tmpValues; 7603 } 7604 } 7605 7606 /* clean up */ 7607 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7608 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7609 7610 if (numFields) { 7611 for (f = 0; f < numFields; f++) { 7612 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7613 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7614 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7615 } 7616 } else { 7617 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7618 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7619 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7620 } 7621 PetscCall(ISRestoreIndices(aIS, &anchors)); 7622 7623 /* output */ 7624 if (outPoints) { 7625 *outPoints = newPoints; 7626 } else { 7627 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7628 } 7629 if (outValues) *outValues = newValues; 7630 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7631 PetscFunctionReturn(PETSC_SUCCESS); 7632 } 7633 7634 /*@C 7635 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7636 7637 Not collective 7638 7639 Input Parameters: 7640 + dm - The `DM` 7641 . section - The `PetscSection` describing the points (a local section) 7642 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7643 . point - The point defining the closure 7644 - useClPerm - Use the closure point permutation if available 7645 7646 Output Parameters: 7647 + numIndices - The number of dof indices in the closure of point with the input sections 7648 . indices - The dof indices 7649 . outOffsets - Array to write the field offsets into, or `NULL` 7650 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7651 7652 Level: advanced 7653 7654 Notes: 7655 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7656 7657 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7658 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7659 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7660 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7661 indices (with the above semantics) are implied. 7662 7663 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7664 `PetscSection`, `DMGetGlobalSection()` 7665 @*/ 7666 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7667 { 7668 /* Closure ordering */ 7669 PetscSection clSection; 7670 IS clPoints; 7671 const PetscInt *clp; 7672 PetscInt *points; 7673 const PetscInt *clperm = NULL; 7674 /* Dof permutation and sign flips */ 7675 const PetscInt **perms[32] = {NULL}; 7676 const PetscScalar **flips[32] = {NULL}; 7677 PetscScalar *valCopy = NULL; 7678 /* Hanging node constraints */ 7679 PetscInt *pointsC = NULL; 7680 PetscScalar *valuesC = NULL; 7681 PetscInt NclC, NiC; 7682 7683 PetscInt *idx; 7684 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7685 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7686 7687 PetscFunctionBeginHot; 7688 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7689 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7690 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7691 if (numIndices) PetscAssertPointer(numIndices, 6); 7692 if (indices) PetscAssertPointer(indices, 7); 7693 if (outOffsets) PetscAssertPointer(outOffsets, 8); 7694 if (values) PetscAssertPointer(values, 9); 7695 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7696 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7697 PetscCall(PetscArrayzero(offsets, 32)); 7698 /* 1) Get points in closure */ 7699 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7700 if (useClPerm) { 7701 PetscInt depth, clsize; 7702 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7703 for (clsize = 0, p = 0; p < Ncl; p++) { 7704 PetscInt dof; 7705 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7706 clsize += dof; 7707 } 7708 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7709 } 7710 /* 2) Get number of indices on these points and field offsets from section */ 7711 for (p = 0; p < Ncl * 2; p += 2) { 7712 PetscInt dof, fdof; 7713 7714 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7715 for (f = 0; f < Nf; ++f) { 7716 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7717 offsets[f + 1] += fdof; 7718 } 7719 Ni += dof; 7720 } 7721 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7722 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7723 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7724 for (f = 0; f < PetscMax(1, Nf); ++f) { 7725 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7726 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7727 /* may need to apply sign changes to the element matrix */ 7728 if (values && flips[f]) { 7729 PetscInt foffset = offsets[f]; 7730 7731 for (p = 0; p < Ncl; ++p) { 7732 PetscInt pnt = points[2 * p], fdof; 7733 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7734 7735 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7736 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7737 if (flip) { 7738 PetscInt i, j, k; 7739 7740 if (!valCopy) { 7741 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7742 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7743 *values = valCopy; 7744 } 7745 for (i = 0; i < fdof; ++i) { 7746 PetscScalar fval = flip[i]; 7747 7748 for (k = 0; k < Ni; ++k) { 7749 valCopy[Ni * (foffset + i) + k] *= fval; 7750 valCopy[Ni * k + (foffset + i)] *= fval; 7751 } 7752 } 7753 } 7754 foffset += fdof; 7755 } 7756 } 7757 } 7758 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7759 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7760 if (NclC) { 7761 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7762 for (f = 0; f < PetscMax(1, Nf); ++f) { 7763 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7764 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7765 } 7766 for (f = 0; f < PetscMax(1, Nf); ++f) { 7767 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7768 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7769 } 7770 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7771 Ncl = NclC; 7772 Ni = NiC; 7773 points = pointsC; 7774 if (values) *values = valuesC; 7775 } 7776 /* 5) Calculate indices */ 7777 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7778 if (Nf) { 7779 PetscInt idxOff; 7780 PetscBool useFieldOffsets; 7781 7782 if (outOffsets) { 7783 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7784 } 7785 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7786 if (useFieldOffsets) { 7787 for (p = 0; p < Ncl; ++p) { 7788 const PetscInt pnt = points[p * 2]; 7789 7790 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7791 } 7792 } else { 7793 for (p = 0; p < Ncl; ++p) { 7794 const PetscInt pnt = points[p * 2]; 7795 7796 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7797 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7798 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7799 * global section. */ 7800 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7801 } 7802 } 7803 } else { 7804 PetscInt off = 0, idxOff; 7805 7806 for (p = 0; p < Ncl; ++p) { 7807 const PetscInt pnt = points[p * 2]; 7808 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7809 7810 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7811 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7812 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7813 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7814 } 7815 } 7816 /* 6) Cleanup */ 7817 for (f = 0; f < PetscMax(1, Nf); ++f) { 7818 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7819 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7820 } 7821 if (NclC) { 7822 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7823 } else { 7824 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7825 } 7826 7827 if (numIndices) *numIndices = Ni; 7828 if (indices) *indices = idx; 7829 PetscFunctionReturn(PETSC_SUCCESS); 7830 } 7831 7832 /*@C 7833 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7834 7835 Not collective 7836 7837 Input Parameters: 7838 + dm - The `DM` 7839 . section - The `PetscSection` describing the points (a local section) 7840 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7841 . point - The point defining the closure 7842 - useClPerm - Use the closure point permutation if available 7843 7844 Output Parameters: 7845 + numIndices - The number of dof indices in the closure of point with the input sections 7846 . indices - The dof indices 7847 . outOffsets - Array to write the field offsets into, or `NULL` 7848 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7849 7850 Level: advanced 7851 7852 Notes: 7853 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7854 7855 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7856 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7857 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7858 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7859 indices (with the above semantics) are implied. 7860 7861 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7862 @*/ 7863 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7864 { 7865 PetscFunctionBegin; 7866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7867 PetscAssertPointer(indices, 7); 7868 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7869 PetscFunctionReturn(PETSC_SUCCESS); 7870 } 7871 7872 /*@C 7873 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7874 7875 Not collective 7876 7877 Input Parameters: 7878 + dm - The `DM` 7879 . section - The section describing the layout in `v`, or `NULL` to use the default section 7880 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 7881 . A - The matrix 7882 . point - The point in the `DM` 7883 . values - The array of values 7884 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7885 7886 Level: intermediate 7887 7888 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7889 @*/ 7890 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7891 { 7892 DM_Plex *mesh = (DM_Plex *)dm->data; 7893 PetscInt *indices; 7894 PetscInt numIndices; 7895 const PetscScalar *valuesOrig = values; 7896 PetscErrorCode ierr; 7897 7898 PetscFunctionBegin; 7899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7900 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7901 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7902 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7903 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7904 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7905 7906 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7907 7908 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7909 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7910 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7911 if (ierr) { 7912 PetscMPIInt rank; 7913 7914 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7915 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7916 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7917 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7918 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7919 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7920 } 7921 if (mesh->printFEM > 1) { 7922 PetscInt i; 7923 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7924 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7925 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7926 } 7927 7928 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7929 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7930 PetscFunctionReturn(PETSC_SUCCESS); 7931 } 7932 7933 /*@C 7934 DMPlexMatSetClosureGeneral - Set an array of the values on the closure of 'point' using a different row and column section 7935 7936 Not collective 7937 7938 Input Parameters: 7939 + dmRow - The `DM` for the row fields 7940 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 7941 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 7942 . dmCol - The `DM` for the column fields 7943 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 7944 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 7945 . A - The matrix 7946 . point - The point in the `DM` 7947 . values - The array of values 7948 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7949 7950 Level: intermediate 7951 7952 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7953 @*/ 7954 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7955 { 7956 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7957 PetscInt *indicesRow, *indicesCol; 7958 PetscInt numIndicesRow, numIndicesCol; 7959 const PetscScalar *valuesOrig = values; 7960 PetscErrorCode ierr; 7961 7962 PetscFunctionBegin; 7963 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7964 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7965 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7966 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7967 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7968 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7969 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7970 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7971 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7972 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7973 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7974 7975 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7976 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7977 7978 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7979 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7980 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7981 if (ierr) { 7982 PetscMPIInt rank; 7983 7984 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7985 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7986 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7987 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7988 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7989 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7990 } 7991 7992 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7993 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7994 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7995 PetscFunctionReturn(PETSC_SUCCESS); 7996 } 7997 7998 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7999 { 8000 DM_Plex *mesh = (DM_Plex *)dmf->data; 8001 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8002 PetscInt *cpoints = NULL; 8003 PetscInt *findices, *cindices; 8004 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8005 PetscInt foffsets[32], coffsets[32]; 8006 DMPolytopeType ct; 8007 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8008 PetscErrorCode ierr; 8009 8010 PetscFunctionBegin; 8011 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8012 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8013 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8014 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8015 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8016 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8017 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8018 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8019 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8020 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8021 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 8022 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8023 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8024 PetscCall(PetscArrayzero(foffsets, 32)); 8025 PetscCall(PetscArrayzero(coffsets, 32)); 8026 /* Column indices */ 8027 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8028 maxFPoints = numCPoints; 8029 /* Compress out points not in the section */ 8030 /* TODO: Squeeze out points with 0 dof as well */ 8031 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8032 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8033 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8034 cpoints[q * 2] = cpoints[p]; 8035 cpoints[q * 2 + 1] = cpoints[p + 1]; 8036 ++q; 8037 } 8038 } 8039 numCPoints = q; 8040 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8041 PetscInt fdof; 8042 8043 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8044 if (!dof) continue; 8045 for (f = 0; f < numFields; ++f) { 8046 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8047 coffsets[f + 1] += fdof; 8048 } 8049 numCIndices += dof; 8050 } 8051 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8052 /* Row indices */ 8053 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8054 { 8055 DMPlexTransform tr; 8056 DMPolytopeType *rct; 8057 PetscInt *rsize, *rcone, *rornt, Nt; 8058 8059 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8060 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8061 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8062 numSubcells = rsize[Nt - 1]; 8063 PetscCall(DMPlexTransformDestroy(&tr)); 8064 } 8065 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8066 for (r = 0, q = 0; r < numSubcells; ++r) { 8067 /* TODO Map from coarse to fine cells */ 8068 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8069 /* Compress out points not in the section */ 8070 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8071 for (p = 0; p < numFPoints * 2; p += 2) { 8072 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8073 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8074 if (!dof) continue; 8075 for (s = 0; s < q; ++s) 8076 if (fpoints[p] == ftotpoints[s * 2]) break; 8077 if (s < q) continue; 8078 ftotpoints[q * 2] = fpoints[p]; 8079 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8080 ++q; 8081 } 8082 } 8083 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8084 } 8085 numFPoints = q; 8086 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8087 PetscInt fdof; 8088 8089 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8090 if (!dof) continue; 8091 for (f = 0; f < numFields; ++f) { 8092 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8093 foffsets[f + 1] += fdof; 8094 } 8095 numFIndices += dof; 8096 } 8097 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8098 8099 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8100 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8101 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8102 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8103 if (numFields) { 8104 const PetscInt **permsF[32] = {NULL}; 8105 const PetscInt **permsC[32] = {NULL}; 8106 8107 for (f = 0; f < numFields; f++) { 8108 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8109 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8110 } 8111 for (p = 0; p < numFPoints; p++) { 8112 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8113 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8114 } 8115 for (p = 0; p < numCPoints; p++) { 8116 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8117 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8118 } 8119 for (f = 0; f < numFields; f++) { 8120 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8121 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8122 } 8123 } else { 8124 const PetscInt **permsF = NULL; 8125 const PetscInt **permsC = NULL; 8126 8127 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8128 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8129 for (p = 0, off = 0; p < numFPoints; p++) { 8130 const PetscInt *perm = permsF ? permsF[p] : NULL; 8131 8132 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8133 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8134 } 8135 for (p = 0, off = 0; p < numCPoints; p++) { 8136 const PetscInt *perm = permsC ? permsC[p] : NULL; 8137 8138 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8139 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8140 } 8141 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8142 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8143 } 8144 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8145 /* TODO: flips */ 8146 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8147 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8148 if (ierr) { 8149 PetscMPIInt rank; 8150 8151 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8152 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8153 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8154 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8155 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8156 } 8157 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8158 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8159 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8160 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8161 PetscFunctionReturn(PETSC_SUCCESS); 8162 } 8163 8164 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8165 { 8166 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8167 PetscInt *cpoints = NULL; 8168 PetscInt foffsets[32], coffsets[32]; 8169 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8170 DMPolytopeType ct; 8171 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8172 8173 PetscFunctionBegin; 8174 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8175 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8176 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8177 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8178 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8179 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8180 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8181 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8182 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8183 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8184 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8185 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8186 PetscCall(PetscArrayzero(foffsets, 32)); 8187 PetscCall(PetscArrayzero(coffsets, 32)); 8188 /* Column indices */ 8189 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8190 maxFPoints = numCPoints; 8191 /* Compress out points not in the section */ 8192 /* TODO: Squeeze out points with 0 dof as well */ 8193 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8194 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8195 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8196 cpoints[q * 2] = cpoints[p]; 8197 cpoints[q * 2 + 1] = cpoints[p + 1]; 8198 ++q; 8199 } 8200 } 8201 numCPoints = q; 8202 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8203 PetscInt fdof; 8204 8205 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8206 if (!dof) continue; 8207 for (f = 0; f < numFields; ++f) { 8208 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8209 coffsets[f + 1] += fdof; 8210 } 8211 numCIndices += dof; 8212 } 8213 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8214 /* Row indices */ 8215 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8216 { 8217 DMPlexTransform tr; 8218 DMPolytopeType *rct; 8219 PetscInt *rsize, *rcone, *rornt, Nt; 8220 8221 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8222 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8223 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8224 numSubcells = rsize[Nt - 1]; 8225 PetscCall(DMPlexTransformDestroy(&tr)); 8226 } 8227 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8228 for (r = 0, q = 0; r < numSubcells; ++r) { 8229 /* TODO Map from coarse to fine cells */ 8230 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8231 /* Compress out points not in the section */ 8232 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8233 for (p = 0; p < numFPoints * 2; p += 2) { 8234 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8235 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8236 if (!dof) continue; 8237 for (s = 0; s < q; ++s) 8238 if (fpoints[p] == ftotpoints[s * 2]) break; 8239 if (s < q) continue; 8240 ftotpoints[q * 2] = fpoints[p]; 8241 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8242 ++q; 8243 } 8244 } 8245 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8246 } 8247 numFPoints = q; 8248 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8249 PetscInt fdof; 8250 8251 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8252 if (!dof) continue; 8253 for (f = 0; f < numFields; ++f) { 8254 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8255 foffsets[f + 1] += fdof; 8256 } 8257 numFIndices += dof; 8258 } 8259 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8260 8261 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8262 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8263 if (numFields) { 8264 const PetscInt **permsF[32] = {NULL}; 8265 const PetscInt **permsC[32] = {NULL}; 8266 8267 for (f = 0; f < numFields; f++) { 8268 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8269 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8270 } 8271 for (p = 0; p < numFPoints; p++) { 8272 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8273 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8274 } 8275 for (p = 0; p < numCPoints; p++) { 8276 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8277 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8278 } 8279 for (f = 0; f < numFields; f++) { 8280 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8281 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8282 } 8283 } else { 8284 const PetscInt **permsF = NULL; 8285 const PetscInt **permsC = NULL; 8286 8287 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8288 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8289 for (p = 0, off = 0; p < numFPoints; p++) { 8290 const PetscInt *perm = permsF ? permsF[p] : NULL; 8291 8292 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8293 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8294 } 8295 for (p = 0, off = 0; p < numCPoints; p++) { 8296 const PetscInt *perm = permsC ? permsC[p] : NULL; 8297 8298 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8299 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8300 } 8301 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8302 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8303 } 8304 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8305 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8306 PetscFunctionReturn(PETSC_SUCCESS); 8307 } 8308 8309 /*@C 8310 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8311 8312 Input Parameter: 8313 . dm - The `DMPLEX` object 8314 8315 Output Parameter: 8316 . cellHeight - The height of a cell 8317 8318 Level: developer 8319 8320 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8321 @*/ 8322 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8323 { 8324 DM_Plex *mesh = (DM_Plex *)dm->data; 8325 8326 PetscFunctionBegin; 8327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8328 PetscAssertPointer(cellHeight, 2); 8329 *cellHeight = mesh->vtkCellHeight; 8330 PetscFunctionReturn(PETSC_SUCCESS); 8331 } 8332 8333 /*@C 8334 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8335 8336 Input Parameters: 8337 + dm - The `DMPLEX` object 8338 - cellHeight - The height of a cell 8339 8340 Level: developer 8341 8342 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8343 @*/ 8344 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8345 { 8346 DM_Plex *mesh = (DM_Plex *)dm->data; 8347 8348 PetscFunctionBegin; 8349 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8350 mesh->vtkCellHeight = cellHeight; 8351 PetscFunctionReturn(PETSC_SUCCESS); 8352 } 8353 8354 /*@ 8355 DMPlexGetCellTypeStratum - Get the range of cells of a given celltype 8356 8357 Input Parameters: 8358 + dm - The `DMPLEX` object 8359 - ct - The `DMPolytopeType` of the cell 8360 8361 Output Parameters: 8362 + start - The first cell of this type, or `NULL` 8363 - end - The upper bound on this celltype, or `NULL` 8364 8365 Level: advanced 8366 8367 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 8368 @*/ 8369 PetscErrorCode DMPlexGetCellTypeStratum(DM dm, DMPolytopeType ct, PetscInt *start, PetscInt *end) 8370 { 8371 DM_Plex *mesh = (DM_Plex *)dm->data; 8372 DMLabel label; 8373 PetscInt pStart, pEnd; 8374 8375 PetscFunctionBegin; 8376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8377 if (start) { 8378 PetscAssertPointer(start, 3); 8379 *start = 0; 8380 } 8381 if (end) { 8382 PetscAssertPointer(end, 4); 8383 *end = 0; 8384 } 8385 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8386 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 8387 if (mesh->tr) { 8388 PetscCall(DMPlexTransformGetCellTypeStratum(mesh->tr, ct, start, end)); 8389 } else { 8390 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 8391 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named celltype was found"); 8392 PetscCall(DMLabelGetStratumBounds(label, ct, start, end)); 8393 } 8394 PetscFunctionReturn(PETSC_SUCCESS); 8395 } 8396 8397 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8398 { 8399 PetscSection section, globalSection; 8400 PetscInt *numbers, p; 8401 8402 PetscFunctionBegin; 8403 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8404 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8405 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8406 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8407 PetscCall(PetscSectionSetUp(section)); 8408 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8409 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8410 for (p = pStart; p < pEnd; ++p) { 8411 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8412 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8413 else numbers[p - pStart] += shift; 8414 } 8415 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8416 if (globalSize) { 8417 PetscLayout layout; 8418 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8419 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8420 PetscCall(PetscLayoutDestroy(&layout)); 8421 } 8422 PetscCall(PetscSectionDestroy(§ion)); 8423 PetscCall(PetscSectionDestroy(&globalSection)); 8424 PetscFunctionReturn(PETSC_SUCCESS); 8425 } 8426 8427 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8428 { 8429 PetscInt cellHeight, cStart, cEnd; 8430 8431 PetscFunctionBegin; 8432 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8433 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8434 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8435 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8436 PetscFunctionReturn(PETSC_SUCCESS); 8437 } 8438 8439 /*@ 8440 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8441 8442 Input Parameter: 8443 . dm - The `DMPLEX` object 8444 8445 Output Parameter: 8446 . globalCellNumbers - Global cell numbers for all cells on this process 8447 8448 Level: developer 8449 8450 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8451 @*/ 8452 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8453 { 8454 DM_Plex *mesh = (DM_Plex *)dm->data; 8455 8456 PetscFunctionBegin; 8457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8458 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8459 *globalCellNumbers = mesh->globalCellNumbers; 8460 PetscFunctionReturn(PETSC_SUCCESS); 8461 } 8462 8463 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8464 { 8465 PetscInt vStart, vEnd; 8466 8467 PetscFunctionBegin; 8468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8469 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8470 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8471 PetscFunctionReturn(PETSC_SUCCESS); 8472 } 8473 8474 /*@ 8475 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8476 8477 Input Parameter: 8478 . dm - The `DMPLEX` object 8479 8480 Output Parameter: 8481 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8482 8483 Level: developer 8484 8485 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8486 @*/ 8487 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8488 { 8489 DM_Plex *mesh = (DM_Plex *)dm->data; 8490 8491 PetscFunctionBegin; 8492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8493 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8494 *globalVertexNumbers = mesh->globalVertexNumbers; 8495 PetscFunctionReturn(PETSC_SUCCESS); 8496 } 8497 8498 /*@ 8499 DMPlexCreatePointNumbering - Create a global numbering for all points. 8500 8501 Collective 8502 8503 Input Parameter: 8504 . dm - The `DMPLEX` object 8505 8506 Output Parameter: 8507 . globalPointNumbers - Global numbers for all points on this process 8508 8509 Level: developer 8510 8511 Notes: 8512 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8513 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8514 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8515 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8516 8517 The partitioned mesh is 8518 ``` 8519 (2)--0--(3)--1--(4) (1)--0--(2) 8520 ``` 8521 and its global numbering is 8522 ``` 8523 (3)--0--(4)--1--(5)--2--(6) 8524 ``` 8525 Then the global numbering is provided as 8526 ``` 8527 [0] Number of indices in set 5 8528 [0] 0 0 8529 [0] 1 1 8530 [0] 2 3 8531 [0] 3 4 8532 [0] 4 -6 8533 [1] Number of indices in set 3 8534 [1] 0 2 8535 [1] 1 5 8536 [1] 2 6 8537 ``` 8538 8539 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8540 @*/ 8541 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8542 { 8543 IS nums[4]; 8544 PetscInt depths[4], gdepths[4], starts[4]; 8545 PetscInt depth, d, shift = 0; 8546 PetscBool empty = PETSC_FALSE; 8547 8548 PetscFunctionBegin; 8549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8550 PetscCall(DMPlexGetDepth(dm, &depth)); 8551 // For unstratified meshes use dim instead of depth 8552 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8553 // If any stratum is empty, we must mark all empty 8554 for (d = 0; d <= depth; ++d) { 8555 PetscInt end; 8556 8557 depths[d] = depth - d; 8558 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8559 if (!(starts[d] - end)) empty = PETSC_TRUE; 8560 } 8561 if (empty) 8562 for (d = 0; d <= depth; ++d) { 8563 depths[d] = -1; 8564 starts[d] = -1; 8565 } 8566 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8567 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8568 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]); 8569 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8570 for (d = 0; d <= depth; ++d) { 8571 PetscInt pStart, pEnd, gsize; 8572 8573 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8574 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8575 shift += gsize; 8576 } 8577 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8578 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8579 PetscFunctionReturn(PETSC_SUCCESS); 8580 } 8581 8582 /*@ 8583 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8584 8585 Input Parameter: 8586 . dm - The `DMPLEX` object 8587 8588 Output Parameter: 8589 . ranks - The rank field 8590 8591 Options Database Key: 8592 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8593 8594 Level: intermediate 8595 8596 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8597 @*/ 8598 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8599 { 8600 DM rdm; 8601 PetscFE fe; 8602 PetscScalar *r; 8603 PetscMPIInt rank; 8604 DMPolytopeType ct; 8605 PetscInt dim, cStart, cEnd, c; 8606 PetscBool simplex; 8607 8608 PetscFunctionBeginUser; 8609 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8610 PetscAssertPointer(ranks, 2); 8611 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8612 PetscCall(DMClone(dm, &rdm)); 8613 PetscCall(DMGetDimension(rdm, &dim)); 8614 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8615 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8616 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8617 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8618 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8619 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8620 PetscCall(PetscFEDestroy(&fe)); 8621 PetscCall(DMCreateDS(rdm)); 8622 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8623 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8624 PetscCall(VecGetArray(*ranks, &r)); 8625 for (c = cStart; c < cEnd; ++c) { 8626 PetscScalar *lr; 8627 8628 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8629 if (lr) *lr = rank; 8630 } 8631 PetscCall(VecRestoreArray(*ranks, &r)); 8632 PetscCall(DMDestroy(&rdm)); 8633 PetscFunctionReturn(PETSC_SUCCESS); 8634 } 8635 8636 /*@ 8637 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8638 8639 Input Parameters: 8640 + dm - The `DMPLEX` 8641 - label - The `DMLabel` 8642 8643 Output Parameter: 8644 . val - The label value field 8645 8646 Options Database Key: 8647 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8648 8649 Level: intermediate 8650 8651 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8652 @*/ 8653 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8654 { 8655 DM rdm; 8656 PetscFE fe; 8657 PetscScalar *v; 8658 PetscInt dim, cStart, cEnd, c; 8659 8660 PetscFunctionBeginUser; 8661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8662 PetscAssertPointer(label, 2); 8663 PetscAssertPointer(val, 3); 8664 PetscCall(DMClone(dm, &rdm)); 8665 PetscCall(DMGetDimension(rdm, &dim)); 8666 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8667 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8668 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8669 PetscCall(PetscFEDestroy(&fe)); 8670 PetscCall(DMCreateDS(rdm)); 8671 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8672 PetscCall(DMCreateGlobalVector(rdm, val)); 8673 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8674 PetscCall(VecGetArray(*val, &v)); 8675 for (c = cStart; c < cEnd; ++c) { 8676 PetscScalar *lv; 8677 PetscInt cval; 8678 8679 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8680 PetscCall(DMLabelGetValue(label, c, &cval)); 8681 *lv = cval; 8682 } 8683 PetscCall(VecRestoreArray(*val, &v)); 8684 PetscCall(DMDestroy(&rdm)); 8685 PetscFunctionReturn(PETSC_SUCCESS); 8686 } 8687 8688 /*@ 8689 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8690 8691 Input Parameter: 8692 . dm - The `DMPLEX` object 8693 8694 Level: developer 8695 8696 Notes: 8697 This is a useful diagnostic when creating meshes programmatically. 8698 8699 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8700 8701 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8702 @*/ 8703 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8704 { 8705 PetscSection coneSection, supportSection; 8706 const PetscInt *cone, *support; 8707 PetscInt coneSize, c, supportSize, s; 8708 PetscInt pStart, pEnd, p, pp, csize, ssize; 8709 PetscBool storagecheck = PETSC_TRUE; 8710 8711 PetscFunctionBegin; 8712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8713 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8714 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8715 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8716 /* Check that point p is found in the support of its cone points, and vice versa */ 8717 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8718 for (p = pStart; p < pEnd; ++p) { 8719 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8720 PetscCall(DMPlexGetCone(dm, p, &cone)); 8721 for (c = 0; c < coneSize; ++c) { 8722 PetscBool dup = PETSC_FALSE; 8723 PetscInt d; 8724 for (d = c - 1; d >= 0; --d) { 8725 if (cone[c] == cone[d]) { 8726 dup = PETSC_TRUE; 8727 break; 8728 } 8729 } 8730 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8731 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8732 for (s = 0; s < supportSize; ++s) { 8733 if (support[s] == p) break; 8734 } 8735 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8736 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8737 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8738 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8739 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8740 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8741 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8742 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]); 8743 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8744 } 8745 } 8746 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8747 if (p != pp) { 8748 storagecheck = PETSC_FALSE; 8749 continue; 8750 } 8751 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8752 PetscCall(DMPlexGetSupport(dm, p, &support)); 8753 for (s = 0; s < supportSize; ++s) { 8754 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8755 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8756 for (c = 0; c < coneSize; ++c) { 8757 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8758 if (cone[c] != pp) { 8759 c = 0; 8760 break; 8761 } 8762 if (cone[c] == p) break; 8763 } 8764 if (c >= coneSize) { 8765 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8766 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8767 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8768 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8769 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8770 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8771 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8772 } 8773 } 8774 } 8775 if (storagecheck) { 8776 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8777 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8778 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8779 } 8780 PetscFunctionReturn(PETSC_SUCCESS); 8781 } 8782 8783 /* 8784 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. 8785 */ 8786 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8787 { 8788 DMPolytopeType cct; 8789 PetscInt ptpoints[4]; 8790 const PetscInt *cone, *ccone, *ptcone; 8791 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8792 8793 PetscFunctionBegin; 8794 *unsplit = 0; 8795 switch (ct) { 8796 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8797 ptpoints[npt++] = c; 8798 break; 8799 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8800 PetscCall(DMPlexGetCone(dm, c, &cone)); 8801 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8802 for (cp = 0; cp < coneSize; ++cp) { 8803 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8804 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8805 } 8806 break; 8807 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8808 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8809 PetscCall(DMPlexGetCone(dm, c, &cone)); 8810 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8811 for (cp = 0; cp < coneSize; ++cp) { 8812 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8813 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8814 for (ccp = 0; ccp < cconeSize; ++ccp) { 8815 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8816 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8817 PetscInt p; 8818 for (p = 0; p < npt; ++p) 8819 if (ptpoints[p] == ccone[ccp]) break; 8820 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8821 } 8822 } 8823 } 8824 break; 8825 default: 8826 break; 8827 } 8828 for (pt = 0; pt < npt; ++pt) { 8829 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8830 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8831 } 8832 PetscFunctionReturn(PETSC_SUCCESS); 8833 } 8834 8835 /*@ 8836 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8837 8838 Input Parameters: 8839 + dm - The `DMPLEX` object 8840 - cellHeight - Normally 0 8841 8842 Level: developer 8843 8844 Notes: 8845 This is a useful diagnostic when creating meshes programmatically. 8846 Currently applicable only to homogeneous simplex or tensor meshes. 8847 8848 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8849 8850 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8851 @*/ 8852 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8853 { 8854 DMPlexInterpolatedFlag interp; 8855 DMPolytopeType ct; 8856 PetscInt vStart, vEnd, cStart, cEnd, c; 8857 8858 PetscFunctionBegin; 8859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8860 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8861 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8862 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8863 for (c = cStart; c < cEnd; ++c) { 8864 PetscInt *closure = NULL; 8865 PetscInt coneSize, closureSize, cl, Nv = 0; 8866 8867 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8868 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8869 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8870 if (interp == DMPLEX_INTERPOLATED_FULL) { 8871 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8872 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)); 8873 } 8874 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8875 for (cl = 0; cl < closureSize * 2; cl += 2) { 8876 const PetscInt p = closure[cl]; 8877 if ((p >= vStart) && (p < vEnd)) ++Nv; 8878 } 8879 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8880 /* Special Case: Tensor faces with identified vertices */ 8881 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8882 PetscInt unsplit; 8883 8884 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8885 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8886 } 8887 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)); 8888 } 8889 PetscFunctionReturn(PETSC_SUCCESS); 8890 } 8891 8892 /*@ 8893 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8894 8895 Collective 8896 8897 Input Parameters: 8898 + dm - The `DMPLEX` object 8899 - cellHeight - Normally 0 8900 8901 Level: developer 8902 8903 Notes: 8904 This is a useful diagnostic when creating meshes programmatically. 8905 This routine is only relevant for meshes that are fully interpolated across all ranks. 8906 It will error out if a partially interpolated mesh is given on some rank. 8907 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8908 8909 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8910 8911 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8912 @*/ 8913 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8914 { 8915 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8916 DMPlexInterpolatedFlag interpEnum; 8917 8918 PetscFunctionBegin; 8919 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8920 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8921 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8922 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8923 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8924 PetscFunctionReturn(PETSC_SUCCESS); 8925 } 8926 8927 PetscCall(DMGetDimension(dm, &dim)); 8928 PetscCall(DMPlexGetDepth(dm, &depth)); 8929 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8930 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8931 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8932 for (c = cStart; c < cEnd; ++c) { 8933 const PetscInt *cone, *ornt, *faceSizes, *faces; 8934 const DMPolytopeType *faceTypes; 8935 DMPolytopeType ct; 8936 PetscInt numFaces, coneSize, f; 8937 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8938 8939 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8940 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8941 if (unsplit) continue; 8942 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8943 PetscCall(DMPlexGetCone(dm, c, &cone)); 8944 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8945 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8946 for (cl = 0; cl < closureSize * 2; cl += 2) { 8947 const PetscInt p = closure[cl]; 8948 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8949 } 8950 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8951 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); 8952 for (f = 0; f < numFaces; ++f) { 8953 DMPolytopeType fct; 8954 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8955 8956 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8957 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8958 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8959 const PetscInt p = fclosure[cl]; 8960 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8961 } 8962 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]); 8963 for (v = 0; v < fnumCorners; ++v) { 8964 if (fclosure[v] != faces[fOff + v]) { 8965 PetscInt v1; 8966 8967 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8968 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8969 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8970 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8971 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8972 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]); 8973 } 8974 } 8975 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8976 fOff += faceSizes[f]; 8977 } 8978 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8979 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8980 } 8981 } 8982 PetscFunctionReturn(PETSC_SUCCESS); 8983 } 8984 8985 /*@ 8986 DMPlexCheckGeometry - Check the geometry of mesh cells 8987 8988 Input Parameter: 8989 . dm - The `DMPLEX` object 8990 8991 Level: developer 8992 8993 Notes: 8994 This is a useful diagnostic when creating meshes programmatically. 8995 8996 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8997 8998 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8999 @*/ 9000 PetscErrorCode DMPlexCheckGeometry(DM dm) 9001 { 9002 Vec coordinates; 9003 PetscReal detJ, J[9], refVol = 1.0; 9004 PetscReal vol; 9005 PetscInt dim, depth, dE, d, cStart, cEnd, c; 9006 9007 PetscFunctionBegin; 9008 PetscCall(DMGetDimension(dm, &dim)); 9009 PetscCall(DMGetCoordinateDim(dm, &dE)); 9010 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 9011 PetscCall(DMPlexGetDepth(dm, &depth)); 9012 for (d = 0; d < dim; ++d) refVol *= 2.0; 9013 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9014 /* Make sure local coordinates are created, because that step is collective */ 9015 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 9016 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 9017 for (c = cStart; c < cEnd; ++c) { 9018 DMPolytopeType ct; 9019 PetscInt unsplit; 9020 PetscBool ignoreZeroVol = PETSC_FALSE; 9021 9022 PetscCall(DMPlexGetCellType(dm, c, &ct)); 9023 switch (ct) { 9024 case DM_POLYTOPE_SEG_PRISM_TENSOR: 9025 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9026 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9027 ignoreZeroVol = PETSC_TRUE; 9028 break; 9029 default: 9030 break; 9031 } 9032 switch (ct) { 9033 case DM_POLYTOPE_TRI_PRISM: 9034 case DM_POLYTOPE_TRI_PRISM_TENSOR: 9035 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 9036 case DM_POLYTOPE_PYRAMID: 9037 continue; 9038 default: 9039 break; 9040 } 9041 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 9042 if (unsplit) continue; 9043 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 9044 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); 9045 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 9046 /* This should work with periodicity since DG coordinates should be used */ 9047 if (depth > 1) { 9048 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9049 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); 9050 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9051 } 9052 } 9053 PetscFunctionReturn(PETSC_SUCCESS); 9054 } 9055 9056 /*@ 9057 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9058 9059 Collective 9060 9061 Input Parameters: 9062 + dm - The `DMPLEX` object 9063 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9064 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9065 9066 Level: developer 9067 9068 Notes: 9069 This is mainly intended for debugging/testing purposes. 9070 9071 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9072 9073 Extra roots can come from priodic cuts, where additional points appear on the boundary 9074 9075 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9076 @*/ 9077 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9078 { 9079 PetscInt l, nleaves, nroots, overlap; 9080 const PetscInt *locals; 9081 const PetscSFNode *remotes; 9082 PetscBool distributed; 9083 MPI_Comm comm; 9084 PetscMPIInt rank; 9085 9086 PetscFunctionBegin; 9087 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9088 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9089 else pointSF = dm->sf; 9090 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9091 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9092 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9093 { 9094 PetscMPIInt mpiFlag; 9095 9096 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9097 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9098 } 9099 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9100 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9101 if (!distributed) { 9102 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); 9103 PetscFunctionReturn(PETSC_SUCCESS); 9104 } 9105 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); 9106 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9107 9108 /* Check SF graph is compatible with DMPlex chart */ 9109 { 9110 PetscInt pStart, pEnd, maxLeaf; 9111 9112 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9113 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9114 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9115 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9116 } 9117 9118 /* Check Point SF has no local points referenced */ 9119 for (l = 0; l < nleaves; l++) { 9120 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); 9121 } 9122 9123 /* Check there are no cells in interface */ 9124 if (!overlap) { 9125 PetscInt cellHeight, cStart, cEnd; 9126 9127 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9128 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9129 for (l = 0; l < nleaves; ++l) { 9130 const PetscInt point = locals ? locals[l] : l; 9131 9132 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9133 } 9134 } 9135 9136 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9137 { 9138 const PetscInt *rootdegree; 9139 9140 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9141 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9142 for (l = 0; l < nleaves; ++l) { 9143 const PetscInt point = locals ? locals[l] : l; 9144 const PetscInt *cone; 9145 PetscInt coneSize, c, idx; 9146 9147 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9148 PetscCall(DMPlexGetCone(dm, point, &cone)); 9149 for (c = 0; c < coneSize; ++c) { 9150 if (!rootdegree[cone[c]]) { 9151 if (locals) { 9152 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9153 } else { 9154 idx = (cone[c] < nleaves) ? cone[c] : -1; 9155 } 9156 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9157 } 9158 } 9159 } 9160 } 9161 PetscFunctionReturn(PETSC_SUCCESS); 9162 } 9163 9164 /*@ 9165 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9166 9167 Input Parameter: 9168 . dm - The `DMPLEX` object 9169 9170 Level: developer 9171 9172 Notes: 9173 This is a useful diagnostic when creating meshes programmatically. 9174 9175 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9176 9177 Currently does not include `DMPlexCheckCellShape()`. 9178 9179 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9180 @*/ 9181 PetscErrorCode DMPlexCheck(DM dm) 9182 { 9183 PetscInt cellHeight; 9184 9185 PetscFunctionBegin; 9186 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9187 PetscCall(DMPlexCheckSymmetry(dm)); 9188 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9189 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9190 PetscCall(DMPlexCheckGeometry(dm)); 9191 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9192 PetscCall(DMPlexCheckInterfaceCones(dm)); 9193 PetscFunctionReturn(PETSC_SUCCESS); 9194 } 9195 9196 typedef struct cell_stats { 9197 PetscReal min, max, sum, squaresum; 9198 PetscInt count; 9199 } cell_stats_t; 9200 9201 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9202 { 9203 PetscInt i, N = *len; 9204 9205 for (i = 0; i < N; i++) { 9206 cell_stats_t *A = (cell_stats_t *)a; 9207 cell_stats_t *B = (cell_stats_t *)b; 9208 9209 B->min = PetscMin(A->min, B->min); 9210 B->max = PetscMax(A->max, B->max); 9211 B->sum += A->sum; 9212 B->squaresum += A->squaresum; 9213 B->count += A->count; 9214 } 9215 } 9216 9217 /*@ 9218 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9219 9220 Collective 9221 9222 Input Parameters: 9223 + dm - The `DMPLEX` object 9224 . output - If true, statistics will be displayed on `stdout` 9225 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9226 9227 Level: developer 9228 9229 Notes: 9230 This is mainly intended for debugging/testing purposes. 9231 9232 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9233 9234 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9235 @*/ 9236 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9237 { 9238 DM dmCoarse; 9239 cell_stats_t stats, globalStats; 9240 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9241 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9242 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9243 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9244 PetscMPIInt rank, size; 9245 9246 PetscFunctionBegin; 9247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9248 stats.min = PETSC_MAX_REAL; 9249 stats.max = PETSC_MIN_REAL; 9250 stats.sum = stats.squaresum = 0.; 9251 stats.count = 0; 9252 9253 PetscCallMPI(MPI_Comm_size(comm, &size)); 9254 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9255 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9256 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9257 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9258 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9259 for (c = cStart; c < cEnd; c++) { 9260 PetscInt i; 9261 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9262 9263 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9264 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9265 for (i = 0; i < PetscSqr(cdim); ++i) { 9266 frobJ += J[i] * J[i]; 9267 frobInvJ += invJ[i] * invJ[i]; 9268 } 9269 cond2 = frobJ * frobInvJ; 9270 cond = PetscSqrtReal(cond2); 9271 9272 stats.min = PetscMin(stats.min, cond); 9273 stats.max = PetscMax(stats.max, cond); 9274 stats.sum += cond; 9275 stats.squaresum += cond2; 9276 stats.count++; 9277 if (output && cond > limit) { 9278 PetscSection coordSection; 9279 Vec coordsLocal; 9280 PetscScalar *coords = NULL; 9281 PetscInt Nv, d, clSize, cl, *closure = NULL; 9282 9283 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9284 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9285 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9286 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9287 for (i = 0; i < Nv / cdim; ++i) { 9288 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9289 for (d = 0; d < cdim; ++d) { 9290 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9291 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9292 } 9293 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9294 } 9295 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9296 for (cl = 0; cl < clSize * 2; cl += 2) { 9297 const PetscInt edge = closure[cl]; 9298 9299 if ((edge >= eStart) && (edge < eEnd)) { 9300 PetscReal len; 9301 9302 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9303 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9304 } 9305 } 9306 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9307 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9308 } 9309 } 9310 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9311 9312 if (size > 1) { 9313 PetscMPIInt blockLengths[2] = {4, 1}; 9314 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9315 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9316 MPI_Op statReduce; 9317 9318 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9319 PetscCallMPI(MPI_Type_commit(&statType)); 9320 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9321 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9322 PetscCallMPI(MPI_Op_free(&statReduce)); 9323 PetscCallMPI(MPI_Type_free(&statType)); 9324 } else { 9325 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9326 } 9327 if (rank == 0) { 9328 count = globalStats.count; 9329 min = globalStats.min; 9330 max = globalStats.max; 9331 mean = globalStats.sum / globalStats.count; 9332 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9333 } 9334 9335 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)); 9336 PetscCall(PetscFree2(J, invJ)); 9337 9338 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9339 if (dmCoarse) { 9340 PetscBool isplex; 9341 9342 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9343 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9344 } 9345 PetscFunctionReturn(PETSC_SUCCESS); 9346 } 9347 9348 /*@ 9349 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9350 orthogonal quality below given tolerance. 9351 9352 Collective 9353 9354 Input Parameters: 9355 + dm - The `DMPLEX` object 9356 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9357 - atol - [0, 1] Absolute tolerance for tagging cells. 9358 9359 Output Parameters: 9360 + OrthQual - `Vec` containing orthogonal quality per cell 9361 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9362 9363 Options Database Keys: 9364 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9365 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9366 9367 Level: intermediate 9368 9369 Notes: 9370 Orthogonal quality is given by the following formula: 9371 9372 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9373 9374 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 9375 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9376 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9377 calculating the cosine of the angle between these vectors. 9378 9379 Orthogonal quality ranges from 1 (best) to 0 (worst). 9380 9381 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9382 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9383 9384 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9385 9386 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9387 @*/ 9388 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9389 { 9390 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9391 PetscInt *idx; 9392 PetscScalar *oqVals; 9393 const PetscScalar *cellGeomArr, *faceGeomArr; 9394 PetscReal *ci, *fi, *Ai; 9395 MPI_Comm comm; 9396 Vec cellgeom, facegeom; 9397 DM dmFace, dmCell; 9398 IS glob; 9399 ISLocalToGlobalMapping ltog; 9400 PetscViewer vwr; 9401 9402 PetscFunctionBegin; 9403 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9404 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9405 PetscAssertPointer(OrthQual, 4); 9406 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9407 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9408 PetscCall(DMGetDimension(dm, &nc)); 9409 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9410 { 9411 DMPlexInterpolatedFlag interpFlag; 9412 9413 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9414 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9415 PetscMPIInt rank; 9416 9417 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9418 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9419 } 9420 } 9421 if (OrthQualLabel) { 9422 PetscAssertPointer(OrthQualLabel, 5); 9423 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9424 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9425 } else { 9426 *OrthQualLabel = NULL; 9427 } 9428 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9429 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9430 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9431 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9432 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9433 PetscCall(VecCreate(comm, OrthQual)); 9434 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9435 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9436 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9437 PetscCall(VecSetUp(*OrthQual)); 9438 PetscCall(ISDestroy(&glob)); 9439 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9440 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9441 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9442 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9443 PetscCall(VecGetDM(cellgeom, &dmCell)); 9444 PetscCall(VecGetDM(facegeom, &dmFace)); 9445 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9446 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9447 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9448 PetscInt cellarr[2], *adj = NULL; 9449 PetscScalar *cArr, *fArr; 9450 PetscReal minvalc = 1.0, minvalf = 1.0; 9451 PetscFVCellGeom *cg; 9452 9453 idx[cellIter] = cell - cStart; 9454 cellarr[0] = cell; 9455 /* Make indexing into cellGeom easier */ 9456 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9457 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9458 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9459 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9460 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9461 PetscInt i; 9462 const PetscInt neigh = adj[cellneigh]; 9463 PetscReal normci = 0, normfi = 0, normai = 0; 9464 PetscFVCellGeom *cgneigh; 9465 PetscFVFaceGeom *fg; 9466 9467 /* Don't count ourselves in the neighbor list */ 9468 if (neigh == cell) continue; 9469 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9470 cellarr[1] = neigh; 9471 { 9472 PetscInt numcovpts; 9473 const PetscInt *covpts; 9474 9475 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9476 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9477 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9478 } 9479 9480 /* Compute c_i, f_i and their norms */ 9481 for (i = 0; i < nc; i++) { 9482 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9483 fi[i] = fg->centroid[i] - cg->centroid[i]; 9484 Ai[i] = fg->normal[i]; 9485 normci += PetscPowReal(ci[i], 2); 9486 normfi += PetscPowReal(fi[i], 2); 9487 normai += PetscPowReal(Ai[i], 2); 9488 } 9489 normci = PetscSqrtReal(normci); 9490 normfi = PetscSqrtReal(normfi); 9491 normai = PetscSqrtReal(normai); 9492 9493 /* Normalize and compute for each face-cell-normal pair */ 9494 for (i = 0; i < nc; i++) { 9495 ci[i] = ci[i] / normci; 9496 fi[i] = fi[i] / normfi; 9497 Ai[i] = Ai[i] / normai; 9498 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9499 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9500 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9501 } 9502 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9503 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9504 } 9505 PetscCall(PetscFree(adj)); 9506 PetscCall(PetscFree2(cArr, fArr)); 9507 /* Defer to cell if they're equal */ 9508 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9509 if (OrthQualLabel) { 9510 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9511 } 9512 } 9513 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9514 PetscCall(VecAssemblyBegin(*OrthQual)); 9515 PetscCall(VecAssemblyEnd(*OrthQual)); 9516 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9517 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9518 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9519 if (OrthQualLabel) { 9520 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9521 } 9522 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9523 PetscCall(PetscViewerDestroy(&vwr)); 9524 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9525 PetscFunctionReturn(PETSC_SUCCESS); 9526 } 9527 9528 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9529 * interpolator construction */ 9530 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9531 { 9532 PetscSection section, newSection, gsection; 9533 PetscSF sf; 9534 PetscBool hasConstraints, ghasConstraints; 9535 9536 PetscFunctionBegin; 9537 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9538 PetscAssertPointer(odm, 2); 9539 PetscCall(DMGetLocalSection(dm, §ion)); 9540 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9541 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9542 if (!ghasConstraints) { 9543 PetscCall(PetscObjectReference((PetscObject)dm)); 9544 *odm = dm; 9545 PetscFunctionReturn(PETSC_SUCCESS); 9546 } 9547 PetscCall(DMClone(dm, odm)); 9548 PetscCall(DMCopyFields(dm, *odm)); 9549 PetscCall(DMGetLocalSection(*odm, &newSection)); 9550 PetscCall(DMGetPointSF(*odm, &sf)); 9551 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9552 PetscCall(DMSetGlobalSection(*odm, gsection)); 9553 PetscCall(PetscSectionDestroy(&gsection)); 9554 PetscFunctionReturn(PETSC_SUCCESS); 9555 } 9556 9557 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9558 { 9559 DM dmco, dmfo; 9560 Mat interpo; 9561 Vec rscale; 9562 Vec cglobalo, clocal; 9563 Vec fglobal, fglobalo, flocal; 9564 PetscBool regular; 9565 9566 PetscFunctionBegin; 9567 PetscCall(DMGetFullDM(dmc, &dmco)); 9568 PetscCall(DMGetFullDM(dmf, &dmfo)); 9569 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9570 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9571 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9572 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9573 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9574 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9575 PetscCall(VecSet(cglobalo, 0.)); 9576 PetscCall(VecSet(clocal, 0.)); 9577 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9578 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9579 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9580 PetscCall(VecSet(fglobal, 0.)); 9581 PetscCall(VecSet(fglobalo, 0.)); 9582 PetscCall(VecSet(flocal, 0.)); 9583 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9584 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9585 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9586 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9587 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9588 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9589 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9590 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9591 *shift = fglobal; 9592 PetscCall(VecDestroy(&flocal)); 9593 PetscCall(VecDestroy(&fglobalo)); 9594 PetscCall(VecDestroy(&clocal)); 9595 PetscCall(VecDestroy(&cglobalo)); 9596 PetscCall(VecDestroy(&rscale)); 9597 PetscCall(MatDestroy(&interpo)); 9598 PetscCall(DMDestroy(&dmfo)); 9599 PetscCall(DMDestroy(&dmco)); 9600 PetscFunctionReturn(PETSC_SUCCESS); 9601 } 9602 9603 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9604 { 9605 PetscObject shifto; 9606 Vec shift; 9607 9608 PetscFunctionBegin; 9609 if (!interp) { 9610 Vec rscale; 9611 9612 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9613 PetscCall(VecDestroy(&rscale)); 9614 } else { 9615 PetscCall(PetscObjectReference((PetscObject)interp)); 9616 } 9617 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9618 if (!shifto) { 9619 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9620 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9621 shifto = (PetscObject)shift; 9622 PetscCall(VecDestroy(&shift)); 9623 } 9624 shift = (Vec)shifto; 9625 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9626 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9627 PetscCall(MatDestroy(&interp)); 9628 PetscFunctionReturn(PETSC_SUCCESS); 9629 } 9630 9631 /* Pointwise interpolation 9632 Just code FEM for now 9633 u^f = I u^c 9634 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9635 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9636 I_{ij} = psi^f_i phi^c_j 9637 */ 9638 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9639 { 9640 PetscSection gsc, gsf; 9641 PetscInt m, n; 9642 void *ctx; 9643 DM cdm; 9644 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9645 9646 PetscFunctionBegin; 9647 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9648 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9649 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9650 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9651 9652 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9653 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9654 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9655 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9656 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9657 9658 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9659 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9660 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9661 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9662 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9663 if (scaling) { 9664 /* Use naive scaling */ 9665 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9666 } 9667 PetscFunctionReturn(PETSC_SUCCESS); 9668 } 9669 9670 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9671 { 9672 VecScatter ctx; 9673 9674 PetscFunctionBegin; 9675 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9676 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9677 PetscCall(VecScatterDestroy(&ctx)); 9678 PetscFunctionReturn(PETSC_SUCCESS); 9679 } 9680 9681 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[]) 9682 { 9683 const PetscInt Nc = uOff[1] - uOff[0]; 9684 PetscInt c; 9685 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9686 } 9687 9688 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9689 { 9690 DM dmc; 9691 PetscDS ds; 9692 Vec ones, locmass; 9693 IS cellIS; 9694 PetscFormKey key; 9695 PetscInt depth; 9696 9697 PetscFunctionBegin; 9698 PetscCall(DMClone(dm, &dmc)); 9699 PetscCall(DMCopyDisc(dm, dmc)); 9700 PetscCall(DMGetDS(dmc, &ds)); 9701 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9702 PetscCall(DMCreateGlobalVector(dmc, mass)); 9703 PetscCall(DMGetLocalVector(dmc, &ones)); 9704 PetscCall(DMGetLocalVector(dmc, &locmass)); 9705 PetscCall(DMPlexGetDepth(dmc, &depth)); 9706 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9707 PetscCall(VecSet(locmass, 0.0)); 9708 PetscCall(VecSet(ones, 1.0)); 9709 key.label = NULL; 9710 key.value = 0; 9711 key.field = 0; 9712 key.part = 0; 9713 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9714 PetscCall(ISDestroy(&cellIS)); 9715 PetscCall(VecSet(*mass, 0.0)); 9716 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9717 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9718 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9719 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9720 PetscCall(DMDestroy(&dmc)); 9721 PetscFunctionReturn(PETSC_SUCCESS); 9722 } 9723 9724 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9725 { 9726 PetscSection gsc, gsf; 9727 PetscInt m, n; 9728 void *ctx; 9729 DM cdm; 9730 PetscBool regular; 9731 9732 PetscFunctionBegin; 9733 if (dmFine == dmCoarse) { 9734 DM dmc; 9735 PetscDS ds; 9736 PetscWeakForm wf; 9737 Vec u; 9738 IS cellIS; 9739 PetscFormKey key; 9740 PetscInt depth; 9741 9742 PetscCall(DMClone(dmFine, &dmc)); 9743 PetscCall(DMCopyDisc(dmFine, dmc)); 9744 PetscCall(DMGetDS(dmc, &ds)); 9745 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9746 PetscCall(PetscWeakFormClear(wf)); 9747 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9748 PetscCall(DMCreateMatrix(dmc, mass)); 9749 PetscCall(DMGetLocalVector(dmc, &u)); 9750 PetscCall(DMPlexGetDepth(dmc, &depth)); 9751 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9752 PetscCall(MatZeroEntries(*mass)); 9753 key.label = NULL; 9754 key.value = 0; 9755 key.field = 0; 9756 key.part = 0; 9757 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9758 PetscCall(ISDestroy(&cellIS)); 9759 PetscCall(DMRestoreLocalVector(dmc, &u)); 9760 PetscCall(DMDestroy(&dmc)); 9761 } else { 9762 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9763 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9764 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9765 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9766 9767 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9768 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9769 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9770 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9771 9772 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9773 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9774 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9775 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9776 } 9777 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9778 PetscFunctionReturn(PETSC_SUCCESS); 9779 } 9780 9781 /*@ 9782 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9783 9784 Input Parameter: 9785 . dm - The `DMPLEX` object 9786 9787 Output Parameter: 9788 . regular - The flag 9789 9790 Level: intermediate 9791 9792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9793 @*/ 9794 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9795 { 9796 PetscFunctionBegin; 9797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9798 PetscAssertPointer(regular, 2); 9799 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9800 PetscFunctionReturn(PETSC_SUCCESS); 9801 } 9802 9803 /*@ 9804 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9805 9806 Input Parameters: 9807 + dm - The `DMPLEX` object 9808 - regular - The flag 9809 9810 Level: intermediate 9811 9812 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9813 @*/ 9814 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9815 { 9816 PetscFunctionBegin; 9817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9818 ((DM_Plex *)dm->data)->regularRefinement = regular; 9819 PetscFunctionReturn(PETSC_SUCCESS); 9820 } 9821 9822 /*@ 9823 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9824 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9825 9826 Not Collective 9827 9828 Input Parameter: 9829 . dm - The `DMPLEX` object 9830 9831 Output Parameters: 9832 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9833 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9834 9835 Level: intermediate 9836 9837 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9838 @*/ 9839 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9840 { 9841 DM_Plex *plex = (DM_Plex *)dm->data; 9842 9843 PetscFunctionBegin; 9844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9845 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9846 if (anchorSection) *anchorSection = plex->anchorSection; 9847 if (anchorIS) *anchorIS = plex->anchorIS; 9848 PetscFunctionReturn(PETSC_SUCCESS); 9849 } 9850 9851 /*@ 9852 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9853 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9854 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 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 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9868 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9869 9870 The reference counts of `anchorSection` and `anchorIS` are incremented. 9871 9872 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9873 @*/ 9874 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9875 { 9876 DM_Plex *plex = (DM_Plex *)dm->data; 9877 PetscMPIInt result; 9878 9879 PetscFunctionBegin; 9880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9881 if (anchorSection) { 9882 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9883 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9884 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9885 } 9886 if (anchorIS) { 9887 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9888 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9889 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9890 } 9891 9892 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9893 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9894 plex->anchorSection = anchorSection; 9895 9896 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9897 PetscCall(ISDestroy(&plex->anchorIS)); 9898 plex->anchorIS = anchorIS; 9899 9900 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9901 PetscInt size, a, pStart, pEnd; 9902 const PetscInt *anchors; 9903 9904 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9905 PetscCall(ISGetLocalSize(anchorIS, &size)); 9906 PetscCall(ISGetIndices(anchorIS, &anchors)); 9907 for (a = 0; a < size; a++) { 9908 PetscInt p; 9909 9910 p = anchors[a]; 9911 if (p >= pStart && p < pEnd) { 9912 PetscInt dof; 9913 9914 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9915 if (dof) { 9916 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9917 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9918 } 9919 } 9920 } 9921 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9922 } 9923 /* reset the generic constraints */ 9924 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9925 PetscFunctionReturn(PETSC_SUCCESS); 9926 } 9927 9928 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9929 { 9930 PetscSection anchorSection; 9931 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9932 9933 PetscFunctionBegin; 9934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9935 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9936 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9937 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9938 if (numFields) { 9939 PetscInt f; 9940 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9941 9942 for (f = 0; f < numFields; f++) { 9943 PetscInt numComp; 9944 9945 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9946 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9947 } 9948 } 9949 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9950 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9951 pStart = PetscMax(pStart, sStart); 9952 pEnd = PetscMin(pEnd, sEnd); 9953 pEnd = PetscMax(pStart, pEnd); 9954 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9955 for (p = pStart; p < pEnd; p++) { 9956 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9957 if (dof) { 9958 PetscCall(PetscSectionGetDof(section, p, &dof)); 9959 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9960 for (f = 0; f < numFields; f++) { 9961 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9962 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9963 } 9964 } 9965 } 9966 PetscCall(PetscSectionSetUp(*cSec)); 9967 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9968 PetscFunctionReturn(PETSC_SUCCESS); 9969 } 9970 9971 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9972 { 9973 PetscSection aSec; 9974 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9975 const PetscInt *anchors; 9976 PetscInt numFields, f; 9977 IS aIS; 9978 MatType mtype; 9979 PetscBool iscuda, iskokkos; 9980 9981 PetscFunctionBegin; 9982 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9983 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9984 PetscCall(PetscSectionGetStorageSize(section, &n)); 9985 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9986 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9987 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9988 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9989 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9990 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9991 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9992 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9993 else mtype = MATSEQAIJ; 9994 PetscCall(MatSetType(*cMat, mtype)); 9995 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9996 PetscCall(ISGetIndices(aIS, &anchors)); 9997 /* cSec will be a subset of aSec and section */ 9998 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9999 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 10000 PetscCall(PetscMalloc1(m + 1, &i)); 10001 i[0] = 0; 10002 PetscCall(PetscSectionGetNumFields(section, &numFields)); 10003 for (p = pStart; p < pEnd; p++) { 10004 PetscInt rDof, rOff, r; 10005 10006 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10007 if (!rDof) continue; 10008 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10009 if (numFields) { 10010 for (f = 0; f < numFields; f++) { 10011 annz = 0; 10012 for (r = 0; r < rDof; r++) { 10013 a = anchors[rOff + r]; 10014 if (a < sStart || a >= sEnd) continue; 10015 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10016 annz += aDof; 10017 } 10018 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10019 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 10020 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10021 } 10022 } else { 10023 annz = 0; 10024 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10025 for (q = 0; q < dof; q++) { 10026 a = anchors[rOff + q]; 10027 if (a < sStart || a >= sEnd) continue; 10028 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10029 annz += aDof; 10030 } 10031 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10032 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 10033 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 10034 } 10035 } 10036 nnz = i[m]; 10037 PetscCall(PetscMalloc1(nnz, &j)); 10038 offset = 0; 10039 for (p = pStart; p < pEnd; p++) { 10040 if (numFields) { 10041 for (f = 0; f < numFields; f++) { 10042 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 10043 for (q = 0; q < dof; q++) { 10044 PetscInt rDof, rOff, r; 10045 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10046 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10047 for (r = 0; r < rDof; r++) { 10048 PetscInt s; 10049 10050 a = anchors[rOff + r]; 10051 if (a < sStart || a >= sEnd) continue; 10052 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10053 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10054 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10055 } 10056 } 10057 } 10058 } else { 10059 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10060 for (q = 0; q < dof; q++) { 10061 PetscInt rDof, rOff, r; 10062 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10063 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10064 for (r = 0; r < rDof; r++) { 10065 PetscInt s; 10066 10067 a = anchors[rOff + r]; 10068 if (a < sStart || a >= sEnd) continue; 10069 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10070 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10071 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10072 } 10073 } 10074 } 10075 } 10076 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10077 PetscCall(PetscFree(i)); 10078 PetscCall(PetscFree(j)); 10079 PetscCall(ISRestoreIndices(aIS, &anchors)); 10080 PetscFunctionReturn(PETSC_SUCCESS); 10081 } 10082 10083 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10084 { 10085 DM_Plex *plex = (DM_Plex *)dm->data; 10086 PetscSection anchorSection, section, cSec; 10087 Mat cMat; 10088 10089 PetscFunctionBegin; 10090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10091 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10092 if (anchorSection) { 10093 PetscInt Nf; 10094 10095 PetscCall(DMGetLocalSection(dm, §ion)); 10096 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10097 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10098 PetscCall(DMGetNumFields(dm, &Nf)); 10099 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10100 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10101 PetscCall(PetscSectionDestroy(&cSec)); 10102 PetscCall(MatDestroy(&cMat)); 10103 } 10104 PetscFunctionReturn(PETSC_SUCCESS); 10105 } 10106 10107 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10108 { 10109 IS subis; 10110 PetscSection section, subsection; 10111 10112 PetscFunctionBegin; 10113 PetscCall(DMGetLocalSection(dm, §ion)); 10114 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10115 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10116 /* Create subdomain */ 10117 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10118 /* Create submodel */ 10119 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10120 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10121 PetscCall(DMSetLocalSection(*subdm, subsection)); 10122 PetscCall(PetscSectionDestroy(&subsection)); 10123 PetscCall(DMCopyDisc(dm, *subdm)); 10124 /* Create map from submodel to global model */ 10125 if (is) { 10126 PetscSection sectionGlobal, subsectionGlobal; 10127 IS spIS; 10128 const PetscInt *spmap; 10129 PetscInt *subIndices; 10130 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10131 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10132 10133 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10134 PetscCall(ISGetIndices(spIS, &spmap)); 10135 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10136 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10137 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10138 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10139 for (p = pStart; p < pEnd; ++p) { 10140 PetscInt gdof, pSubSize = 0; 10141 10142 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10143 if (gdof > 0) { 10144 for (f = 0; f < Nf; ++f) { 10145 PetscInt fdof, fcdof; 10146 10147 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10148 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10149 pSubSize += fdof - fcdof; 10150 } 10151 subSize += pSubSize; 10152 if (pSubSize) { 10153 if (bs < 0) { 10154 bs = pSubSize; 10155 } else if (bs != pSubSize) { 10156 /* Layout does not admit a pointwise block size */ 10157 bs = 1; 10158 } 10159 } 10160 } 10161 } 10162 /* Must have same blocksize on all procs (some might have no points) */ 10163 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10164 bsLocal[1] = bs; 10165 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10166 if (bsMinMax[0] != bsMinMax[1]) { 10167 bs = 1; 10168 } else { 10169 bs = bsMinMax[0]; 10170 } 10171 PetscCall(PetscMalloc1(subSize, &subIndices)); 10172 for (p = pStart; p < pEnd; ++p) { 10173 PetscInt gdof, goff; 10174 10175 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10176 if (gdof > 0) { 10177 const PetscInt point = spmap[p]; 10178 10179 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10180 for (f = 0; f < Nf; ++f) { 10181 PetscInt fdof, fcdof, fc, f2, poff = 0; 10182 10183 /* Can get rid of this loop by storing field information in the global section */ 10184 for (f2 = 0; f2 < f; ++f2) { 10185 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10186 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10187 poff += fdof - fcdof; 10188 } 10189 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10190 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10191 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10192 } 10193 } 10194 } 10195 PetscCall(ISRestoreIndices(spIS, &spmap)); 10196 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10197 if (bs > 1) { 10198 /* We need to check that the block size does not come from non-contiguous fields */ 10199 PetscInt i, j, set = 1; 10200 for (i = 0; i < subSize; i += bs) { 10201 for (j = 0; j < bs; ++j) { 10202 if (subIndices[i + j] != subIndices[i] + j) { 10203 set = 0; 10204 break; 10205 } 10206 } 10207 } 10208 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10209 } 10210 /* Attach nullspace */ 10211 for (f = 0; f < Nf; ++f) { 10212 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10213 if ((*subdm)->nullspaceConstructors[f]) break; 10214 } 10215 if (f < Nf) { 10216 MatNullSpace nullSpace; 10217 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10218 10219 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10220 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10221 } 10222 } 10223 PetscFunctionReturn(PETSC_SUCCESS); 10224 } 10225 10226 /*@ 10227 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10228 10229 Input Parameters: 10230 + dm - The `DM` 10231 - dummy - unused argument 10232 10233 Options Database Key: 10234 . -dm_plex_monitor_throughput - Activate the monitor 10235 10236 Level: developer 10237 10238 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10239 @*/ 10240 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10241 { 10242 PetscLogHandler default_handler; 10243 10244 PetscFunctionBegin; 10245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10246 PetscCall(PetscLogGetDefaultHandler(&default_handler)); 10247 if (default_handler) { 10248 PetscLogEvent event; 10249 PetscEventPerfInfo eventInfo; 10250 PetscReal cellRate, flopRate; 10251 PetscInt cStart, cEnd, Nf, N; 10252 const char *name; 10253 10254 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10255 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10256 PetscCall(DMGetNumFields(dm, &Nf)); 10257 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10258 PetscCall(PetscLogEventGetPerfInfo(PETSC_DEFAULT, event, &eventInfo)); 10259 N = (cEnd - cStart) * Nf * eventInfo.count; 10260 flopRate = eventInfo.flops / eventInfo.time; 10261 cellRate = N / eventInfo.time; 10262 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))); 10263 } else { 10264 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."); 10265 } 10266 PetscFunctionReturn(PETSC_SUCCESS); 10267 } 10268