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