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