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; 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(0); 45 } 46 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 47 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 48 PetscFunctionReturn(0); 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(0); 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(0); 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(0); 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(0); 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(0); 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 *coords, *array; 253 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 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(VecGetArrayRead(coordinates, &coords)); 278 for (c = 0; c < N; c += dim) { 279 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 280 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 281 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 282 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 283 } 284 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 285 PetscCall(PetscDrawClear(draw)); 286 287 /* Could implement something like DMDASelectFields() */ 288 for (f = 0; f < Nf; ++f) { 289 DM fdm = dm; 290 Vec fv = v; 291 IS fis; 292 char prefix[PETSC_MAX_PATH_LEN]; 293 const char *fname; 294 295 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 296 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 297 298 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 299 else prefix[0] = '\0'; 300 if (Nf > 1) { 301 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 302 PetscCall(VecGetSubVector(v, fis, &fv)); 303 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 304 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 305 } 306 for (comp = 0; comp < Nc; ++comp, ++w) { 307 PetscInt nmax = 2; 308 309 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 310 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 311 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 312 PetscCall(PetscDrawSetTitle(draw, title)); 313 314 /* TODO Get max and min only for this component */ 315 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 316 if (!flg) { 317 PetscCall(VecMin(fv, NULL, &vbound[0])); 318 PetscCall(VecMax(fv, NULL, &vbound[1])); 319 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 320 } 321 PetscCall(PetscDrawGetPopup(draw, &popup)); 322 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 323 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 324 325 PetscCall(VecGetArrayRead(fv, &array)); 326 for (c = cStart; c < cEnd; ++c) { 327 PetscScalar *coords = NULL, *a = NULL; 328 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 329 330 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 331 if (a) { 332 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 333 color[1] = color[2] = color[3] = color[0]; 334 } else { 335 PetscScalar *vals = NULL; 336 PetscInt numVals, va; 337 338 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 339 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); 340 switch (numVals / Nc) { 341 case 3: /* P1 Triangle */ 342 case 4: /* P1 Quadrangle */ 343 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 344 break; 345 case 6: /* P2 Triangle */ 346 case 8: /* P2 Quadrangle */ 347 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 348 break; 349 default: 350 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 351 } 352 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 353 } 354 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 switch (numCoords) { 356 case 6: 357 case 12: /* Localized triangle */ 358 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])); 359 break; 360 case 8: 361 case 16: /* Localized quadrilateral */ 362 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])); 363 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])); 364 break; 365 default: 366 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 367 } 368 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 369 } 370 PetscCall(VecRestoreArrayRead(fv, &array)); 371 PetscCall(PetscDrawFlush(draw)); 372 PetscCall(PetscDrawPause(draw)); 373 PetscCall(PetscDrawSave(draw)); 374 } 375 if (Nf > 1) { 376 PetscCall(VecRestoreSubVector(v, fis, &fv)); 377 PetscCall(ISDestroy(&fis)); 378 PetscCall(DMDestroy(&fdm)); 379 } 380 } 381 PetscFunctionReturn(0); 382 } 383 384 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 385 { 386 DM dm; 387 PetscDraw draw; 388 PetscInt dim; 389 PetscBool isnull; 390 391 PetscFunctionBegin; 392 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 393 PetscCall(PetscDrawIsNull(draw, &isnull)); 394 if (isnull) PetscFunctionReturn(0); 395 396 PetscCall(VecGetDM(v, &dm)); 397 PetscCall(DMGetCoordinateDim(dm, &dim)); 398 switch (dim) { 399 case 1: 400 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 401 break; 402 case 2: 403 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 404 break; 405 default: 406 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 407 } 408 PetscFunctionReturn(0); 409 } 410 411 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 412 { 413 DM dm; 414 Vec locv; 415 const char *name; 416 PetscSection section; 417 PetscInt pStart, pEnd; 418 PetscInt numFields; 419 PetscViewerVTKFieldType ft; 420 421 PetscFunctionBegin; 422 PetscCall(VecGetDM(v, &dm)); 423 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 424 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 425 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 426 PetscCall(VecCopy(v, locv)); 427 PetscCall(DMGetLocalSection(dm, §ion)); 428 PetscCall(PetscSectionGetNumFields(section, &numFields)); 429 if (!numFields) { 430 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 431 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 432 } else { 433 PetscInt f; 434 435 for (f = 0; f < numFields; f++) { 436 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 437 if (ft == PETSC_VTK_INVALID) continue; 438 PetscCall(PetscObjectReference((PetscObject)locv)); 439 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 440 } 441 PetscCall(VecDestroy(&locv)); 442 } 443 PetscFunctionReturn(0); 444 } 445 446 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 447 { 448 DM dm; 449 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 450 451 PetscFunctionBegin; 452 PetscCall(VecGetDM(v, &dm)); 453 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 454 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 455 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 456 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 457 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 458 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 459 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 460 PetscInt i, numFields; 461 PetscObject fe; 462 PetscBool fem = PETSC_FALSE; 463 Vec locv = v; 464 const char *name; 465 PetscInt step; 466 PetscReal time; 467 468 PetscCall(DMGetNumFields(dm, &numFields)); 469 for (i = 0; i < numFields; i++) { 470 PetscCall(DMGetField(dm, i, NULL, &fe)); 471 if (fe->classid == PETSCFE_CLASSID) { 472 fem = PETSC_TRUE; 473 break; 474 } 475 } 476 if (fem) { 477 PetscObject isZero; 478 479 PetscCall(DMGetLocalVector(dm, &locv)); 480 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 481 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 482 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 483 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 484 PetscCall(VecCopy(v, locv)); 485 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 486 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 487 } 488 if (isvtk) { 489 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 490 } else if (ishdf5) { 491 #if defined(PETSC_HAVE_HDF5) 492 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 493 #else 494 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 495 #endif 496 } else if (isdraw) { 497 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 498 } else if (isglvis) { 499 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 500 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 501 PetscCall(VecView_GLVis(locv, viewer)); 502 } else if (iscgns) { 503 #if defined(PETSC_HAVE_CGNS) 504 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 505 #else 506 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 507 #endif 508 } 509 if (fem) { 510 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 511 PetscCall(DMRestoreLocalVector(dm, &locv)); 512 } 513 } else { 514 PetscBool isseq; 515 516 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 517 if (isseq) PetscCall(VecView_Seq(v, viewer)); 518 else PetscCall(VecView_MPI(v, viewer)); 519 } 520 PetscFunctionReturn(0); 521 } 522 523 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 524 { 525 DM dm; 526 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 527 528 PetscFunctionBegin; 529 PetscCall(VecGetDM(v, &dm)); 530 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 532 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 535 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 536 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 537 if (isvtk || isdraw || isglvis || iscgns) { 538 Vec locv; 539 PetscObject isZero; 540 const char *name; 541 542 PetscCall(DMGetLocalVector(dm, &locv)); 543 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 544 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 545 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 546 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 547 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 548 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 549 PetscCall(VecView_Plex_Local(locv, viewer)); 550 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 551 PetscCall(DMRestoreLocalVector(dm, &locv)); 552 } else if (ishdf5) { 553 #if defined(PETSC_HAVE_HDF5) 554 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 555 #else 556 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 557 #endif 558 } else if (isexodusii) { 559 #if defined(PETSC_HAVE_EXODUSII) 560 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 561 #else 562 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 563 #endif 564 } else { 565 PetscBool isseq; 566 567 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 568 if (isseq) PetscCall(VecView_Seq(v, viewer)); 569 else PetscCall(VecView_MPI(v, viewer)); 570 } 571 PetscFunctionReturn(0); 572 } 573 574 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 575 { 576 DM dm; 577 MPI_Comm comm; 578 PetscViewerFormat format; 579 Vec v; 580 PetscBool isvtk, ishdf5; 581 582 PetscFunctionBegin; 583 PetscCall(VecGetDM(originalv, &dm)); 584 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 585 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 586 PetscCall(PetscViewerGetFormat(viewer, &format)); 587 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 588 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 589 if (format == PETSC_VIEWER_NATIVE) { 590 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 591 /* this need a better fix */ 592 if (dm->useNatural) { 593 if (dm->sfNatural) { 594 const char *vecname; 595 PetscInt n, nroots; 596 597 PetscCall(VecGetLocalSize(originalv, &n)); 598 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 599 if (n == nroots) { 600 PetscCall(DMGetGlobalVector(dm, &v)); 601 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 602 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 603 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 604 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 605 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 606 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 607 } else v = originalv; 608 } else v = originalv; 609 610 if (ishdf5) { 611 #if defined(PETSC_HAVE_HDF5) 612 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 613 #else 614 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 615 #endif 616 } else if (isvtk) { 617 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 618 } else { 619 PetscBool isseq; 620 621 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 622 if (isseq) PetscCall(VecView_Seq(v, viewer)); 623 else PetscCall(VecView_MPI(v, viewer)); 624 } 625 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 626 PetscFunctionReturn(0); 627 } 628 629 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool ishdf5; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 638 if (ishdf5) { 639 DM dmBC; 640 Vec gv; 641 const char *name; 642 643 PetscCall(DMGetOutputDM(dm, &dmBC)); 644 PetscCall(DMGetGlobalVector(dmBC, &gv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 647 PetscCall(VecLoad_Default(gv, viewer)); 648 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 649 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 650 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 651 } else PetscCall(VecLoad_Default(v, viewer)); 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 656 { 657 DM dm; 658 PetscBool ishdf5, isexodusii; 659 660 PetscFunctionBegin; 661 PetscCall(VecGetDM(v, &dm)); 662 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 663 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 664 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 665 if (ishdf5) { 666 #if defined(PETSC_HAVE_HDF5) 667 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 668 #else 669 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 670 #endif 671 } else if (isexodusii) { 672 #if defined(PETSC_HAVE_EXODUSII) 673 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 674 #else 675 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 676 #endif 677 } else PetscCall(VecLoad_Default(v, viewer)); 678 PetscFunctionReturn(0); 679 } 680 681 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 682 { 683 DM dm; 684 PetscViewerFormat format; 685 PetscBool ishdf5; 686 687 PetscFunctionBegin; 688 PetscCall(VecGetDM(originalv, &dm)); 689 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 690 PetscCall(PetscViewerGetFormat(viewer, &format)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 if (dm->useNatural) { 694 if (dm->sfNatural) { 695 if (ishdf5) { 696 #if defined(PETSC_HAVE_HDF5) 697 Vec v; 698 const char *vecname; 699 700 PetscCall(DMGetGlobalVector(dm, &v)); 701 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 702 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 703 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 704 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 705 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 706 PetscCall(DMRestoreGlobalVector(dm, &v)); 707 #else 708 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 709 #endif 710 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 711 } 712 } else PetscCall(VecLoad_Default(originalv, viewer)); 713 } 714 PetscFunctionReturn(0); 715 } 716 717 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 718 { 719 PetscSection coordSection; 720 Vec coordinates; 721 DMLabel depthLabel, celltypeLabel; 722 const char *name[4]; 723 const PetscScalar *a; 724 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 725 726 PetscFunctionBegin; 727 PetscCall(DMGetDimension(dm, &dim)); 728 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 729 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 730 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 731 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 732 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 733 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 734 PetscCall(VecGetArrayRead(coordinates, &a)); 735 name[0] = "vertex"; 736 name[1] = "edge"; 737 name[dim - 1] = "face"; 738 name[dim] = "cell"; 739 for (c = cStart; c < cEnd; ++c) { 740 PetscInt *closure = NULL; 741 PetscInt closureSize, cl, ct; 742 743 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 744 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 745 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 746 PetscCall(PetscViewerASCIIPushTab(viewer)); 747 for (cl = 0; cl < closureSize * 2; cl += 2) { 748 PetscInt point = closure[cl], depth, dof, off, d, p; 749 750 if ((point < pStart) || (point >= pEnd)) continue; 751 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 752 if (!dof) continue; 753 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 754 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 755 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 756 for (p = 0; p < dof / dim; ++p) { 757 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 758 for (d = 0; d < dim; ++d) { 759 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 760 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 761 } 762 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 763 } 764 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 765 } 766 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 767 PetscCall(PetscViewerASCIIPopTab(viewer)); 768 } 769 PetscCall(VecRestoreArrayRead(coordinates, &a)); 770 PetscFunctionReturn(0); 771 } 772 773 typedef enum { 774 CS_CARTESIAN, 775 CS_POLAR, 776 CS_CYLINDRICAL, 777 CS_SPHERICAL 778 } CoordSystem; 779 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 780 781 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 782 { 783 PetscInt i; 784 785 PetscFunctionBegin; 786 if (dim > 3) { 787 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 788 } else { 789 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 790 791 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 792 switch (cs) { 793 case CS_CARTESIAN: 794 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 795 break; 796 case CS_POLAR: 797 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 798 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 799 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 800 break; 801 case CS_CYLINDRICAL: 802 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 803 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 804 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 805 trcoords[2] = coords[2]; 806 break; 807 case CS_SPHERICAL: 808 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 809 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 810 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 811 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 812 break; 813 } 814 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 815 } 816 PetscFunctionReturn(0); 817 } 818 819 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 820 { 821 DM_Plex *mesh = (DM_Plex *)dm->data; 822 DM cdm, cdmCell; 823 PetscSection coordSection, coordSectionCell; 824 Vec coordinates, coordinatesCell; 825 PetscViewerFormat format; 826 827 PetscFunctionBegin; 828 PetscCall(DMGetCoordinateDM(dm, &cdm)); 829 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 830 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 831 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 832 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 833 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 834 PetscCall(PetscViewerGetFormat(viewer, &format)); 835 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 836 const char *name; 837 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 838 PetscInt pStart, pEnd, p, numLabels, l; 839 PetscMPIInt rank, size; 840 841 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 842 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 843 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 844 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 845 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 846 PetscCall(DMGetDimension(dm, &dim)); 847 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 848 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 849 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 850 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 851 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 852 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 853 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 854 for (p = pStart; p < pEnd; ++p) { 855 PetscInt dof, off, s; 856 857 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 858 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 859 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 860 } 861 PetscCall(PetscViewerFlush(viewer)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off, c; 866 867 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 869 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])); 870 } 871 PetscCall(PetscViewerFlush(viewer)); 872 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 873 if (coordSection && coordinates) { 874 CoordSystem cs = CS_CARTESIAN; 875 const PetscScalar *array, *arrayCell = NULL; 876 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 877 PetscMPIInt rank; 878 const char *name; 879 880 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 881 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 882 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 883 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 884 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 885 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 886 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 887 pStart = PetscMin(pvStart, pcStart); 888 pEnd = PetscMax(pvEnd, pcEnd); 889 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 890 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 891 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 892 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 893 894 PetscCall(VecGetArrayRead(coordinates, &array)); 895 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 896 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 897 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 898 for (p = pStart; p < pEnd; ++p) { 899 PetscInt dof, off; 900 901 if (p >= pvStart && p < pvEnd) { 902 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 903 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 904 if (dof) { 905 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 906 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 907 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 908 } 909 } 910 if (cdmCell && p >= pcStart && p < pcEnd) { 911 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 912 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 913 if (dof) { 914 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 915 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 916 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 917 } 918 } 919 } 920 PetscCall(PetscViewerFlush(viewer)); 921 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 922 PetscCall(VecRestoreArrayRead(coordinates, &array)); 923 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 924 } 925 PetscCall(DMGetNumLabels(dm, &numLabels)); 926 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 927 for (l = 0; l < numLabels; ++l) { 928 DMLabel label; 929 PetscBool isdepth; 930 const char *name; 931 932 PetscCall(DMGetLabelName(dm, l, &name)); 933 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 934 if (isdepth) continue; 935 PetscCall(DMGetLabel(dm, name, &label)); 936 PetscCall(DMLabelView(label, viewer)); 937 } 938 if (size > 1) { 939 PetscSF sf; 940 941 PetscCall(DMGetPointSF(dm, &sf)); 942 PetscCall(PetscSFView(sf, viewer)); 943 } 944 PetscCall(PetscViewerFlush(viewer)); 945 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 946 const char *name, *color; 947 const char *defcolors[3] = {"gray", "orange", "green"}; 948 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 949 char lname[PETSC_MAX_PATH_LEN]; 950 PetscReal scale = 2.0; 951 PetscReal tikzscale = 1.0; 952 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 953 double tcoords[3]; 954 PetscScalar *coords; 955 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 956 PetscMPIInt rank, size; 957 char **names, **colors, **lcolors; 958 PetscBool flg, lflg; 959 PetscBT wp = NULL; 960 PetscInt pEnd, pStart; 961 962 PetscCall(DMGetDimension(dm, &dim)); 963 PetscCall(DMPlexGetDepth(dm, &depth)); 964 PetscCall(DMGetNumLabels(dm, &numLabels)); 965 numLabels = PetscMax(numLabels, 10); 966 numColors = 10; 967 numLColors = 10; 968 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 969 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 970 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 971 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 972 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 973 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 974 n = 4; 975 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 976 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 977 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &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(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 980 if (!useLabels) numLabels = 0; 981 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 982 if (!useColors) { 983 numColors = 3; 984 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 985 } 986 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 987 if (!useColors) { 988 numLColors = 4; 989 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 990 } 991 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 992 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 993 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 994 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 995 if (depth < dim) plotEdges = PETSC_FALSE; 996 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 997 998 /* filter points with labelvalue != labeldefaultvalue */ 999 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1000 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1001 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1002 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1003 if (lflg) { 1004 DMLabel lbl; 1005 1006 PetscCall(DMGetLabel(dm, lname, &lbl)); 1007 if (lbl) { 1008 PetscInt val, defval; 1009 1010 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1011 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1012 for (c = pStart; c < pEnd; c++) { 1013 PetscInt *closure = NULL; 1014 PetscInt closureSize; 1015 1016 PetscCall(DMLabelGetValue(lbl, c, &val)); 1017 if (val == defval) continue; 1018 1019 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1020 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1021 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1022 } 1023 } 1024 } 1025 1026 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1027 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1028 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1029 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1030 \\documentclass[tikz]{standalone}\n\n\ 1031 \\usepackage{pgflibraryshapes}\n\ 1032 \\usetikzlibrary{backgrounds}\n\ 1033 \\usetikzlibrary{arrows}\n\ 1034 \\begin{document}\n")); 1035 if (size > 1) { 1036 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1037 for (p = 0; p < size; ++p) { 1038 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1039 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1040 } 1041 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1042 } 1043 if (drawHasse) { 1044 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1045 1046 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1047 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1048 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1049 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1050 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1058 } 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1060 1061 /* Plot vertices */ 1062 PetscCall(VecGetArray(coordinates, &coords)); 1063 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1064 for (v = vStart; v < vEnd; ++v) { 1065 PetscInt off, dof, d; 1066 PetscBool isLabeled = PETSC_FALSE; 1067 1068 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1069 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1070 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1071 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1072 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1073 for (d = 0; d < dof; ++d) { 1074 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1075 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1076 } 1077 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1078 if (dim == 3) { 1079 PetscReal tmp = tcoords[1]; 1080 tcoords[1] = tcoords[2]; 1081 tcoords[2] = -tmp; 1082 } 1083 for (d = 0; d < dof; ++d) { 1084 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1085 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1086 } 1087 if (drawHasse) color = colors[0 % numColors]; 1088 else color = colors[rank % numColors]; 1089 for (l = 0; l < numLabels; ++l) { 1090 PetscInt val; 1091 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1092 if (val >= 0) { 1093 color = lcolors[l % numLColors]; 1094 isLabeled = PETSC_TRUE; 1095 break; 1096 } 1097 } 1098 if (drawNumbers[0]) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1100 } else if (drawColors[0]) { 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1102 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1103 } 1104 PetscCall(VecRestoreArray(coordinates, &coords)); 1105 PetscCall(PetscViewerFlush(viewer)); 1106 /* Plot edges */ 1107 if (plotEdges) { 1108 PetscCall(VecGetArray(coordinates, &coords)); 1109 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1110 for (e = eStart; e < eEnd; ++e) { 1111 const PetscInt *cone; 1112 PetscInt coneSize, offA, offB, dof, d; 1113 1114 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1115 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1116 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1117 PetscCall(DMPlexGetCone(dm, e, &cone)); 1118 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1119 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1120 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1121 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1122 for (d = 0; d < dof; ++d) { 1123 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1124 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1125 } 1126 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1127 if (dim == 3) { 1128 PetscReal tmp = tcoords[1]; 1129 tcoords[1] = tcoords[2]; 1130 tcoords[2] = -tmp; 1131 } 1132 for (d = 0; d < dof; ++d) { 1133 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1134 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1135 } 1136 if (drawHasse) color = colors[1 % numColors]; 1137 else color = colors[rank % numColors]; 1138 for (l = 0; l < numLabels; ++l) { 1139 PetscInt val; 1140 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1141 if (val >= 0) { 1142 color = lcolors[l % numLColors]; 1143 break; 1144 } 1145 } 1146 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1147 } 1148 PetscCall(VecRestoreArray(coordinates, &coords)); 1149 PetscCall(PetscViewerFlush(viewer)); 1150 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1151 } 1152 /* Plot cells */ 1153 if (dim == 3 || !drawNumbers[1]) { 1154 for (e = eStart; e < eEnd; ++e) { 1155 const PetscInt *cone; 1156 1157 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1158 color = colors[rank % numColors]; 1159 for (l = 0; l < numLabels; ++l) { 1160 PetscInt val; 1161 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1162 if (val >= 0) { 1163 color = lcolors[l % numLColors]; 1164 break; 1165 } 1166 } 1167 PetscCall(DMPlexGetCone(dm, e, &cone)); 1168 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1169 } 1170 } else { 1171 DMPolytopeType ct; 1172 1173 /* Drawing a 2D polygon */ 1174 for (c = cStart; c < cEnd; ++c) { 1175 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1176 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1177 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1178 const PetscInt *cone; 1179 PetscInt coneSize, e; 1180 1181 PetscCall(DMPlexGetCone(dm, c, &cone)); 1182 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1183 for (e = 0; e < coneSize; ++e) { 1184 const PetscInt *econe; 1185 1186 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1187 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)); 1188 } 1189 } else { 1190 PetscInt *closure = NULL; 1191 PetscInt closureSize, Nv = 0, v; 1192 1193 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1194 for (p = 0; p < closureSize * 2; p += 2) { 1195 const PetscInt point = closure[p]; 1196 1197 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1198 } 1199 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1200 for (v = 0; v <= Nv; ++v) { 1201 const PetscInt vertex = closure[v % Nv]; 1202 1203 if (v > 0) { 1204 if (plotEdges) { 1205 const PetscInt *edge; 1206 PetscInt endpoints[2], ne; 1207 1208 endpoints[0] = closure[v - 1]; 1209 endpoints[1] = vertex; 1210 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1211 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1212 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1213 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1214 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1215 } 1216 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1217 } 1218 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1219 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1220 } 1221 } 1222 } 1223 for (c = cStart; c < cEnd; ++c) { 1224 double ccoords[3] = {0.0, 0.0, 0.0}; 1225 PetscBool isLabeled = PETSC_FALSE; 1226 PetscScalar *cellCoords = NULL; 1227 const PetscScalar *array; 1228 PetscInt numCoords, cdim, d; 1229 PetscBool isDG; 1230 1231 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1232 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1233 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1234 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1235 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1236 for (p = 0; p < numCoords / cdim; ++p) { 1237 for (d = 0; d < cdim; ++d) { 1238 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1239 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1240 } 1241 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1242 if (cdim == 3) { 1243 PetscReal tmp = tcoords[1]; 1244 tcoords[1] = tcoords[2]; 1245 tcoords[2] = -tmp; 1246 } 1247 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1248 } 1249 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1250 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1251 for (d = 0; d < cdim; ++d) { 1252 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1253 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1254 } 1255 if (drawHasse) color = colors[depth % numColors]; 1256 else color = colors[rank % numColors]; 1257 for (l = 0; l < numLabels; ++l) { 1258 PetscInt val; 1259 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1260 if (val >= 0) { 1261 color = lcolors[l % numLColors]; 1262 isLabeled = PETSC_TRUE; 1263 break; 1264 } 1265 } 1266 if (drawNumbers[dim]) { 1267 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1268 } else if (drawColors[dim]) { 1269 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1270 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1271 } 1272 if (drawHasse) { 1273 color = colors[depth % numColors]; 1274 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1275 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1278 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1279 1280 color = colors[1 % numColors]; 1281 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1282 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1283 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1284 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1286 1287 color = colors[0 % numColors]; 1288 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1289 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1291 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1293 1294 for (p = pStart; p < pEnd; ++p) { 1295 const PetscInt *cone; 1296 PetscInt coneSize, cp; 1297 1298 PetscCall(DMPlexGetCone(dm, p, &cone)); 1299 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1300 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1301 } 1302 } 1303 PetscCall(PetscViewerFlush(viewer)); 1304 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1305 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1306 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1307 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1308 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1309 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1310 PetscCall(PetscFree3(names, colors, lcolors)); 1311 PetscCall(PetscBTDestroy(&wp)); 1312 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1313 Vec cown, acown; 1314 VecScatter sct; 1315 ISLocalToGlobalMapping g2l; 1316 IS gid, acis; 1317 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1318 MPI_Group ggroup, ngroup; 1319 PetscScalar *array, nid; 1320 const PetscInt *idxs; 1321 PetscInt *idxs2, *start, *adjacency, *work; 1322 PetscInt64 lm[3], gm[3]; 1323 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1324 PetscMPIInt d1, d2, rank; 1325 1326 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1327 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1328 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1329 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1330 #endif 1331 if (ncomm != MPI_COMM_NULL) { 1332 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1333 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1334 d1 = 0; 1335 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1336 nid = d2; 1337 PetscCallMPI(MPI_Group_free(&ggroup)); 1338 PetscCallMPI(MPI_Group_free(&ngroup)); 1339 PetscCallMPI(MPI_Comm_free(&ncomm)); 1340 } else nid = 0.0; 1341 1342 /* Get connectivity */ 1343 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1344 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1345 1346 /* filter overlapped local cells */ 1347 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1348 PetscCall(ISGetIndices(gid, &idxs)); 1349 PetscCall(ISGetLocalSize(gid, &cum)); 1350 PetscCall(PetscMalloc1(cum, &idxs2)); 1351 for (c = cStart, cum = 0; c < cEnd; c++) { 1352 if (idxs[c - cStart] < 0) continue; 1353 idxs2[cum++] = idxs[c - cStart]; 1354 } 1355 PetscCall(ISRestoreIndices(gid, &idxs)); 1356 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1357 PetscCall(ISDestroy(&gid)); 1358 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1359 1360 /* support for node-aware cell locality */ 1361 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1362 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1363 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1364 PetscCall(VecGetArray(cown, &array)); 1365 for (c = 0; c < numVertices; c++) array[c] = nid; 1366 PetscCall(VecRestoreArray(cown, &array)); 1367 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1368 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1369 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1370 PetscCall(ISDestroy(&acis)); 1371 PetscCall(VecScatterDestroy(&sct)); 1372 PetscCall(VecDestroy(&cown)); 1373 1374 /* compute edgeCut */ 1375 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1376 PetscCall(PetscMalloc1(cum, &work)); 1377 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1378 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1379 PetscCall(ISDestroy(&gid)); 1380 PetscCall(VecGetArray(acown, &array)); 1381 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1382 PetscInt totl; 1383 1384 totl = start[c + 1] - start[c]; 1385 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1386 for (i = 0; i < totl; i++) { 1387 if (work[i] < 0) { 1388 ect += 1; 1389 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1390 } 1391 } 1392 } 1393 PetscCall(PetscFree(work)); 1394 PetscCall(VecRestoreArray(acown, &array)); 1395 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1396 lm[1] = -numVertices; 1397 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1398 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1399 lm[0] = ect; /* edgeCut */ 1400 lm[1] = ectn; /* node-aware edgeCut */ 1401 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1402 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1403 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1404 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1405 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1406 #else 1407 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1408 #endif 1409 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1410 PetscCall(PetscFree(start)); 1411 PetscCall(PetscFree(adjacency)); 1412 PetscCall(VecDestroy(&acown)); 1413 } else { 1414 const char *name; 1415 PetscInt *sizes, *hybsizes, *ghostsizes; 1416 PetscInt locDepth, depth, cellHeight, dim, d; 1417 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1418 PetscInt numLabels, l, maxSize = 17; 1419 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1420 MPI_Comm comm; 1421 PetscMPIInt size, rank; 1422 1423 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1424 PetscCallMPI(MPI_Comm_size(comm, &size)); 1425 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1426 PetscCall(DMGetDimension(dm, &dim)); 1427 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1428 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1429 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1430 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1431 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1432 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1433 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1434 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1435 gcNum = gcEnd - gcStart; 1436 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1437 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1438 for (d = 0; d <= depth; d++) { 1439 PetscInt Nc[2] = {0, 0}, ict; 1440 1441 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1442 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1443 ict = ct0; 1444 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1445 ct0 = (DMPolytopeType)ict; 1446 for (p = pStart; p < pEnd; ++p) { 1447 DMPolytopeType ct; 1448 1449 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1450 if (ct == ct0) ++Nc[0]; 1451 else ++Nc[1]; 1452 } 1453 if (size < maxSize) { 1454 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1455 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1456 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1457 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1458 for (p = 0; p < size; ++p) { 1459 if (rank == 0) { 1460 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1461 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1462 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1463 } 1464 } 1465 } else { 1466 PetscInt locMinMax[2]; 1467 1468 locMinMax[0] = Nc[0] + Nc[1]; 1469 locMinMax[1] = Nc[0] + Nc[1]; 1470 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1471 locMinMax[0] = Nc[1]; 1472 locMinMax[1] = Nc[1]; 1473 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1474 if (d == depth) { 1475 locMinMax[0] = gcNum; 1476 locMinMax[1] = gcNum; 1477 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1478 } 1479 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1480 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1481 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1482 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1483 } 1484 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1485 } 1486 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1487 { 1488 const PetscReal *maxCell; 1489 const PetscReal *L; 1490 PetscBool localized; 1491 1492 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1493 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1494 if (L || localized) { 1495 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1496 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1497 if (L) { 1498 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1499 for (d = 0; d < dim; ++d) { 1500 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1502 } 1503 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1504 } 1505 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1506 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1507 } 1508 } 1509 PetscCall(DMGetNumLabels(dm, &numLabels)); 1510 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1511 for (l = 0; l < numLabels; ++l) { 1512 DMLabel label; 1513 const char *name; 1514 IS valueIS; 1515 const PetscInt *values; 1516 PetscInt numValues, v; 1517 1518 PetscCall(DMGetLabelName(dm, l, &name)); 1519 PetscCall(DMGetLabel(dm, name, &label)); 1520 PetscCall(DMLabelGetNumValues(label, &numValues)); 1521 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1522 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1523 PetscCall(ISGetIndices(valueIS, &values)); 1524 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1525 for (v = 0; v < numValues; ++v) { 1526 PetscInt size; 1527 1528 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1529 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1530 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1531 } 1532 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1533 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1534 PetscCall(ISRestoreIndices(valueIS, &values)); 1535 PetscCall(ISDestroy(&valueIS)); 1536 } 1537 { 1538 char **labelNames; 1539 PetscInt Nl = numLabels; 1540 PetscBool flg; 1541 1542 PetscCall(PetscMalloc1(Nl, &labelNames)); 1543 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1544 for (l = 0; l < Nl; ++l) { 1545 DMLabel label; 1546 1547 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1548 if (flg) { 1549 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1550 PetscCall(DMLabelView(label, viewer)); 1551 } 1552 PetscCall(PetscFree(labelNames[l])); 1553 } 1554 PetscCall(PetscFree(labelNames)); 1555 } 1556 /* If no fields are specified, people do not want to see adjacency */ 1557 if (dm->Nf) { 1558 PetscInt f; 1559 1560 for (f = 0; f < dm->Nf; ++f) { 1561 const char *name; 1562 1563 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1564 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1565 PetscCall(PetscViewerASCIIPushTab(viewer)); 1566 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1567 if (dm->fields[f].adjacency[0]) { 1568 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1569 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1570 } else { 1571 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1572 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1573 } 1574 PetscCall(PetscViewerASCIIPopTab(viewer)); 1575 } 1576 } 1577 PetscCall(DMGetCoarseDM(dm, &cdm)); 1578 if (cdm) { 1579 PetscCall(PetscViewerASCIIPushTab(viewer)); 1580 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1581 PetscCall(PetscViewerASCIIPopTab(viewer)); 1582 } 1583 } 1584 PetscFunctionReturn(0); 1585 } 1586 1587 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1588 { 1589 DMPolytopeType ct; 1590 PetscMPIInt rank; 1591 PetscInt cdim; 1592 1593 PetscFunctionBegin; 1594 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1595 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1596 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1597 switch (ct) { 1598 case DM_POLYTOPE_SEGMENT: 1599 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1600 switch (cdim) { 1601 case 1: { 1602 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1603 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1604 1605 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1606 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1607 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1608 } break; 1609 case 2: { 1610 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1611 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1612 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1613 1614 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1615 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)); 1616 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)); 1617 } break; 1618 default: 1619 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1620 } 1621 break; 1622 case DM_POLYTOPE_TRIANGLE: 1623 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)); 1624 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1625 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1626 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1627 break; 1628 case DM_POLYTOPE_QUADRILATERAL: 1629 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)); 1630 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)); 1631 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1632 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1633 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1634 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1635 break; 1636 case DM_POLYTOPE_FV_GHOST: 1637 break; 1638 default: 1639 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1640 } 1641 PetscFunctionReturn(0); 1642 } 1643 1644 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1645 { 1646 DMPolytopeType ct; 1647 PetscReal centroid[2] = {0., 0.}; 1648 PetscMPIInt rank; 1649 PetscInt fillColor, v, e, d; 1650 1651 PetscFunctionBegin; 1652 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1653 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1654 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1655 switch (ct) { 1656 case DM_POLYTOPE_TRIANGLE: { 1657 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1658 1659 for (v = 0; v < 3; ++v) { 1660 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1661 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1662 } 1663 for (e = 0; e < 3; ++e) { 1664 refCoords[0] = refVertices[e * 2 + 0]; 1665 refCoords[1] = refVertices[e * 2 + 1]; 1666 for (d = 1; d <= edgeDiv; ++d) { 1667 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1668 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1669 } 1670 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1671 for (d = 0; d < edgeDiv; ++d) { 1672 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)); 1673 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1674 } 1675 } 1676 } break; 1677 default: 1678 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1679 } 1680 PetscFunctionReturn(0); 1681 } 1682 1683 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1684 { 1685 PetscDraw draw; 1686 DM cdm; 1687 PetscSection coordSection; 1688 Vec coordinates; 1689 const PetscScalar *coords; 1690 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1691 PetscReal *refCoords, *edgeCoords; 1692 PetscBool isnull, drawAffine = PETSC_TRUE; 1693 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1694 1695 PetscFunctionBegin; 1696 PetscCall(DMGetCoordinateDim(dm, &dim)); 1697 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1698 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1699 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1700 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1701 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1702 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1703 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1704 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1705 1706 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1707 PetscCall(PetscDrawIsNull(draw, &isnull)); 1708 if (isnull) PetscFunctionReturn(0); 1709 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1710 1711 PetscCall(VecGetLocalSize(coordinates, &N)); 1712 PetscCall(VecGetArrayRead(coordinates, &coords)); 1713 for (c = 0; c < N; c += dim) { 1714 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1715 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1716 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1717 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1718 } 1719 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1720 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1721 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 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 PetscInt numCoords; 1728 1729 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1730 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1731 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1732 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1733 } 1734 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1735 PetscCall(PetscDrawFlush(draw)); 1736 PetscCall(PetscDrawPause(draw)); 1737 PetscCall(PetscDrawSave(draw)); 1738 PetscFunctionReturn(0); 1739 } 1740 1741 #if defined(PETSC_HAVE_EXODUSII) 1742 #include <exodusII.h> 1743 #include <petscviewerexodusii.h> 1744 #endif 1745 1746 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1747 { 1748 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1749 char name[PETSC_MAX_PATH_LEN]; 1750 1751 PetscFunctionBegin; 1752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1753 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1754 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1755 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1756 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1757 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1758 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1759 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1760 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1761 if (iascii) { 1762 PetscViewerFormat format; 1763 PetscCall(PetscViewerGetFormat(viewer, &format)); 1764 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1765 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1766 } else if (ishdf5) { 1767 #if defined(PETSC_HAVE_HDF5) 1768 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1769 #else 1770 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1771 #endif 1772 } else if (isvtk) { 1773 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1774 } else if (isdraw) { 1775 PetscCall(DMPlexView_Draw(dm, viewer)); 1776 } else if (isglvis) { 1777 PetscCall(DMPlexView_GLVis(dm, viewer)); 1778 #if defined(PETSC_HAVE_EXODUSII) 1779 } else if (isexodus) { 1780 /* 1781 exodusII requires that all sets be part of exactly one cell set. 1782 If the dm does not have a "Cell Sets" label defined, we create one 1783 with ID 1, containig all cells. 1784 Note that if the Cell Sets label is defined but does not cover all cells, 1785 we may still have a problem. This should probably be checked here or in the viewer; 1786 */ 1787 PetscInt numCS; 1788 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1789 if (!numCS) { 1790 PetscInt cStart, cEnd, c; 1791 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1792 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1793 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1794 } 1795 PetscCall(DMView_PlexExodusII(dm, viewer)); 1796 #endif 1797 #if defined(PETSC_HAVE_CGNS) 1798 } else if (iscgns) { 1799 PetscCall(DMView_PlexCGNS(dm, viewer)); 1800 #endif 1801 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1802 /* Optionally view the partition */ 1803 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1804 if (flg) { 1805 Vec ranks; 1806 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1807 PetscCall(VecView(ranks, viewer)); 1808 PetscCall(VecDestroy(&ranks)); 1809 } 1810 /* Optionally view a label */ 1811 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1812 if (flg) { 1813 DMLabel label; 1814 Vec val; 1815 1816 PetscCall(DMGetLabel(dm, name, &label)); 1817 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1818 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1819 PetscCall(VecView(val, viewer)); 1820 PetscCall(VecDestroy(&val)); 1821 } 1822 PetscFunctionReturn(0); 1823 } 1824 1825 /*@ 1826 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1827 1828 Collective on dm 1829 1830 Input Parameters: 1831 + dm - The `DM` whose topology is to be saved 1832 - viewer - The `PetscViewer` to save it in 1833 1834 Level: advanced 1835 1836 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1837 @*/ 1838 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1839 { 1840 PetscBool ishdf5; 1841 1842 PetscFunctionBegin; 1843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1844 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1845 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1846 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1847 if (ishdf5) { 1848 #if defined(PETSC_HAVE_HDF5) 1849 PetscViewerFormat format; 1850 PetscCall(PetscViewerGetFormat(viewer, &format)); 1851 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1852 IS globalPointNumbering; 1853 1854 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1855 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1856 PetscCall(ISDestroy(&globalPointNumbering)); 1857 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1858 #else 1859 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1860 #endif 1861 } 1862 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1863 PetscFunctionReturn(0); 1864 } 1865 1866 /*@ 1867 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1868 1869 Collective on dm 1870 1871 Input Parameters: 1872 + dm - The `DM` whose coordinates are to be saved 1873 - viewer - The `PetscViewer` for saving 1874 1875 Level: advanced 1876 1877 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1878 @*/ 1879 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1880 { 1881 PetscBool ishdf5; 1882 1883 PetscFunctionBegin; 1884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1885 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1886 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1887 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1888 if (ishdf5) { 1889 #if defined(PETSC_HAVE_HDF5) 1890 PetscViewerFormat format; 1891 PetscCall(PetscViewerGetFormat(viewer, &format)); 1892 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1893 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1894 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1895 #else 1896 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1897 #endif 1898 } 1899 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1900 PetscFunctionReturn(0); 1901 } 1902 1903 /*@ 1904 DMPlexLabelsView - Saves `DMPLEX` labels into a file 1905 1906 Collective on dm 1907 1908 Input Parameters: 1909 + dm - The `DM` whose labels are to be saved 1910 - viewer - The `PetscViewer` for saving 1911 1912 Level: advanced 1913 1914 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 1915 @*/ 1916 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1917 { 1918 PetscBool ishdf5; 1919 1920 PetscFunctionBegin; 1921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1922 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1923 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1924 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1925 if (ishdf5) { 1926 #if defined(PETSC_HAVE_HDF5) 1927 IS globalPointNumbering; 1928 PetscViewerFormat format; 1929 1930 PetscCall(PetscViewerGetFormat(viewer, &format)); 1931 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1932 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1933 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1934 PetscCall(ISDestroy(&globalPointNumbering)); 1935 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1936 #else 1937 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1938 #endif 1939 } 1940 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1941 PetscFunctionReturn(0); 1942 } 1943 1944 /*@ 1945 DMPlexSectionView - Saves a section associated with a `DMPLEX` 1946 1947 Collective on dm 1948 1949 Input Parameters: 1950 + dm - The `DM` that contains the topology on which the section to be saved is defined 1951 . viewer - The `PetscViewer` for saving 1952 - sectiondm - The `DM` that contains the section to be saved 1953 1954 Level: advanced 1955 1956 Notes: 1957 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. 1958 1959 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. 1960 1961 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 1962 @*/ 1963 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1964 { 1965 PetscBool ishdf5; 1966 1967 PetscFunctionBegin; 1968 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1969 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1970 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1971 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1972 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1973 if (ishdf5) { 1974 #if defined(PETSC_HAVE_HDF5) 1975 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1976 #else 1977 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1978 #endif 1979 } 1980 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1981 PetscFunctionReturn(0); 1982 } 1983 1984 /*@ 1985 DMPlexGlobalVectorView - Saves a global vector 1986 1987 Collective on dm 1988 1989 Input Parameters: 1990 + dm - The `DM` that represents the topology 1991 . viewer - The `PetscViewer` to save data with 1992 . sectiondm - The `DM` that contains the global section on which vec is defined 1993 - vec - The global vector to be saved 1994 1995 Level: advanced 1996 1997 Notes: 1998 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. 1999 2000 Typical calling sequence: 2001 .vb 2002 DMCreate(PETSC_COMM_WORLD, &dm); 2003 DMSetType(dm, DMPLEX); 2004 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2005 DMClone(dm, §iondm); 2006 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2007 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2008 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2009 PetscSectionSetChart(section, pStart, pEnd); 2010 PetscSectionSetUp(section); 2011 DMSetLocalSection(sectiondm, section); 2012 PetscSectionDestroy(§ion); 2013 DMGetGlobalVector(sectiondm, &vec); 2014 PetscObjectSetName((PetscObject)vec, "vec_name"); 2015 DMPlexTopologyView(dm, viewer); 2016 DMPlexSectionView(dm, viewer, sectiondm); 2017 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2018 DMRestoreGlobalVector(sectiondm, &vec); 2019 DMDestroy(§iondm); 2020 DMDestroy(&dm); 2021 .ve 2022 2023 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2024 @*/ 2025 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2026 { 2027 PetscBool ishdf5; 2028 2029 PetscFunctionBegin; 2030 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2031 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2032 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2033 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2034 /* Check consistency */ 2035 { 2036 PetscSection section; 2037 PetscBool includesConstraints; 2038 PetscInt m, m1; 2039 2040 PetscCall(VecGetLocalSize(vec, &m1)); 2041 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2042 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2043 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2044 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2045 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2046 } 2047 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2048 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2049 if (ishdf5) { 2050 #if defined(PETSC_HAVE_HDF5) 2051 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2052 #else 2053 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2054 #endif 2055 } 2056 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2057 PetscFunctionReturn(0); 2058 } 2059 2060 /*@ 2061 DMPlexLocalVectorView - Saves a local vector 2062 2063 Collective on dm 2064 2065 Input Parameters: 2066 + dm - The `DM` that represents the topology 2067 . viewer - The `PetscViewer` to save data with 2068 . sectiondm - The `DM` that contains the local section on which vec is defined; may be the same as dm 2069 - vec - The local vector to be saved 2070 2071 Level: advanced 2072 2073 Note: 2074 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. 2075 2076 Typical calling sequence: 2077 .vb 2078 DMCreate(PETSC_COMM_WORLD, &dm); 2079 DMSetType(dm, DMPLEX); 2080 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2081 DMClone(dm, §iondm); 2082 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2083 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2084 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2085 PetscSectionSetChart(section, pStart, pEnd); 2086 PetscSectionSetUp(section); 2087 DMSetLocalSection(sectiondm, section); 2088 DMGetLocalVector(sectiondm, &vec); 2089 PetscObjectSetName((PetscObject)vec, "vec_name"); 2090 DMPlexTopologyView(dm, viewer); 2091 DMPlexSectionView(dm, viewer, sectiondm); 2092 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2093 DMRestoreLocalVector(sectiondm, &vec); 2094 DMDestroy(§iondm); 2095 DMDestroy(&dm); 2096 .ve 2097 2098 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2099 @*/ 2100 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2101 { 2102 PetscBool ishdf5; 2103 2104 PetscFunctionBegin; 2105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2106 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2107 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2108 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2109 /* Check consistency */ 2110 { 2111 PetscSection section; 2112 PetscBool includesConstraints; 2113 PetscInt m, m1; 2114 2115 PetscCall(VecGetLocalSize(vec, &m1)); 2116 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2117 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2118 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2119 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2120 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2121 } 2122 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2123 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2124 if (ishdf5) { 2125 #if defined(PETSC_HAVE_HDF5) 2126 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2127 #else 2128 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2129 #endif 2130 } 2131 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2132 PetscFunctionReturn(0); 2133 } 2134 2135 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2136 { 2137 PetscBool ishdf5; 2138 2139 PetscFunctionBegin; 2140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2141 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2142 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2143 if (ishdf5) { 2144 #if defined(PETSC_HAVE_HDF5) 2145 PetscViewerFormat format; 2146 PetscCall(PetscViewerGetFormat(viewer, &format)); 2147 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2148 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2149 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2150 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2151 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2152 PetscFunctionReturn(0); 2153 #else 2154 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2155 #endif 2156 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2157 } 2158 2159 /*@ 2160 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2161 2162 Collective on dm 2163 2164 Input Parameters: 2165 + dm - The `DM` into which the topology is loaded 2166 - viewer - The `PetscViewer` for the saved topology 2167 2168 Output Parameters: 2169 . 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 2170 2171 Level: advanced 2172 2173 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2174 `PetscViewer`, `PetscSF` 2175 @*/ 2176 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2177 { 2178 PetscBool ishdf5; 2179 2180 PetscFunctionBegin; 2181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2182 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2183 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2184 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2185 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2186 if (ishdf5) { 2187 #if defined(PETSC_HAVE_HDF5) 2188 PetscViewerFormat format; 2189 PetscCall(PetscViewerGetFormat(viewer, &format)); 2190 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2191 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2192 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2193 #else 2194 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2195 #endif 2196 } 2197 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2198 PetscFunctionReturn(0); 2199 } 2200 2201 /*@ 2202 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2203 2204 Collective on dm 2205 2206 Input Parameters: 2207 + dm - The `DM` into which the coordinates are loaded 2208 . viewer - The `PetscViewer` for the saved coordinates 2209 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2210 2211 Level: advanced 2212 2213 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2214 `PetscSF`, `PetscViewer` 2215 @*/ 2216 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2217 { 2218 PetscBool ishdf5; 2219 2220 PetscFunctionBegin; 2221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2222 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2223 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2224 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2225 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2226 if (ishdf5) { 2227 #if defined(PETSC_HAVE_HDF5) 2228 PetscViewerFormat format; 2229 PetscCall(PetscViewerGetFormat(viewer, &format)); 2230 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2231 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2232 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2233 #else 2234 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2235 #endif 2236 } 2237 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2238 PetscFunctionReturn(0); 2239 } 2240 2241 /*@ 2242 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2243 2244 Collective on dm 2245 2246 Input Parameters: 2247 + dm - The `DM` into which the labels are loaded 2248 . viewer - The `PetscViewer` for the saved labels 2249 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2250 2251 Level: advanced 2252 2253 Note: 2254 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2255 2256 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2257 `PetscSF`, `PetscViewer` 2258 @*/ 2259 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2260 { 2261 PetscBool ishdf5; 2262 2263 PetscFunctionBegin; 2264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2265 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2266 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2267 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2268 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2269 if (ishdf5) { 2270 #if defined(PETSC_HAVE_HDF5) 2271 PetscViewerFormat format; 2272 2273 PetscCall(PetscViewerGetFormat(viewer, &format)); 2274 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2275 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2276 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2277 #else 2278 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2279 #endif 2280 } 2281 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2282 PetscFunctionReturn(0); 2283 } 2284 2285 /*@ 2286 DMPlexSectionLoad - Loads section into a `DMPLEX` 2287 2288 Collective on dm 2289 2290 Input Parameters: 2291 + dm - The `DM` that represents the topology 2292 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2293 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2294 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2295 2296 Output Parameters 2297 + 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) 2298 - 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) 2299 2300 Level: advanced 2301 2302 Notes: 2303 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. 2304 2305 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. 2306 2307 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. 2308 2309 Example using 2 processes: 2310 .vb 2311 NX (number of points on dm): 4 2312 sectionA : the on-disk section 2313 vecA : a vector associated with sectionA 2314 sectionB : sectiondm's local section constructed in this function 2315 vecB (local) : a vector associated with sectiondm's local section 2316 vecB (global) : a vector associated with sectiondm's global section 2317 2318 rank 0 rank 1 2319 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2320 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2321 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2322 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2323 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2324 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2325 sectionB->atlasDof : 1 0 1 | 1 3 2326 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2327 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2328 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2329 .ve 2330 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2331 2332 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2333 @*/ 2334 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2335 { 2336 PetscBool ishdf5; 2337 2338 PetscFunctionBegin; 2339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2340 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2341 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2342 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2343 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2344 if (localDofSF) PetscValidPointer(localDofSF, 6); 2345 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2346 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2347 if (ishdf5) { 2348 #if defined(PETSC_HAVE_HDF5) 2349 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2350 #else 2351 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2352 #endif 2353 } 2354 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2355 PetscFunctionReturn(0); 2356 } 2357 2358 /*@ 2359 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2360 2361 Collective on dm 2362 2363 Input Parameters: 2364 + dm - The `DM` that represents the topology 2365 . viewer - The `PetscViewer` that represents the on-disk vector data 2366 . sectiondm - The `DM` that contains the global section on which vec is defined 2367 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2368 - vec - The global vector to set values of 2369 2370 Level: advanced 2371 2372 Notes: 2373 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. 2374 2375 Typical calling sequence: 2376 .vb 2377 DMCreate(PETSC_COMM_WORLD, &dm); 2378 DMSetType(dm, DMPLEX); 2379 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2380 DMPlexTopologyLoad(dm, viewer, &sfX); 2381 DMClone(dm, §iondm); 2382 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2383 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2384 DMGetGlobalVector(sectiondm, &vec); 2385 PetscObjectSetName((PetscObject)vec, "vec_name"); 2386 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2387 DMRestoreGlobalVector(sectiondm, &vec); 2388 PetscSFDestroy(&gsf); 2389 PetscSFDestroy(&sfX); 2390 DMDestroy(§iondm); 2391 DMDestroy(&dm); 2392 .ve 2393 2394 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2395 `PetscSF`, `PetscViewer` 2396 @*/ 2397 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2398 { 2399 PetscBool ishdf5; 2400 2401 PetscFunctionBegin; 2402 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2403 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2404 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2405 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2406 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2407 /* Check consistency */ 2408 { 2409 PetscSection section; 2410 PetscBool includesConstraints; 2411 PetscInt m, m1; 2412 2413 PetscCall(VecGetLocalSize(vec, &m1)); 2414 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2415 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2416 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2417 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2418 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2419 } 2420 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2421 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2422 if (ishdf5) { 2423 #if defined(PETSC_HAVE_HDF5) 2424 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2425 #else 2426 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2427 #endif 2428 } 2429 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2430 PetscFunctionReturn(0); 2431 } 2432 2433 /*@ 2434 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2435 2436 Collective on dm 2437 2438 Input Parameters: 2439 + dm - The `DM` that represents the topology 2440 . viewer - The `PetscViewer` that represents the on-disk vector data 2441 . sectiondm - The `DM` that contains the local section on which vec is defined 2442 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2443 - vec - The local vector to set values of 2444 2445 Level: advanced 2446 2447 Notes: 2448 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. 2449 2450 Typical calling sequence: 2451 .vb 2452 DMCreate(PETSC_COMM_WORLD, &dm); 2453 DMSetType(dm, DMPLEX); 2454 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2455 DMPlexTopologyLoad(dm, viewer, &sfX); 2456 DMClone(dm, §iondm); 2457 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2458 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2459 DMGetLocalVector(sectiondm, &vec); 2460 PetscObjectSetName((PetscObject)vec, "vec_name"); 2461 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2462 DMRestoreLocalVector(sectiondm, &vec); 2463 PetscSFDestroy(&lsf); 2464 PetscSFDestroy(&sfX); 2465 DMDestroy(§iondm); 2466 DMDestroy(&dm); 2467 .ve 2468 2469 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2470 `PetscSF`, `PetscViewer` 2471 @*/ 2472 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2473 { 2474 PetscBool ishdf5; 2475 2476 PetscFunctionBegin; 2477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2478 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2479 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2480 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2481 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2482 /* Check consistency */ 2483 { 2484 PetscSection section; 2485 PetscBool includesConstraints; 2486 PetscInt m, m1; 2487 2488 PetscCall(VecGetLocalSize(vec, &m1)); 2489 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2490 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2491 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2492 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2493 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2494 } 2495 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2496 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2497 if (ishdf5) { 2498 #if defined(PETSC_HAVE_HDF5) 2499 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2500 #else 2501 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2502 #endif 2503 } 2504 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2505 PetscFunctionReturn(0); 2506 } 2507 2508 PetscErrorCode DMDestroy_Plex(DM dm) 2509 { 2510 DM_Plex *mesh = (DM_Plex *)dm->data; 2511 2512 PetscFunctionBegin; 2513 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2514 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2515 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2516 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2517 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2518 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2519 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2520 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2521 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2522 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2523 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2524 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2525 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2526 if (--mesh->refct > 0) PetscFunctionReturn(0); 2527 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2528 PetscCall(PetscFree(mesh->cones)); 2529 PetscCall(PetscFree(mesh->coneOrientations)); 2530 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2531 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2532 PetscCall(PetscFree(mesh->supports)); 2533 PetscCall(PetscFree(mesh->facesTmp)); 2534 PetscCall(PetscFree(mesh->tetgenOpts)); 2535 PetscCall(PetscFree(mesh->triangleOpts)); 2536 PetscCall(PetscFree(mesh->transformType)); 2537 PetscCall(PetscFree(mesh->distributionName)); 2538 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2539 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2540 PetscCall(ISDestroy(&mesh->subpointIS)); 2541 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2542 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2543 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2544 PetscCall(ISDestroy(&mesh->anchorIS)); 2545 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2546 PetscCall(PetscFree(mesh->parents)); 2547 PetscCall(PetscFree(mesh->childIDs)); 2548 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2549 PetscCall(PetscFree(mesh->children)); 2550 PetscCall(DMDestroy(&mesh->referenceTree)); 2551 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2552 PetscCall(PetscFree(mesh->neighbors)); 2553 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2554 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2555 PetscCall(PetscFree(mesh)); 2556 PetscFunctionReturn(0); 2557 } 2558 2559 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2560 { 2561 PetscSection sectionGlobal; 2562 PetscInt bs = -1, mbs; 2563 PetscInt localSize, localStart = 0; 2564 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2565 MatType mtype; 2566 ISLocalToGlobalMapping ltog; 2567 2568 PetscFunctionBegin; 2569 PetscCall(MatInitializePackage()); 2570 mtype = dm->mattype; 2571 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2572 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2573 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2574 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2575 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2576 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2577 PetscCall(MatSetType(*J, mtype)); 2578 PetscCall(MatSetFromOptions(*J)); 2579 PetscCall(MatGetBlockSize(*J, &mbs)); 2580 if (mbs > 1) bs = mbs; 2581 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2582 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2583 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2584 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2585 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2586 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2587 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2588 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2589 if (!isShell) { 2590 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2591 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2592 PetscInt pStart, pEnd, p, dof, cdof; 2593 2594 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2595 2596 PetscCall(PetscCalloc1(localSize, &pblocks)); 2597 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2598 for (p = pStart; p < pEnd; ++p) { 2599 PetscInt bdof, offset; 2600 2601 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2602 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2603 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2604 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2605 dof = dof < 0 ? -(dof + 1) : dof; 2606 bdof = cdof && (dof - cdof) ? 1 : dof; 2607 if (dof) { 2608 if (bs < 0) { 2609 bs = bdof; 2610 } else if (bs != bdof) { 2611 bs = 1; 2612 } 2613 } 2614 } 2615 /* Must have same blocksize on all procs (some might have no points) */ 2616 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2617 bsLocal[1] = bs; 2618 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2619 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2620 else bs = bsMinMax[0]; 2621 bs = PetscMax(1, bs); 2622 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2623 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2624 PetscCall(MatSetBlockSize(*J, bs)); 2625 PetscCall(MatSetUp(*J)); 2626 } else { 2627 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2628 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2629 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2630 } 2631 { // Consolidate blocks 2632 PetscInt nblocks = 0; 2633 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2634 if (pblocks[i] == 0) continue; 2635 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2636 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]); 2637 } 2638 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2639 } 2640 PetscCall(PetscFree(pblocks)); 2641 } 2642 PetscCall(MatSetDM(*J, dm)); 2643 PetscFunctionReturn(0); 2644 } 2645 2646 /*@ 2647 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2648 2649 Not Collective 2650 2651 Input Parameter: 2652 . mesh - The `DMPLEX` 2653 2654 Output Parameters: 2655 . subsection - The subdomain section 2656 2657 Level: developer 2658 2659 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSection` 2660 @*/ 2661 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2662 { 2663 DM_Plex *mesh = (DM_Plex *)dm->data; 2664 2665 PetscFunctionBegin; 2666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2667 if (!mesh->subdomainSection) { 2668 PetscSection section; 2669 PetscSF sf; 2670 2671 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2672 PetscCall(DMGetLocalSection(dm, §ion)); 2673 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2674 PetscCall(PetscSFDestroy(&sf)); 2675 } 2676 *subsection = mesh->subdomainSection; 2677 PetscFunctionReturn(0); 2678 } 2679 2680 /*@ 2681 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2682 2683 Not Collective 2684 2685 Input Parameter: 2686 . mesh - The `DMPLEX` 2687 2688 Output Parameters: 2689 + pStart - The first mesh point 2690 - pEnd - The upper bound for mesh points 2691 2692 Level: beginner 2693 2694 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2695 @*/ 2696 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2697 { 2698 DM_Plex *mesh = (DM_Plex *)dm->data; 2699 2700 PetscFunctionBegin; 2701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2702 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2703 PetscFunctionReturn(0); 2704 } 2705 2706 /*@ 2707 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2708 2709 Not Collective 2710 2711 Input Parameters: 2712 + mesh - The `DMPLEX` 2713 . pStart - The first mesh point 2714 - pEnd - The upper bound for mesh points 2715 2716 Level: beginner 2717 2718 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2719 @*/ 2720 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2721 { 2722 DM_Plex *mesh = (DM_Plex *)dm->data; 2723 2724 PetscFunctionBegin; 2725 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2726 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2727 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2728 PetscFunctionReturn(0); 2729 } 2730 2731 /*@ 2732 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2733 2734 Not Collective 2735 2736 Input Parameters: 2737 + mesh - The `DMPLEX` 2738 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2739 2740 Output Parameter: 2741 . size - The cone size for point p 2742 2743 Level: beginner 2744 2745 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2746 @*/ 2747 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2748 { 2749 DM_Plex *mesh = (DM_Plex *)dm->data; 2750 2751 PetscFunctionBegin; 2752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2753 PetscValidIntPointer(size, 3); 2754 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2755 PetscFunctionReturn(0); 2756 } 2757 2758 /*@ 2759 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2760 2761 Not Collective 2762 2763 Input Parameters: 2764 + mesh - The `DMPLEX` 2765 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2766 - size - The cone size for point p 2767 2768 Level: beginner 2769 2770 Note: 2771 This should be called after `DMPlexSetChart()`. 2772 2773 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2774 @*/ 2775 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2776 { 2777 DM_Plex *mesh = (DM_Plex *)dm->data; 2778 2779 PetscFunctionBegin; 2780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2781 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2782 PetscFunctionReturn(0); 2783 } 2784 2785 /*@ 2786 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2787 2788 Not Collective 2789 2790 Input Parameters: 2791 + mesh - The `DMPLEX` 2792 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2793 - size - The additional cone size for point p 2794 2795 Level: beginner 2796 2797 Note: 2798 This should be called after `DMPlexSetChart()`. 2799 2800 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2801 @*/ 2802 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2803 { 2804 DM_Plex *mesh = (DM_Plex *)dm->data; 2805 PetscFunctionBegin; 2806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2807 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2808 PetscFunctionReturn(0); 2809 } 2810 2811 /*@C 2812 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2813 2814 Not Collective 2815 2816 Input Parameters: 2817 + dm - The `DMPLEX` 2818 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2819 2820 Output Parameter: 2821 . cone - An array of points which are on the in-edges for point p 2822 2823 Level: beginner 2824 2825 Fortran Note: 2826 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2827 `DMPlexRestoreCone()` is not needed/available in C. 2828 2829 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2830 @*/ 2831 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2832 { 2833 DM_Plex *mesh = (DM_Plex *)dm->data; 2834 PetscInt off; 2835 2836 PetscFunctionBegin; 2837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2838 PetscValidPointer(cone, 3); 2839 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2840 *cone = &mesh->cones[off]; 2841 PetscFunctionReturn(0); 2842 } 2843 2844 /*@C 2845 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2846 2847 Not Collective 2848 2849 Input Parameters: 2850 + dm - The `DMPLEX` 2851 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2852 2853 Output Parameters: 2854 + pConesSection - `PetscSection` describing the layout of pCones 2855 - pCones - An array of points which are on the in-edges for the point set p 2856 2857 Level: intermediate 2858 2859 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2860 @*/ 2861 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2862 { 2863 PetscSection cs, newcs; 2864 PetscInt *cones; 2865 PetscInt *newarr = NULL; 2866 PetscInt n; 2867 2868 PetscFunctionBegin; 2869 PetscCall(DMPlexGetCones(dm, &cones)); 2870 PetscCall(DMPlexGetConeSection(dm, &cs)); 2871 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2872 if (pConesSection) *pConesSection = newcs; 2873 if (pCones) { 2874 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2875 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2876 } 2877 PetscFunctionReturn(0); 2878 } 2879 2880 /*@ 2881 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2882 2883 Not Collective 2884 2885 Input Parameters: 2886 + dm - The `DMPLEX` 2887 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2888 2889 Output Parameter: 2890 . expandedPoints - An array of vertices recursively expanded from input points 2891 2892 Level: advanced 2893 2894 Notes: 2895 Like `DMPlexGetConeRecursive()` but returns only the 0-depth IS (i.e. vertices only) and no sections. 2896 2897 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 2898 2899 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 2900 `DMPlexGetDepth()`, `IS` 2901 @*/ 2902 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2903 { 2904 IS *expandedPointsAll; 2905 PetscInt depth; 2906 2907 PetscFunctionBegin; 2908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2909 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2910 PetscValidPointer(expandedPoints, 3); 2911 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2912 *expandedPoints = expandedPointsAll[0]; 2913 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2914 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2915 PetscFunctionReturn(0); 2916 } 2917 2918 /*@ 2919 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). 2920 2921 Not Collective 2922 2923 Input Parameters: 2924 + dm - The `DMPLEX` 2925 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2926 2927 Output Parameters: 2928 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 2929 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2930 - sections - (optional) An array of sections which describe mappings from points to their cone points 2931 2932 Level: advanced 2933 2934 Notes: 2935 Like `DMPlexGetConeTuple()` but recursive. 2936 2937 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. 2938 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2939 2940 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: 2941 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2942 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2943 2944 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 2945 `DMPlexGetDepth()`, `PetscSection`, `IS` 2946 @*/ 2947 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2948 { 2949 const PetscInt *arr0 = NULL, *cone = NULL; 2950 PetscInt *arr = NULL, *newarr = NULL; 2951 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2952 IS *expandedPoints_; 2953 PetscSection *sections_; 2954 2955 PetscFunctionBegin; 2956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2957 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2958 if (depth) PetscValidIntPointer(depth, 3); 2959 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2960 if (sections) PetscValidPointer(sections, 5); 2961 PetscCall(ISGetLocalSize(points, &n)); 2962 PetscCall(ISGetIndices(points, &arr0)); 2963 PetscCall(DMPlexGetDepth(dm, &depth_)); 2964 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2965 PetscCall(PetscCalloc1(depth_, §ions_)); 2966 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2967 for (d = depth_ - 1; d >= 0; d--) { 2968 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2969 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2970 for (i = 0; i < n; i++) { 2971 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2972 if (arr[i] >= start && arr[i] < end) { 2973 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2974 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2975 } else { 2976 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2977 } 2978 } 2979 PetscCall(PetscSectionSetUp(sections_[d])); 2980 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2981 PetscCall(PetscMalloc1(newn, &newarr)); 2982 for (i = 0; i < n; i++) { 2983 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2984 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2985 if (cn > 1) { 2986 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2987 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2988 } else { 2989 newarr[co] = arr[i]; 2990 } 2991 } 2992 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2993 arr = newarr; 2994 n = newn; 2995 } 2996 PetscCall(ISRestoreIndices(points, &arr0)); 2997 *depth = depth_; 2998 if (expandedPoints) *expandedPoints = expandedPoints_; 2999 else { 3000 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3001 PetscCall(PetscFree(expandedPoints_)); 3002 } 3003 if (sections) *sections = sections_; 3004 else { 3005 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3006 PetscCall(PetscFree(sections_)); 3007 } 3008 PetscFunctionReturn(0); 3009 } 3010 3011 /*@ 3012 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3013 3014 Not Collective 3015 3016 Input Parameters: 3017 + dm - The `DMPLEX` 3018 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3019 3020 Output Parameters: 3021 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3022 . expandedPoints - (optional) An array of recursively expanded cones 3023 - sections - (optional) An array of sections which describe mappings from points to their cone points 3024 3025 Level: advanced 3026 3027 Note: 3028 See `DMPlexGetConeRecursive()` 3029 3030 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3031 `DMPlexGetDepth()`, `IS`, `PetscSection` 3032 @*/ 3033 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3034 { 3035 PetscInt d, depth_; 3036 3037 PetscFunctionBegin; 3038 PetscCall(DMPlexGetDepth(dm, &depth_)); 3039 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3040 if (depth) *depth = 0; 3041 if (expandedPoints) { 3042 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3043 PetscCall(PetscFree(*expandedPoints)); 3044 } 3045 if (sections) { 3046 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3047 PetscCall(PetscFree(*sections)); 3048 } 3049 PetscFunctionReturn(0); 3050 } 3051 3052 /*@ 3053 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 3054 3055 Not Collective 3056 3057 Input Parameters: 3058 + mesh - The `DMPLEX` 3059 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3060 - cone - An array of points which are on the in-edges for point p 3061 3062 Level: beginner 3063 3064 Note: 3065 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3066 3067 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3068 @*/ 3069 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3070 { 3071 DM_Plex *mesh = (DM_Plex *)dm->data; 3072 PetscInt pStart, pEnd; 3073 PetscInt dof, off, c; 3074 3075 PetscFunctionBegin; 3076 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3077 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3078 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3079 if (dof) PetscValidIntPointer(cone, 3); 3080 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3081 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); 3082 for (c = 0; c < dof; ++c) { 3083 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); 3084 mesh->cones[off + c] = cone[c]; 3085 } 3086 PetscFunctionReturn(0); 3087 } 3088 3089 /*@C 3090 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3091 3092 Not Collective 3093 3094 Input Parameters: 3095 + mesh - The `DMPLEX` 3096 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3097 3098 Output Parameter: 3099 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3100 integer giving the prescription for cone traversal. 3101 3102 Level: beginner 3103 3104 Note: 3105 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3106 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3107 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3108 with the identity. 3109 3110 Fortran Note: 3111 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3112 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3113 3114 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3115 @*/ 3116 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3117 { 3118 DM_Plex *mesh = (DM_Plex *)dm->data; 3119 PetscInt off; 3120 3121 PetscFunctionBegin; 3122 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3123 if (PetscDefined(USE_DEBUG)) { 3124 PetscInt dof; 3125 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3126 if (dof) PetscValidPointer(coneOrientation, 3); 3127 } 3128 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3129 3130 *coneOrientation = &mesh->coneOrientations[off]; 3131 PetscFunctionReturn(0); 3132 } 3133 3134 /*@ 3135 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3136 3137 Not Collective 3138 3139 Input Parameters: 3140 + mesh - The `DMPLEX` 3141 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3142 - coneOrientation - An array of orientations 3143 3144 Level: beginner 3145 3146 Notes: 3147 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3148 3149 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3150 3151 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3152 @*/ 3153 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3154 { 3155 DM_Plex *mesh = (DM_Plex *)dm->data; 3156 PetscInt pStart, pEnd; 3157 PetscInt dof, off, c; 3158 3159 PetscFunctionBegin; 3160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3161 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3162 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3163 if (dof) PetscValidIntPointer(coneOrientation, 3); 3164 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3165 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); 3166 for (c = 0; c < dof; ++c) { 3167 PetscInt cdof, o = coneOrientation[c]; 3168 3169 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3170 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); 3171 mesh->coneOrientations[off + c] = o; 3172 } 3173 PetscFunctionReturn(0); 3174 } 3175 3176 /*@ 3177 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3178 3179 Not Collective 3180 3181 Input Parameters: 3182 + mesh - The `DMPLEX` 3183 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3184 . conePos - The local index in the cone where the point should be put 3185 - conePoint - The mesh point to insert 3186 3187 Level: beginner 3188 3189 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3190 @*/ 3191 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3192 { 3193 DM_Plex *mesh = (DM_Plex *)dm->data; 3194 PetscInt pStart, pEnd; 3195 PetscInt dof, off; 3196 3197 PetscFunctionBegin; 3198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3199 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3200 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); 3201 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); 3202 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3203 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3204 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); 3205 mesh->cones[off + conePos] = conePoint; 3206 PetscFunctionReturn(0); 3207 } 3208 3209 /*@ 3210 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3211 3212 Not Collective 3213 3214 Input Parameters: 3215 + mesh - The `DMPLEX` 3216 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3217 . conePos - The local index in the cone where the point should be put 3218 - coneOrientation - The point orientation to insert 3219 3220 Level: beginner 3221 3222 Note: 3223 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3224 3225 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3226 @*/ 3227 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3228 { 3229 DM_Plex *mesh = (DM_Plex *)dm->data; 3230 PetscInt pStart, pEnd; 3231 PetscInt dof, off; 3232 3233 PetscFunctionBegin; 3234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3235 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3236 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); 3237 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3238 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3239 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); 3240 mesh->coneOrientations[off + conePos] = coneOrientation; 3241 PetscFunctionReturn(0); 3242 } 3243 3244 /*@ 3245 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3246 3247 Not Collective 3248 3249 Input Parameters: 3250 + mesh - The `DMPLEX` 3251 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3252 3253 Output Parameter: 3254 . size - The support size for point p 3255 3256 Level: beginner 3257 3258 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3259 @*/ 3260 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3261 { 3262 DM_Plex *mesh = (DM_Plex *)dm->data; 3263 3264 PetscFunctionBegin; 3265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3266 PetscValidIntPointer(size, 3); 3267 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3268 PetscFunctionReturn(0); 3269 } 3270 3271 /*@ 3272 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3273 3274 Not Collective 3275 3276 Input Parameters: 3277 + mesh - The `DMPLEX` 3278 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3279 - size - The support size for point p 3280 3281 Level: beginner 3282 3283 Note: 3284 This should be called after DMPlexSetChart(). 3285 3286 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3287 @*/ 3288 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3289 { 3290 DM_Plex *mesh = (DM_Plex *)dm->data; 3291 3292 PetscFunctionBegin; 3293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3294 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3295 PetscFunctionReturn(0); 3296 } 3297 3298 /*@C 3299 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3300 3301 Not Collective 3302 3303 Input Parameters: 3304 + mesh - The `DMPLEX` 3305 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3306 3307 Output Parameter: 3308 . support - An array of points which are on the out-edges for point p 3309 3310 Level: beginner 3311 3312 Fortran Note: 3313 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3314 `DMPlexRestoreSupport()` is not needed/available in C. 3315 3316 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3317 @*/ 3318 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3319 { 3320 DM_Plex *mesh = (DM_Plex *)dm->data; 3321 PetscInt off; 3322 3323 PetscFunctionBegin; 3324 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3325 PetscValidPointer(support, 3); 3326 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3327 *support = &mesh->supports[off]; 3328 PetscFunctionReturn(0); 3329 } 3330 3331 /*@ 3332 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3333 3334 Not Collective 3335 3336 Input Parameters: 3337 + mesh - The `DMPLEX` 3338 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3339 - support - An array of points which are on the out-edges for point p 3340 3341 Level: beginner 3342 3343 Note: 3344 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3345 3346 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3347 @*/ 3348 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3349 { 3350 DM_Plex *mesh = (DM_Plex *)dm->data; 3351 PetscInt pStart, pEnd; 3352 PetscInt dof, off, c; 3353 3354 PetscFunctionBegin; 3355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3356 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3357 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3358 if (dof) PetscValidIntPointer(support, 3); 3359 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3360 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); 3361 for (c = 0; c < dof; ++c) { 3362 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); 3363 mesh->supports[off + c] = support[c]; 3364 } 3365 PetscFunctionReturn(0); 3366 } 3367 3368 /*@ 3369 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3370 3371 Not Collective 3372 3373 Input Parameters: 3374 + mesh - The `DMPLEX` 3375 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3376 . supportPos - The local index in the cone where the point should be put 3377 - supportPoint - The mesh point to insert 3378 3379 Level: beginner 3380 3381 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3382 @*/ 3383 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3384 { 3385 DM_Plex *mesh = (DM_Plex *)dm->data; 3386 PetscInt pStart, pEnd; 3387 PetscInt dof, off; 3388 3389 PetscFunctionBegin; 3390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3391 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3392 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3393 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3394 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); 3395 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); 3396 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); 3397 mesh->supports[off + supportPos] = supportPoint; 3398 PetscFunctionReturn(0); 3399 } 3400 3401 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3402 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3403 { 3404 switch (ct) { 3405 case DM_POLYTOPE_SEGMENT: 3406 if (o == -1) return -2; 3407 break; 3408 case DM_POLYTOPE_TRIANGLE: 3409 if (o == -3) return -1; 3410 if (o == -2) return -3; 3411 if (o == -1) return -2; 3412 break; 3413 case DM_POLYTOPE_QUADRILATERAL: 3414 if (o == -4) return -2; 3415 if (o == -3) return -1; 3416 if (o == -2) return -4; 3417 if (o == -1) return -3; 3418 break; 3419 default: 3420 return o; 3421 } 3422 return o; 3423 } 3424 3425 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3426 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3427 { 3428 switch (ct) { 3429 case DM_POLYTOPE_SEGMENT: 3430 if ((o == -2) || (o == 1)) return -1; 3431 if (o == -1) return 0; 3432 break; 3433 case DM_POLYTOPE_TRIANGLE: 3434 if (o == -3) return -2; 3435 if (o == -2) return -1; 3436 if (o == -1) return -3; 3437 break; 3438 case DM_POLYTOPE_QUADRILATERAL: 3439 if (o == -4) return -2; 3440 if (o == -3) return -1; 3441 if (o == -2) return -4; 3442 if (o == -1) return -3; 3443 break; 3444 default: 3445 return o; 3446 } 3447 return o; 3448 } 3449 3450 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3451 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3452 { 3453 PetscInt pStart, pEnd, p; 3454 3455 PetscFunctionBegin; 3456 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3457 for (p = pStart; p < pEnd; ++p) { 3458 const PetscInt *cone, *ornt; 3459 PetscInt coneSize, c; 3460 3461 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3462 PetscCall(DMPlexGetCone(dm, p, &cone)); 3463 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3464 for (c = 0; c < coneSize; ++c) { 3465 DMPolytopeType ct; 3466 const PetscInt o = ornt[c]; 3467 3468 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3469 switch (ct) { 3470 case DM_POLYTOPE_SEGMENT: 3471 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3472 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3473 break; 3474 case DM_POLYTOPE_TRIANGLE: 3475 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3476 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3477 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3478 break; 3479 case DM_POLYTOPE_QUADRILATERAL: 3480 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3481 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3482 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3483 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3484 break; 3485 default: 3486 break; 3487 } 3488 } 3489 } 3490 PetscFunctionReturn(0); 3491 } 3492 3493 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3494 { 3495 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3496 PetscInt *closure; 3497 const PetscInt *tmp = NULL, *tmpO = NULL; 3498 PetscInt off = 0, tmpSize, t; 3499 3500 PetscFunctionBeginHot; 3501 if (ornt) { 3502 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3503 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3504 } 3505 if (*points) { 3506 closure = *points; 3507 } else { 3508 PetscInt maxConeSize, maxSupportSize; 3509 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3510 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3511 } 3512 if (useCone) { 3513 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3514 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3515 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3516 } else { 3517 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3518 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3519 } 3520 if (ct == DM_POLYTOPE_UNKNOWN) { 3521 closure[off++] = p; 3522 closure[off++] = 0; 3523 for (t = 0; t < tmpSize; ++t) { 3524 closure[off++] = tmp[t]; 3525 closure[off++] = tmpO ? tmpO[t] : 0; 3526 } 3527 } else { 3528 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3529 3530 /* We assume that cells with a valid type have faces with a valid type */ 3531 closure[off++] = p; 3532 closure[off++] = ornt; 3533 for (t = 0; t < tmpSize; ++t) { 3534 DMPolytopeType ft; 3535 3536 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3537 closure[off++] = tmp[arr[t]]; 3538 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3539 } 3540 } 3541 if (numPoints) *numPoints = tmpSize + 1; 3542 if (points) *points = closure; 3543 PetscFunctionReturn(0); 3544 } 3545 3546 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3547 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3548 { 3549 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3550 const PetscInt *cone, *ornt; 3551 PetscInt *pts, *closure = NULL; 3552 DMPolytopeType ft; 3553 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3554 PetscInt dim, coneSize, c, d, clSize, cl; 3555 3556 PetscFunctionBeginHot; 3557 PetscCall(DMGetDimension(dm, &dim)); 3558 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3559 PetscCall(DMPlexGetCone(dm, point, &cone)); 3560 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3561 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3562 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3563 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3564 maxSize = PetscMax(coneSeries, supportSeries); 3565 if (*points) { 3566 pts = *points; 3567 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3568 c = 0; 3569 pts[c++] = point; 3570 pts[c++] = o; 3571 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3572 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3573 for (cl = 0; cl < clSize * 2; cl += 2) { 3574 pts[c++] = closure[cl]; 3575 pts[c++] = closure[cl + 1]; 3576 } 3577 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3578 for (cl = 0; cl < clSize * 2; cl += 2) { 3579 pts[c++] = closure[cl]; 3580 pts[c++] = closure[cl + 1]; 3581 } 3582 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3583 for (d = 2; d < coneSize; ++d) { 3584 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3585 pts[c++] = cone[arr[d * 2 + 0]]; 3586 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3587 } 3588 if (dim >= 3) { 3589 for (d = 2; d < coneSize; ++d) { 3590 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3591 const PetscInt *fcone, *fornt; 3592 PetscInt fconeSize, fc, i; 3593 3594 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3595 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3596 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3597 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3598 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3599 for (fc = 0; fc < fconeSize; ++fc) { 3600 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3601 const PetscInt co = farr[fc * 2 + 1]; 3602 3603 for (i = 0; i < c; i += 2) 3604 if (pts[i] == cp) break; 3605 if (i == c) { 3606 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3607 pts[c++] = cp; 3608 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3609 } 3610 } 3611 } 3612 } 3613 *numPoints = c / 2; 3614 *points = pts; 3615 PetscFunctionReturn(0); 3616 } 3617 3618 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3619 { 3620 DMPolytopeType ct; 3621 PetscInt *closure, *fifo; 3622 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3623 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3624 PetscInt depth, maxSize; 3625 3626 PetscFunctionBeginHot; 3627 PetscCall(DMPlexGetDepth(dm, &depth)); 3628 if (depth == 1) { 3629 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3630 PetscFunctionReturn(0); 3631 } 3632 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3633 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3634 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3635 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3636 PetscFunctionReturn(0); 3637 } 3638 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3639 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3640 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3641 maxSize = PetscMax(coneSeries, supportSeries); 3642 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3643 if (*points) { 3644 closure = *points; 3645 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3646 closure[closureSize++] = p; 3647 closure[closureSize++] = ornt; 3648 fifo[fifoSize++] = p; 3649 fifo[fifoSize++] = ornt; 3650 fifo[fifoSize++] = ct; 3651 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3652 while (fifoSize - fifoStart) { 3653 const PetscInt q = fifo[fifoStart++]; 3654 const PetscInt o = fifo[fifoStart++]; 3655 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3656 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3657 const PetscInt *tmp, *tmpO; 3658 PetscInt tmpSize, t; 3659 3660 if (PetscDefined(USE_DEBUG)) { 3661 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3662 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); 3663 } 3664 if (useCone) { 3665 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3666 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3667 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3668 } else { 3669 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3670 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3671 tmpO = NULL; 3672 } 3673 for (t = 0; t < tmpSize; ++t) { 3674 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3675 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3676 const PetscInt cp = tmp[ip]; 3677 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3678 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3679 PetscInt c; 3680 3681 /* Check for duplicate */ 3682 for (c = 0; c < closureSize; c += 2) { 3683 if (closure[c] == cp) break; 3684 } 3685 if (c == closureSize) { 3686 closure[closureSize++] = cp; 3687 closure[closureSize++] = co; 3688 fifo[fifoSize++] = cp; 3689 fifo[fifoSize++] = co; 3690 fifo[fifoSize++] = ct; 3691 } 3692 } 3693 } 3694 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3695 if (numPoints) *numPoints = closureSize / 2; 3696 if (points) *points = closure; 3697 PetscFunctionReturn(0); 3698 } 3699 3700 /*@C 3701 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3702 3703 Not Collective 3704 3705 Input Parameters: 3706 + dm - The `DMPLEX` 3707 . p - The mesh point 3708 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3709 3710 Input/Output Parameter: 3711 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3712 if NULL on input, internal storage will be returned, otherwise the provided array is used 3713 3714 Output Parameter: 3715 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3716 3717 Level: beginner 3718 3719 Note: 3720 If using internal storage (points is NULL on input), each call overwrites the last output. 3721 3722 Fortran Note: 3723 The numPoints argument is not present in the Fortran binding since it is internal to the array. 3724 3725 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3726 @*/ 3727 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3728 { 3729 PetscFunctionBeginHot; 3730 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3731 if (numPoints) PetscValidIntPointer(numPoints, 4); 3732 if (points) PetscValidPointer(points, 5); 3733 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3734 PetscFunctionReturn(0); 3735 } 3736 3737 /*@C 3738 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3739 3740 Not Collective 3741 3742 Input Parameters: 3743 + dm - The `DMPLEX` 3744 . p - The mesh point 3745 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3746 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3747 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3748 3749 Level: beginner 3750 3751 Note: 3752 If not using internal storage (points is not NULL on input), this call is unnecessary 3753 3754 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3755 @*/ 3756 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3757 { 3758 PetscFunctionBeginHot; 3759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3760 if (numPoints) *numPoints = 0; 3761 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3762 PetscFunctionReturn(0); 3763 } 3764 3765 /*@ 3766 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3767 3768 Not Collective 3769 3770 Input Parameter: 3771 . mesh - The `DMPLEX` 3772 3773 Output Parameters: 3774 + maxConeSize - The maximum number of in-edges 3775 - maxSupportSize - The maximum number of out-edges 3776 3777 Level: beginner 3778 3779 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3780 @*/ 3781 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3782 { 3783 DM_Plex *mesh = (DM_Plex *)dm->data; 3784 3785 PetscFunctionBegin; 3786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3787 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3788 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3789 PetscFunctionReturn(0); 3790 } 3791 3792 PetscErrorCode DMSetUp_Plex(DM dm) 3793 { 3794 DM_Plex *mesh = (DM_Plex *)dm->data; 3795 PetscInt size, maxSupportSize; 3796 3797 PetscFunctionBegin; 3798 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3799 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3800 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3801 PetscCall(PetscMalloc1(size, &mesh->cones)); 3802 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3803 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3804 if (maxSupportSize) { 3805 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3806 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3807 PetscCall(PetscMalloc1(size, &mesh->supports)); 3808 } 3809 PetscFunctionReturn(0); 3810 } 3811 3812 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3813 { 3814 PetscFunctionBegin; 3815 if (subdm) PetscCall(DMClone(dm, subdm)); 3816 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3817 if (subdm) (*subdm)->useNatural = dm->useNatural; 3818 if (dm->useNatural && dm->sfMigration) { 3819 PetscSF sfNatural; 3820 3821 (*subdm)->sfMigration = dm->sfMigration; 3822 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3823 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3824 (*subdm)->sfNatural = sfNatural; 3825 } 3826 PetscFunctionReturn(0); 3827 } 3828 3829 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3830 { 3831 PetscInt i = 0; 3832 3833 PetscFunctionBegin; 3834 PetscCall(DMClone(dms[0], superdm)); 3835 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3836 (*superdm)->useNatural = PETSC_FALSE; 3837 for (i = 0; i < len; i++) { 3838 if (dms[i]->useNatural && dms[i]->sfMigration) { 3839 PetscSF sfNatural; 3840 3841 (*superdm)->sfMigration = dms[i]->sfMigration; 3842 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3843 (*superdm)->useNatural = PETSC_TRUE; 3844 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3845 (*superdm)->sfNatural = sfNatural; 3846 break; 3847 } 3848 } 3849 PetscFunctionReturn(0); 3850 } 3851 3852 /*@ 3853 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3854 3855 Not Collective 3856 3857 Input Parameter: 3858 . mesh - The `DMPLEX` 3859 3860 Level: beginner 3861 3862 Note: 3863 This should be called after all calls to `DMPlexSetCone()` 3864 3865 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3866 @*/ 3867 PetscErrorCode DMPlexSymmetrize(DM dm) 3868 { 3869 DM_Plex *mesh = (DM_Plex *)dm->data; 3870 PetscInt *offsets; 3871 PetscInt supportSize; 3872 PetscInt pStart, pEnd, p; 3873 3874 PetscFunctionBegin; 3875 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3876 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3877 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3878 /* Calculate support sizes */ 3879 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3880 for (p = pStart; p < pEnd; ++p) { 3881 PetscInt dof, off, c; 3882 3883 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3884 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3885 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3886 } 3887 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3888 /* Calculate supports */ 3889 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3890 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3891 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3892 for (p = pStart; p < pEnd; ++p) { 3893 PetscInt dof, off, c; 3894 3895 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3896 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3897 for (c = off; c < off + dof; ++c) { 3898 const PetscInt q = mesh->cones[c]; 3899 PetscInt offS; 3900 3901 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3902 3903 mesh->supports[offS + offsets[q]] = p; 3904 ++offsets[q]; 3905 } 3906 } 3907 PetscCall(PetscFree(offsets)); 3908 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3909 PetscFunctionReturn(0); 3910 } 3911 3912 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3913 { 3914 IS stratumIS; 3915 3916 PetscFunctionBegin; 3917 if (pStart >= pEnd) PetscFunctionReturn(0); 3918 if (PetscDefined(USE_DEBUG)) { 3919 PetscInt qStart, qEnd, numLevels, level; 3920 PetscBool overlap = PETSC_FALSE; 3921 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3922 for (level = 0; level < numLevels; level++) { 3923 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3924 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 3925 overlap = PETSC_TRUE; 3926 break; 3927 } 3928 } 3929 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); 3930 } 3931 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 3932 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3933 PetscCall(ISDestroy(&stratumIS)); 3934 PetscFunctionReturn(0); 3935 } 3936 3937 /*@ 3938 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3939 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3940 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3941 the DAG. 3942 3943 Collective on dm 3944 3945 Input Parameter: 3946 . mesh - The `DMPLEX` 3947 3948 Level: beginner 3949 3950 Notes: 3951 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3952 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3953 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 3954 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 3955 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 3956 3957 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3958 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3959 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 3960 to interpolate only that one (e0), so that 3961 .vb 3962 cone(c0) = {e0, v2} 3963 cone(e0) = {v0, v1} 3964 .ve 3965 If `DMPlexStratify()` is run on this mesh, it will give depths 3966 .vb 3967 depth 0 = {v0, v1, v2} 3968 depth 1 = {e0, c0} 3969 .ve 3970 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3971 3972 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 3973 3974 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3975 @*/ 3976 PetscErrorCode DMPlexStratify(DM dm) 3977 { 3978 DM_Plex *mesh = (DM_Plex *)dm->data; 3979 DMLabel label; 3980 PetscInt pStart, pEnd, p; 3981 PetscInt numRoots = 0, numLeaves = 0; 3982 3983 PetscFunctionBegin; 3984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3985 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 3986 3987 /* Create depth label */ 3988 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3989 PetscCall(DMCreateLabel(dm, "depth")); 3990 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3991 3992 { 3993 /* Initialize roots and count leaves */ 3994 PetscInt sMin = PETSC_MAX_INT; 3995 PetscInt sMax = PETSC_MIN_INT; 3996 PetscInt coneSize, supportSize; 3997 3998 for (p = pStart; p < pEnd; ++p) { 3999 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4000 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4001 if (!coneSize && supportSize) { 4002 sMin = PetscMin(p, sMin); 4003 sMax = PetscMax(p, sMax); 4004 ++numRoots; 4005 } else if (!supportSize && coneSize) { 4006 ++numLeaves; 4007 } else if (!supportSize && !coneSize) { 4008 /* Isolated points */ 4009 sMin = PetscMin(p, sMin); 4010 sMax = PetscMax(p, sMax); 4011 } 4012 } 4013 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4014 } 4015 4016 if (numRoots + numLeaves == (pEnd - pStart)) { 4017 PetscInt sMin = PETSC_MAX_INT; 4018 PetscInt sMax = PETSC_MIN_INT; 4019 PetscInt coneSize, supportSize; 4020 4021 for (p = pStart; p < pEnd; ++p) { 4022 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4023 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4024 if (!supportSize && coneSize) { 4025 sMin = PetscMin(p, sMin); 4026 sMax = PetscMax(p, sMax); 4027 } 4028 } 4029 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4030 } else { 4031 PetscInt level = 0; 4032 PetscInt qStart, qEnd, q; 4033 4034 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4035 while (qEnd > qStart) { 4036 PetscInt sMin = PETSC_MAX_INT; 4037 PetscInt sMax = PETSC_MIN_INT; 4038 4039 for (q = qStart; q < qEnd; ++q) { 4040 const PetscInt *support; 4041 PetscInt supportSize, s; 4042 4043 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4044 PetscCall(DMPlexGetSupport(dm, q, &support)); 4045 for (s = 0; s < supportSize; ++s) { 4046 sMin = PetscMin(support[s], sMin); 4047 sMax = PetscMax(support[s], sMax); 4048 } 4049 } 4050 PetscCall(DMLabelGetNumValues(label, &level)); 4051 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4052 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4053 } 4054 } 4055 { /* just in case there is an empty process */ 4056 PetscInt numValues, maxValues = 0, v; 4057 4058 PetscCall(DMLabelGetNumValues(label, &numValues)); 4059 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4060 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4061 } 4062 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4063 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4064 PetscFunctionReturn(0); 4065 } 4066 4067 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4068 { 4069 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4070 PetscInt dim, depth, pheight, coneSize; 4071 4072 PetscFunctionBeginHot; 4073 PetscCall(DMGetDimension(dm, &dim)); 4074 PetscCall(DMPlexGetDepth(dm, &depth)); 4075 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4076 pheight = depth - pdepth; 4077 if (depth <= 1) { 4078 switch (pdepth) { 4079 case 0: 4080 ct = DM_POLYTOPE_POINT; 4081 break; 4082 case 1: 4083 switch (coneSize) { 4084 case 2: 4085 ct = DM_POLYTOPE_SEGMENT; 4086 break; 4087 case 3: 4088 ct = DM_POLYTOPE_TRIANGLE; 4089 break; 4090 case 4: 4091 switch (dim) { 4092 case 2: 4093 ct = DM_POLYTOPE_QUADRILATERAL; 4094 break; 4095 case 3: 4096 ct = DM_POLYTOPE_TETRAHEDRON; 4097 break; 4098 default: 4099 break; 4100 } 4101 break; 4102 case 5: 4103 ct = DM_POLYTOPE_PYRAMID; 4104 break; 4105 case 6: 4106 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4107 break; 4108 case 8: 4109 ct = DM_POLYTOPE_HEXAHEDRON; 4110 break; 4111 default: 4112 break; 4113 } 4114 } 4115 } else { 4116 if (pdepth == 0) { 4117 ct = DM_POLYTOPE_POINT; 4118 } else if (pheight == 0) { 4119 switch (dim) { 4120 case 1: 4121 switch (coneSize) { 4122 case 2: 4123 ct = DM_POLYTOPE_SEGMENT; 4124 break; 4125 default: 4126 break; 4127 } 4128 break; 4129 case 2: 4130 switch (coneSize) { 4131 case 3: 4132 ct = DM_POLYTOPE_TRIANGLE; 4133 break; 4134 case 4: 4135 ct = DM_POLYTOPE_QUADRILATERAL; 4136 break; 4137 default: 4138 break; 4139 } 4140 break; 4141 case 3: 4142 switch (coneSize) { 4143 case 4: 4144 ct = DM_POLYTOPE_TETRAHEDRON; 4145 break; 4146 case 5: { 4147 const PetscInt *cone; 4148 PetscInt faceConeSize; 4149 4150 PetscCall(DMPlexGetCone(dm, p, &cone)); 4151 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4152 switch (faceConeSize) { 4153 case 3: 4154 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4155 break; 4156 case 4: 4157 ct = DM_POLYTOPE_PYRAMID; 4158 break; 4159 } 4160 } break; 4161 case 6: 4162 ct = DM_POLYTOPE_HEXAHEDRON; 4163 break; 4164 default: 4165 break; 4166 } 4167 break; 4168 default: 4169 break; 4170 } 4171 } else if (pheight > 0) { 4172 switch (coneSize) { 4173 case 2: 4174 ct = DM_POLYTOPE_SEGMENT; 4175 break; 4176 case 3: 4177 ct = DM_POLYTOPE_TRIANGLE; 4178 break; 4179 case 4: 4180 ct = DM_POLYTOPE_QUADRILATERAL; 4181 break; 4182 default: 4183 break; 4184 } 4185 } 4186 } 4187 *pt = ct; 4188 PetscFunctionReturn(0); 4189 } 4190 4191 /*@ 4192 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4193 4194 Collective on dm 4195 4196 Input Parameter: 4197 . mesh - The `DMPLEX` 4198 4199 Level: developer 4200 4201 Note: 4202 This function is normally called automatically when a cell type is requested. It creates an 4203 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4204 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4205 4206 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4207 4208 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4209 @*/ 4210 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4211 { 4212 DM_Plex *mesh; 4213 DMLabel ctLabel; 4214 PetscInt pStart, pEnd, p; 4215 4216 PetscFunctionBegin; 4217 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4218 mesh = (DM_Plex *)dm->data; 4219 PetscCall(DMCreateLabel(dm, "celltype")); 4220 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4221 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4222 for (p = pStart; p < pEnd; ++p) { 4223 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4224 PetscInt pdepth; 4225 4226 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4227 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4228 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4229 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4230 } 4231 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4232 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4233 PetscFunctionReturn(0); 4234 } 4235 4236 /*@C 4237 DMPlexGetJoin - Get an array for the join of the set of points 4238 4239 Not Collective 4240 4241 Input Parameters: 4242 + dm - The `DMPLEX` object 4243 . numPoints - The number of input points for the join 4244 - points - The input points 4245 4246 Output Parameters: 4247 + numCoveredPoints - The number of points in the join 4248 - coveredPoints - The points in the join 4249 4250 Level: intermediate 4251 4252 Note: 4253 Currently, this is restricted to a single level join 4254 4255 Fortran Note: 4256 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4257 4258 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4259 @*/ 4260 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4261 { 4262 DM_Plex *mesh = (DM_Plex *)dm->data; 4263 PetscInt *join[2]; 4264 PetscInt joinSize, i = 0; 4265 PetscInt dof, off, p, c, m; 4266 PetscInt maxSupportSize; 4267 4268 PetscFunctionBegin; 4269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4270 PetscValidIntPointer(points, 3); 4271 PetscValidIntPointer(numCoveredPoints, 4); 4272 PetscValidPointer(coveredPoints, 5); 4273 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4274 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4275 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4276 /* Copy in support of first point */ 4277 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4278 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4279 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4280 /* Check each successive support */ 4281 for (p = 1; p < numPoints; ++p) { 4282 PetscInt newJoinSize = 0; 4283 4284 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4285 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4286 for (c = 0; c < dof; ++c) { 4287 const PetscInt point = mesh->supports[off + c]; 4288 4289 for (m = 0; m < joinSize; ++m) { 4290 if (point == join[i][m]) { 4291 join[1 - i][newJoinSize++] = point; 4292 break; 4293 } 4294 } 4295 } 4296 joinSize = newJoinSize; 4297 i = 1 - i; 4298 } 4299 *numCoveredPoints = joinSize; 4300 *coveredPoints = join[i]; 4301 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4302 PetscFunctionReturn(0); 4303 } 4304 4305 /*@C 4306 DMPlexRestoreJoin - Restore an array for the join of the set of points 4307 4308 Not Collective 4309 4310 Input Parameters: 4311 + dm - The `DMPLEX` object 4312 . numPoints - The number of input points for the join 4313 - points - The input points 4314 4315 Output Parameters: 4316 + numCoveredPoints - The number of points in the join 4317 - coveredPoints - The points in the join 4318 4319 Level: intermediate 4320 4321 Fortran Note: 4322 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4323 4324 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4325 @*/ 4326 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4327 { 4328 PetscFunctionBegin; 4329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4330 if (points) PetscValidIntPointer(points, 3); 4331 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4332 PetscValidPointer(coveredPoints, 5); 4333 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4334 if (numCoveredPoints) *numCoveredPoints = 0; 4335 PetscFunctionReturn(0); 4336 } 4337 4338 /*@C 4339 DMPlexGetFullJoin - Get an array for the join of the set of points 4340 4341 Not Collective 4342 4343 Input Parameters: 4344 + dm - The `DMPLEX` object 4345 . numPoints - The number of input points for the join 4346 - points - The input points 4347 4348 Output Parameters: 4349 + numCoveredPoints - The number of points in the join 4350 - coveredPoints - The points in the join 4351 4352 Level: intermediate 4353 4354 Fortran Note: 4355 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4356 4357 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4358 @*/ 4359 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4360 { 4361 PetscInt *offsets, **closures; 4362 PetscInt *join[2]; 4363 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4364 PetscInt p, d, c, m, ms; 4365 4366 PetscFunctionBegin; 4367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4368 PetscValidIntPointer(points, 3); 4369 PetscValidIntPointer(numCoveredPoints, 4); 4370 PetscValidPointer(coveredPoints, 5); 4371 4372 PetscCall(DMPlexGetDepth(dm, &depth)); 4373 PetscCall(PetscCalloc1(numPoints, &closures)); 4374 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4375 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4376 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4377 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4378 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4379 4380 for (p = 0; p < numPoints; ++p) { 4381 PetscInt closureSize; 4382 4383 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4384 4385 offsets[p * (depth + 2) + 0] = 0; 4386 for (d = 0; d < depth + 1; ++d) { 4387 PetscInt pStart, pEnd, i; 4388 4389 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4390 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4391 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4392 offsets[p * (depth + 2) + d + 1] = i; 4393 break; 4394 } 4395 } 4396 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4397 } 4398 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); 4399 } 4400 for (d = 0; d < depth + 1; ++d) { 4401 PetscInt dof; 4402 4403 /* Copy in support of first point */ 4404 dof = offsets[d + 1] - offsets[d]; 4405 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4406 /* Check each successive cone */ 4407 for (p = 1; p < numPoints && joinSize; ++p) { 4408 PetscInt newJoinSize = 0; 4409 4410 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4411 for (c = 0; c < dof; ++c) { 4412 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4413 4414 for (m = 0; m < joinSize; ++m) { 4415 if (point == join[i][m]) { 4416 join[1 - i][newJoinSize++] = point; 4417 break; 4418 } 4419 } 4420 } 4421 joinSize = newJoinSize; 4422 i = 1 - i; 4423 } 4424 if (joinSize) break; 4425 } 4426 *numCoveredPoints = joinSize; 4427 *coveredPoints = join[i]; 4428 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4429 PetscCall(PetscFree(closures)); 4430 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4431 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4432 PetscFunctionReturn(0); 4433 } 4434 4435 /*@C 4436 DMPlexGetMeet - Get an array for the meet of the set of points 4437 4438 Not Collective 4439 4440 Input Parameters: 4441 + dm - The `DMPLEX` object 4442 . numPoints - The number of input points for the meet 4443 - points - The input points 4444 4445 Output Parameters: 4446 + numCoveredPoints - The number of points in the meet 4447 - coveredPoints - The points in the meet 4448 4449 Level: intermediate 4450 4451 Note: 4452 Currently, this is restricted to a single level meet 4453 4454 Fortran Notes: 4455 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4456 4457 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4458 @*/ 4459 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4460 { 4461 DM_Plex *mesh = (DM_Plex *)dm->data; 4462 PetscInt *meet[2]; 4463 PetscInt meetSize, i = 0; 4464 PetscInt dof, off, p, c, m; 4465 PetscInt maxConeSize; 4466 4467 PetscFunctionBegin; 4468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4469 PetscValidIntPointer(points, 3); 4470 PetscValidIntPointer(numCoveringPoints, 4); 4471 PetscValidPointer(coveringPoints, 5); 4472 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4473 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4474 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4475 /* Copy in cone of first point */ 4476 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4477 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4478 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4479 /* Check each successive cone */ 4480 for (p = 1; p < numPoints; ++p) { 4481 PetscInt newMeetSize = 0; 4482 4483 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4484 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4485 for (c = 0; c < dof; ++c) { 4486 const PetscInt point = mesh->cones[off + c]; 4487 4488 for (m = 0; m < meetSize; ++m) { 4489 if (point == meet[i][m]) { 4490 meet[1 - i][newMeetSize++] = point; 4491 break; 4492 } 4493 } 4494 } 4495 meetSize = newMeetSize; 4496 i = 1 - i; 4497 } 4498 *numCoveringPoints = meetSize; 4499 *coveringPoints = meet[i]; 4500 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4501 PetscFunctionReturn(0); 4502 } 4503 4504 /*@C 4505 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4506 4507 Not Collective 4508 4509 Input Parameters: 4510 + dm - The `DMPLEX` object 4511 . numPoints - The number of input points for the meet 4512 - points - The input points 4513 4514 Output Parameters: 4515 + numCoveredPoints - The number of points in the meet 4516 - coveredPoints - The points in the meet 4517 4518 Level: intermediate 4519 4520 Fortran Note: 4521 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4522 4523 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4524 @*/ 4525 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4526 { 4527 PetscFunctionBegin; 4528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4529 if (points) PetscValidIntPointer(points, 3); 4530 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4531 PetscValidPointer(coveredPoints, 5); 4532 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4533 if (numCoveredPoints) *numCoveredPoints = 0; 4534 PetscFunctionReturn(0); 4535 } 4536 4537 /*@C 4538 DMPlexGetFullMeet - Get an array for the meet of the set of points 4539 4540 Not Collective 4541 4542 Input Parameters: 4543 + dm - The `DMPLEX` object 4544 . numPoints - The number of input points for the meet 4545 - points - The input points 4546 4547 Output Parameters: 4548 + numCoveredPoints - The number of points in the meet 4549 - coveredPoints - The points in the meet 4550 4551 Level: intermediate 4552 4553 Fortran Note: 4554 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4555 4556 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4557 @*/ 4558 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4559 { 4560 PetscInt *offsets, **closures; 4561 PetscInt *meet[2]; 4562 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4563 PetscInt p, h, c, m, mc; 4564 4565 PetscFunctionBegin; 4566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4567 PetscValidIntPointer(points, 3); 4568 PetscValidIntPointer(numCoveredPoints, 4); 4569 PetscValidPointer(coveredPoints, 5); 4570 4571 PetscCall(DMPlexGetDepth(dm, &height)); 4572 PetscCall(PetscMalloc1(numPoints, &closures)); 4573 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4574 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4575 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4576 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4577 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4578 4579 for (p = 0; p < numPoints; ++p) { 4580 PetscInt closureSize; 4581 4582 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4583 4584 offsets[p * (height + 2) + 0] = 0; 4585 for (h = 0; h < height + 1; ++h) { 4586 PetscInt pStart, pEnd, i; 4587 4588 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4589 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4590 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4591 offsets[p * (height + 2) + h + 1] = i; 4592 break; 4593 } 4594 } 4595 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4596 } 4597 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); 4598 } 4599 for (h = 0; h < height + 1; ++h) { 4600 PetscInt dof; 4601 4602 /* Copy in cone of first point */ 4603 dof = offsets[h + 1] - offsets[h]; 4604 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4605 /* Check each successive cone */ 4606 for (p = 1; p < numPoints && meetSize; ++p) { 4607 PetscInt newMeetSize = 0; 4608 4609 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4610 for (c = 0; c < dof; ++c) { 4611 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4612 4613 for (m = 0; m < meetSize; ++m) { 4614 if (point == meet[i][m]) { 4615 meet[1 - i][newMeetSize++] = point; 4616 break; 4617 } 4618 } 4619 } 4620 meetSize = newMeetSize; 4621 i = 1 - i; 4622 } 4623 if (meetSize) break; 4624 } 4625 *numCoveredPoints = meetSize; 4626 *coveredPoints = meet[i]; 4627 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4628 PetscCall(PetscFree(closures)); 4629 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4630 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4631 PetscFunctionReturn(0); 4632 } 4633 4634 /*@C 4635 DMPlexEqual - Determine if two `DM` have the same topology 4636 4637 Not Collective 4638 4639 Input Parameters: 4640 + dmA - A `DMPLEX` object 4641 - dmB - A `DMPLEX` object 4642 4643 Output Parameters: 4644 . equal - `PETSC_TRUE` if the topologies are identical 4645 4646 Level: intermediate 4647 4648 Note: 4649 We are not solving graph isomorphism, so we do not permute. 4650 4651 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4652 @*/ 4653 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4654 { 4655 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4656 4657 PetscFunctionBegin; 4658 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4659 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4660 PetscValidBoolPointer(equal, 3); 4661 4662 *equal = PETSC_FALSE; 4663 PetscCall(DMPlexGetDepth(dmA, &depth)); 4664 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4665 if (depth != depthB) PetscFunctionReturn(0); 4666 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4667 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4668 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4669 for (p = pStart; p < pEnd; ++p) { 4670 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4671 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4672 4673 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4674 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4675 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4676 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4677 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4678 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4679 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4680 for (c = 0; c < coneSize; ++c) { 4681 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4682 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4683 } 4684 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4685 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4686 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4687 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4688 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4689 for (s = 0; s < supportSize; ++s) { 4690 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4691 } 4692 } 4693 *equal = PETSC_TRUE; 4694 PetscFunctionReturn(0); 4695 } 4696 4697 /*@C 4698 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4699 4700 Not Collective 4701 4702 Input Parameters: 4703 + dm - The `DMPLEX` 4704 . cellDim - The cell dimension 4705 - numCorners - The number of vertices on a cell 4706 4707 Output Parameters: 4708 . numFaceVertices - The number of vertices on a face 4709 4710 Level: developer 4711 4712 Note: 4713 Of course this can only work for a restricted set of symmetric shapes 4714 4715 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4716 @*/ 4717 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4718 { 4719 MPI_Comm comm; 4720 4721 PetscFunctionBegin; 4722 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4723 PetscValidIntPointer(numFaceVertices, 4); 4724 switch (cellDim) { 4725 case 0: 4726 *numFaceVertices = 0; 4727 break; 4728 case 1: 4729 *numFaceVertices = 1; 4730 break; 4731 case 2: 4732 switch (numCorners) { 4733 case 3: /* triangle */ 4734 *numFaceVertices = 2; /* Edge has 2 vertices */ 4735 break; 4736 case 4: /* quadrilateral */ 4737 *numFaceVertices = 2; /* Edge has 2 vertices */ 4738 break; 4739 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4740 *numFaceVertices = 3; /* Edge has 3 vertices */ 4741 break; 4742 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4743 *numFaceVertices = 3; /* Edge has 3 vertices */ 4744 break; 4745 default: 4746 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4747 } 4748 break; 4749 case 3: 4750 switch (numCorners) { 4751 case 4: /* tetradehdron */ 4752 *numFaceVertices = 3; /* Face has 3 vertices */ 4753 break; 4754 case 6: /* tet cohesive cells */ 4755 *numFaceVertices = 4; /* Face has 4 vertices */ 4756 break; 4757 case 8: /* hexahedron */ 4758 *numFaceVertices = 4; /* Face has 4 vertices */ 4759 break; 4760 case 9: /* tet cohesive Lagrange cells */ 4761 *numFaceVertices = 6; /* Face has 6 vertices */ 4762 break; 4763 case 10: /* quadratic tetrahedron */ 4764 *numFaceVertices = 6; /* Face has 6 vertices */ 4765 break; 4766 case 12: /* hex cohesive Lagrange cells */ 4767 *numFaceVertices = 6; /* Face has 6 vertices */ 4768 break; 4769 case 18: /* quadratic tet cohesive Lagrange cells */ 4770 *numFaceVertices = 6; /* Face has 6 vertices */ 4771 break; 4772 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4773 *numFaceVertices = 9; /* Face has 9 vertices */ 4774 break; 4775 default: 4776 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4777 } 4778 break; 4779 default: 4780 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4781 } 4782 PetscFunctionReturn(0); 4783 } 4784 4785 /*@ 4786 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 4787 4788 Not Collective 4789 4790 Input Parameter: 4791 . dm - The `DMPLEX` object 4792 4793 Output Parameter: 4794 . depthLabel - The `DMLabel` recording point depth 4795 4796 Level: developer 4797 4798 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4799 @*/ 4800 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4801 { 4802 PetscFunctionBegin; 4803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4804 PetscValidPointer(depthLabel, 2); 4805 *depthLabel = dm->depthLabel; 4806 PetscFunctionReturn(0); 4807 } 4808 4809 /*@ 4810 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4811 4812 Not Collective 4813 4814 Input Parameter: 4815 . dm - The `DMPLEX` object 4816 4817 Output Parameter: 4818 . depth - The number of strata (breadth first levels) in the DAG 4819 4820 Level: developer 4821 4822 Notes: 4823 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 4824 4825 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 4826 4827 An empty mesh gives -1. 4828 4829 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4830 @*/ 4831 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4832 { 4833 DMLabel label; 4834 PetscInt d = 0; 4835 4836 PetscFunctionBegin; 4837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4838 PetscValidIntPointer(depth, 2); 4839 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4840 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4841 *depth = d - 1; 4842 PetscFunctionReturn(0); 4843 } 4844 4845 /*@ 4846 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4847 4848 Not Collective 4849 4850 Input Parameters: 4851 + dm - The `DMPLEX` object 4852 - depth - The requested depth 4853 4854 Output Parameters: 4855 + start - The first point at this depth 4856 - end - One beyond the last point at this depth 4857 4858 Level: developer 4859 4860 Notes: 4861 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4862 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 4863 higher dimension, e.g., "edges". 4864 4865 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4866 @*/ 4867 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4868 { 4869 DMLabel label; 4870 PetscInt pStart, pEnd; 4871 4872 PetscFunctionBegin; 4873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4874 if (start) { 4875 PetscValidIntPointer(start, 3); 4876 *start = 0; 4877 } 4878 if (end) { 4879 PetscValidIntPointer(end, 4); 4880 *end = 0; 4881 } 4882 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4883 if (pStart == pEnd) PetscFunctionReturn(0); 4884 if (depth < 0) { 4885 if (start) *start = pStart; 4886 if (end) *end = pEnd; 4887 PetscFunctionReturn(0); 4888 } 4889 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4890 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4891 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4892 PetscFunctionReturn(0); 4893 } 4894 4895 /*@ 4896 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4897 4898 Not Collective 4899 4900 Input Parameters: 4901 + dm - The `DMPLEX` object 4902 - height - The requested height 4903 4904 Output Parameters: 4905 + start - The first point at this height 4906 - end - One beyond the last point at this height 4907 4908 Level: developer 4909 4910 Notes: 4911 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4912 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 4913 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4914 4915 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4916 @*/ 4917 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4918 { 4919 DMLabel label; 4920 PetscInt depth, pStart, pEnd; 4921 4922 PetscFunctionBegin; 4923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4924 if (start) { 4925 PetscValidIntPointer(start, 3); 4926 *start = 0; 4927 } 4928 if (end) { 4929 PetscValidIntPointer(end, 4); 4930 *end = 0; 4931 } 4932 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4933 if (pStart == pEnd) PetscFunctionReturn(0); 4934 if (height < 0) { 4935 if (start) *start = pStart; 4936 if (end) *end = pEnd; 4937 PetscFunctionReturn(0); 4938 } 4939 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4940 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4941 PetscCall(DMLabelGetNumValues(label, &depth)); 4942 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 4943 PetscFunctionReturn(0); 4944 } 4945 4946 /*@ 4947 DMPlexGetPointDepth - Get the depth of a given point 4948 4949 Not Collective 4950 4951 Input Parameters: 4952 + dm - The `DMPLEX` object 4953 - point - The point 4954 4955 Output Parameter: 4956 . depth - The depth of the point 4957 4958 Level: intermediate 4959 4960 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4961 @*/ 4962 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4963 { 4964 PetscFunctionBegin; 4965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4966 PetscValidIntPointer(depth, 3); 4967 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4968 PetscFunctionReturn(0); 4969 } 4970 4971 /*@ 4972 DMPlexGetPointHeight - Get the height of a given point 4973 4974 Not Collective 4975 4976 Input Parameters: 4977 + dm - The `DMPLEX` object 4978 - point - The point 4979 4980 Output Parameter: 4981 . height - The height of the point 4982 4983 Level: intermediate 4984 4985 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4986 @*/ 4987 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4988 { 4989 PetscInt n, pDepth; 4990 4991 PetscFunctionBegin; 4992 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4993 PetscValidIntPointer(height, 3); 4994 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4995 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4996 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4997 PetscFunctionReturn(0); 4998 } 4999 5000 /*@ 5001 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5002 5003 Not Collective 5004 5005 Input Parameter: 5006 . dm - The `DMPLEX` object 5007 5008 Output Parameter: 5009 . celltypeLabel - The `DMLabel` recording cell polytope type 5010 5011 Level: developer 5012 5013 Note: 5014 This function will trigger automatica computation of cell types. This can be disabled by calling 5015 `DMCreateLabel`(dm, "celltype") beforehand. 5016 5017 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5018 @*/ 5019 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5020 { 5021 PetscFunctionBegin; 5022 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5023 PetscValidPointer(celltypeLabel, 2); 5024 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5025 *celltypeLabel = dm->celltypeLabel; 5026 PetscFunctionReturn(0); 5027 } 5028 5029 /*@ 5030 DMPlexGetCellType - Get the polytope type of a given cell 5031 5032 Not Collective 5033 5034 Input Parameters: 5035 + dm - The `DMPLEX` object 5036 - cell - The cell 5037 5038 Output Parameter: 5039 . celltype - The polytope type of the cell 5040 5041 Level: intermediate 5042 5043 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5044 @*/ 5045 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5046 { 5047 DMLabel label; 5048 PetscInt ct; 5049 5050 PetscFunctionBegin; 5051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5052 PetscValidPointer(celltype, 3); 5053 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5054 PetscCall(DMLabelGetValue(label, cell, &ct)); 5055 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5056 *celltype = (DMPolytopeType)ct; 5057 PetscFunctionReturn(0); 5058 } 5059 5060 /*@ 5061 DMPlexSetCellType - Set the polytope type of a given cell 5062 5063 Not Collective 5064 5065 Input Parameters: 5066 + dm - The `DMPLEX` object 5067 . cell - The cell 5068 - celltype - The polytope type of the cell 5069 5070 Level: advanced 5071 5072 Note: 5073 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5074 is executed. This function will override the computed type. However, if automatic classification will not succeed 5075 and a user wants to manually specify all types, the classification must be disabled by calling 5076 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5077 5078 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5079 @*/ 5080 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5081 { 5082 DMLabel label; 5083 5084 PetscFunctionBegin; 5085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5086 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5087 PetscCall(DMLabelSetValue(label, cell, celltype)); 5088 PetscFunctionReturn(0); 5089 } 5090 5091 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5092 { 5093 PetscSection section, s; 5094 Mat m; 5095 PetscInt maxHeight; 5096 5097 PetscFunctionBegin; 5098 PetscCall(DMClone(dm, cdm)); 5099 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5100 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5101 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5102 PetscCall(DMSetLocalSection(*cdm, section)); 5103 PetscCall(PetscSectionDestroy(§ion)); 5104 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5105 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5106 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5107 PetscCall(PetscSectionDestroy(&s)); 5108 PetscCall(MatDestroy(&m)); 5109 5110 PetscCall(DMSetNumFields(*cdm, 1)); 5111 PetscCall(DMCreateDS(*cdm)); 5112 PetscFunctionReturn(0); 5113 } 5114 5115 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5116 { 5117 Vec coordsLocal, cellCoordsLocal; 5118 DM coordsDM, cellCoordsDM; 5119 5120 PetscFunctionBegin; 5121 *field = NULL; 5122 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5123 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5124 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5125 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5126 if (coordsLocal && coordsDM) { 5127 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5128 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5129 } 5130 PetscFunctionReturn(0); 5131 } 5132 5133 /*@C 5134 DMPlexGetConeSection - Return a section which describes the layout of cone data 5135 5136 Not Collective 5137 5138 Input Parameters: 5139 . dm - The `DMPLEX` object 5140 5141 Output Parameter: 5142 . section - The `PetscSection` object 5143 5144 Level: developer 5145 5146 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5147 @*/ 5148 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5149 { 5150 DM_Plex *mesh = (DM_Plex *)dm->data; 5151 5152 PetscFunctionBegin; 5153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5154 if (section) *section = mesh->coneSection; 5155 PetscFunctionReturn(0); 5156 } 5157 5158 /*@C 5159 DMPlexGetSupportSection - Return a section which describes the layout of support data 5160 5161 Not Collective 5162 5163 Input Parameters: 5164 . dm - The `DMPLEX` object 5165 5166 Output Parameter: 5167 . section - The `PetscSection` object 5168 5169 Level: developer 5170 5171 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5172 @*/ 5173 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5174 { 5175 DM_Plex *mesh = (DM_Plex *)dm->data; 5176 5177 PetscFunctionBegin; 5178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5179 if (section) *section = mesh->supportSection; 5180 PetscFunctionReturn(0); 5181 } 5182 5183 /*@C 5184 DMPlexGetCones - Return cone data 5185 5186 Not Collective 5187 5188 Input Parameters: 5189 . dm - The `DMPLEX` object 5190 5191 Output Parameter: 5192 . cones - The cone for each point 5193 5194 Level: developer 5195 5196 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5197 @*/ 5198 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5199 { 5200 DM_Plex *mesh = (DM_Plex *)dm->data; 5201 5202 PetscFunctionBegin; 5203 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5204 if (cones) *cones = mesh->cones; 5205 PetscFunctionReturn(0); 5206 } 5207 5208 /*@C 5209 DMPlexGetConeOrientations - Return cone orientation data 5210 5211 Not Collective 5212 5213 Input Parameters: 5214 . dm - The `DMPLEX` object 5215 5216 Output Parameter: 5217 . coneOrientations - The array of cone orientations for all points 5218 5219 Level: developer 5220 5221 Notes: 5222 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5223 5224 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5225 5226 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5227 @*/ 5228 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5229 { 5230 DM_Plex *mesh = (DM_Plex *)dm->data; 5231 5232 PetscFunctionBegin; 5233 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5234 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5235 PetscFunctionReturn(0); 5236 } 5237 5238 /******************************** FEM Support **********************************/ 5239 5240 /* 5241 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5242 representing a line in the section. 5243 */ 5244 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5245 { 5246 PetscFunctionBeginHot; 5247 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5248 if (line < 0) { 5249 *k = 0; 5250 *Nc = 0; 5251 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5252 *k = 1; 5253 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5254 /* An order k SEM disc has k-1 dofs on an edge */ 5255 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5256 *k = *k / *Nc + 1; 5257 } 5258 PetscFunctionReturn(0); 5259 } 5260 5261 /*@ 5262 5263 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5264 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5265 section provided (or the section of the DM). 5266 5267 Input Parameters: 5268 + dm - The DM 5269 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5270 - section - The PetscSection to reorder, or NULL for the default section 5271 5272 Example: 5273 A typical interpolated single-quad mesh might order points as 5274 .vb 5275 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5276 5277 v4 -- e6 -- v3 5278 | | 5279 e7 c0 e8 5280 | | 5281 v1 -- e5 -- v2 5282 .ve 5283 5284 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5285 dofs in the order of points, e.g., 5286 .vb 5287 c0 -> [0,1,2,3] 5288 v1 -> [4] 5289 ... 5290 e5 -> [8, 9] 5291 .ve 5292 5293 which corresponds to the dofs 5294 .vb 5295 6 10 11 7 5296 13 2 3 15 5297 12 0 1 14 5298 4 8 9 5 5299 .ve 5300 5301 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5302 .vb 5303 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5304 .ve 5305 5306 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5307 .vb 5308 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5309 .ve 5310 5311 Level: developer 5312 5313 Note: 5314 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5315 degree of the basis. 5316 5317 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5318 @*/ 5319 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5320 { 5321 DMLabel label; 5322 PetscInt dim, depth = -1, eStart = -1, Nf; 5323 PetscBool vertexchart; 5324 5325 PetscFunctionBegin; 5326 PetscCall(DMGetDimension(dm, &dim)); 5327 if (dim < 1) PetscFunctionReturn(0); 5328 if (point < 0) { 5329 PetscInt sStart, sEnd; 5330 5331 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5332 point = sEnd - sStart ? sStart : point; 5333 } 5334 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5335 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5336 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5337 if (depth == 1) { 5338 eStart = point; 5339 } else if (depth == dim) { 5340 const PetscInt *cone; 5341 5342 PetscCall(DMPlexGetCone(dm, point, &cone)); 5343 if (dim == 2) eStart = cone[0]; 5344 else if (dim == 3) { 5345 const PetscInt *cone2; 5346 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5347 eStart = cone2[0]; 5348 } 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); 5349 } 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); 5350 { /* Determine whether the chart covers all points or just vertices. */ 5351 PetscInt pStart, pEnd, cStart, cEnd; 5352 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5353 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5354 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5355 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5356 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5357 } 5358 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5359 for (PetscInt d = 1; d <= dim; d++) { 5360 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5361 PetscInt *perm; 5362 5363 for (f = 0; f < Nf; ++f) { 5364 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5365 size += PetscPowInt(k + 1, d) * Nc; 5366 } 5367 PetscCall(PetscMalloc1(size, &perm)); 5368 for (f = 0; f < Nf; ++f) { 5369 switch (d) { 5370 case 1: 5371 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5372 /* 5373 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5374 We want [ vtx0; edge of length k-1; vtx1 ] 5375 */ 5376 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5377 for (i = 0; i < k - 1; i++) 5378 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5379 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5380 foffset = offset; 5381 break; 5382 case 2: 5383 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5384 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5385 /* The SEM order is 5386 5387 v_lb, {e_b}, v_rb, 5388 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5389 v_lt, reverse {e_t}, v_rt 5390 */ 5391 { 5392 const PetscInt of = 0; 5393 const PetscInt oeb = of + PetscSqr(k - 1); 5394 const PetscInt oer = oeb + (k - 1); 5395 const PetscInt oet = oer + (k - 1); 5396 const PetscInt oel = oet + (k - 1); 5397 const PetscInt ovlb = oel + (k - 1); 5398 const PetscInt ovrb = ovlb + 1; 5399 const PetscInt ovrt = ovrb + 1; 5400 const PetscInt ovlt = ovrt + 1; 5401 PetscInt o; 5402 5403 /* bottom */ 5404 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5405 for (o = oeb; o < oer; ++o) 5406 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5407 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5408 /* middle */ 5409 for (i = 0; i < k - 1; ++i) { 5410 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5411 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5412 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5414 } 5415 /* top */ 5416 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5417 for (o = oel - 1; o >= oet; --o) 5418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5419 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5420 foffset = offset; 5421 } 5422 break; 5423 case 3: 5424 /* The original hex closure is 5425 5426 {c, 5427 f_b, f_t, f_f, f_b, f_r, f_l, 5428 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5429 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5430 */ 5431 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5432 /* The SEM order is 5433 Bottom Slice 5434 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5435 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5436 v_blb, {e_bb}, v_brb, 5437 5438 Middle Slice (j) 5439 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5440 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5441 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5442 5443 Top Slice 5444 v_tlf, {e_tf}, v_trf, 5445 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5446 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5447 */ 5448 { 5449 const PetscInt oc = 0; 5450 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5451 const PetscInt oft = ofb + PetscSqr(k - 1); 5452 const PetscInt off = oft + PetscSqr(k - 1); 5453 const PetscInt ofk = off + PetscSqr(k - 1); 5454 const PetscInt ofr = ofk + PetscSqr(k - 1); 5455 const PetscInt ofl = ofr + PetscSqr(k - 1); 5456 const PetscInt oebl = ofl + PetscSqr(k - 1); 5457 const PetscInt oebb = oebl + (k - 1); 5458 const PetscInt oebr = oebb + (k - 1); 5459 const PetscInt oebf = oebr + (k - 1); 5460 const PetscInt oetf = oebf + (k - 1); 5461 const PetscInt oetr = oetf + (k - 1); 5462 const PetscInt oetb = oetr + (k - 1); 5463 const PetscInt oetl = oetb + (k - 1); 5464 const PetscInt oerf = oetl + (k - 1); 5465 const PetscInt oelf = oerf + (k - 1); 5466 const PetscInt oelb = oelf + (k - 1); 5467 const PetscInt oerb = oelb + (k - 1); 5468 const PetscInt ovblf = oerb + (k - 1); 5469 const PetscInt ovblb = ovblf + 1; 5470 const PetscInt ovbrb = ovblb + 1; 5471 const PetscInt ovbrf = ovbrb + 1; 5472 const PetscInt ovtlf = ovbrf + 1; 5473 const PetscInt ovtrf = ovtlf + 1; 5474 const PetscInt ovtrb = ovtrf + 1; 5475 const PetscInt ovtlb = ovtrb + 1; 5476 PetscInt o, n; 5477 5478 /* Bottom Slice */ 5479 /* bottom */ 5480 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5481 for (o = oetf - 1; o >= oebf; --o) 5482 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5483 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5484 /* middle */ 5485 for (i = 0; i < k - 1; ++i) { 5486 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5487 for (n = 0; n < k - 1; ++n) { 5488 o = ofb + n * (k - 1) + i; 5489 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5490 } 5491 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5492 } 5493 /* top */ 5494 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5495 for (o = oebb; o < oebr; ++o) 5496 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5497 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5498 5499 /* Middle Slice */ 5500 for (j = 0; j < k - 1; ++j) { 5501 /* bottom */ 5502 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5503 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5504 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5505 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5506 /* middle */ 5507 for (i = 0; i < k - 1; ++i) { 5508 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5509 for (n = 0; n < k - 1; ++n) 5510 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5511 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5512 } 5513 /* top */ 5514 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5515 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5516 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5517 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5518 } 5519 5520 /* Top Slice */ 5521 /* bottom */ 5522 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5523 for (o = oetf; o < oetr; ++o) 5524 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5525 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5526 /* middle */ 5527 for (i = 0; i < k - 1; ++i) { 5528 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5529 for (n = 0; n < k - 1; ++n) 5530 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5531 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5532 } 5533 /* top */ 5534 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5535 for (o = oetl - 1; o >= oetb; --o) 5536 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5537 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5538 5539 foffset = offset; 5540 } 5541 break; 5542 default: 5543 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5544 } 5545 } 5546 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5547 /* Check permutation */ 5548 { 5549 PetscInt *check; 5550 5551 PetscCall(PetscMalloc1(size, &check)); 5552 for (i = 0; i < size; ++i) { 5553 check[i] = -1; 5554 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5555 } 5556 for (i = 0; i < size; ++i) check[perm[i]] = i; 5557 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5558 PetscCall(PetscFree(check)); 5559 } 5560 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5561 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5562 PetscInt *loc_perm; 5563 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5564 for (PetscInt i = 0; i < size; i++) { 5565 loc_perm[i] = perm[i]; 5566 loc_perm[size + i] = size + perm[i]; 5567 } 5568 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5569 } 5570 } 5571 PetscFunctionReturn(0); 5572 } 5573 5574 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5575 { 5576 PetscDS prob; 5577 PetscInt depth, Nf, h; 5578 DMLabel label; 5579 5580 PetscFunctionBeginHot; 5581 PetscCall(DMGetDS(dm, &prob)); 5582 Nf = prob->Nf; 5583 label = dm->depthLabel; 5584 *dspace = NULL; 5585 if (field < Nf) { 5586 PetscObject disc = prob->disc[field]; 5587 5588 if (disc->classid == PETSCFE_CLASSID) { 5589 PetscDualSpace dsp; 5590 5591 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5592 PetscCall(DMLabelGetNumValues(label, &depth)); 5593 PetscCall(DMLabelGetValue(label, point, &h)); 5594 h = depth - 1 - h; 5595 if (h) { 5596 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5597 } else { 5598 *dspace = dsp; 5599 } 5600 } 5601 } 5602 PetscFunctionReturn(0); 5603 } 5604 5605 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5606 { 5607 PetscScalar *array; 5608 const PetscScalar *vArray; 5609 const PetscInt *cone, *coneO; 5610 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5611 5612 PetscFunctionBeginHot; 5613 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5614 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5615 PetscCall(DMPlexGetCone(dm, point, &cone)); 5616 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5617 if (!values || !*values) { 5618 if ((point >= pStart) && (point < pEnd)) { 5619 PetscInt dof; 5620 5621 PetscCall(PetscSectionGetDof(section, point, &dof)); 5622 size += dof; 5623 } 5624 for (p = 0; p < numPoints; ++p) { 5625 const PetscInt cp = cone[p]; 5626 PetscInt dof; 5627 5628 if ((cp < pStart) || (cp >= pEnd)) continue; 5629 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5630 size += dof; 5631 } 5632 if (!values) { 5633 if (csize) *csize = size; 5634 PetscFunctionReturn(0); 5635 } 5636 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5637 } else { 5638 array = *values; 5639 } 5640 size = 0; 5641 PetscCall(VecGetArrayRead(v, &vArray)); 5642 if ((point >= pStart) && (point < pEnd)) { 5643 PetscInt dof, off, d; 5644 const PetscScalar *varr; 5645 5646 PetscCall(PetscSectionGetDof(section, point, &dof)); 5647 PetscCall(PetscSectionGetOffset(section, point, &off)); 5648 varr = &vArray[off]; 5649 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5650 size += dof; 5651 } 5652 for (p = 0; p < numPoints; ++p) { 5653 const PetscInt cp = cone[p]; 5654 PetscInt o = coneO[p]; 5655 PetscInt dof, off, d; 5656 const PetscScalar *varr; 5657 5658 if ((cp < pStart) || (cp >= pEnd)) continue; 5659 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5660 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5661 varr = &vArray[off]; 5662 if (o >= 0) { 5663 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5664 } else { 5665 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5666 } 5667 size += dof; 5668 } 5669 PetscCall(VecRestoreArrayRead(v, &vArray)); 5670 if (!*values) { 5671 if (csize) *csize = size; 5672 *values = array; 5673 } else { 5674 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5675 *csize = size; 5676 } 5677 PetscFunctionReturn(0); 5678 } 5679 5680 /* Compress out points not in the section */ 5681 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5682 { 5683 const PetscInt np = *numPoints; 5684 PetscInt pStart, pEnd, p, q; 5685 5686 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5687 for (p = 0, q = 0; p < np; ++p) { 5688 const PetscInt r = points[p * 2]; 5689 if ((r >= pStart) && (r < pEnd)) { 5690 points[q * 2] = r; 5691 points[q * 2 + 1] = points[p * 2 + 1]; 5692 ++q; 5693 } 5694 } 5695 *numPoints = q; 5696 return 0; 5697 } 5698 5699 /* Compressed closure does not apply closure permutation */ 5700 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5701 { 5702 const PetscInt *cla = NULL; 5703 PetscInt np, *pts = NULL; 5704 5705 PetscFunctionBeginHot; 5706 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5707 if (*clPoints) { 5708 PetscInt dof, off; 5709 5710 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5711 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5712 PetscCall(ISGetIndices(*clPoints, &cla)); 5713 np = dof / 2; 5714 pts = (PetscInt *)&cla[off]; 5715 } else { 5716 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5717 PetscCall(CompressPoints_Private(section, &np, pts)); 5718 } 5719 *numPoints = np; 5720 *points = pts; 5721 *clp = cla; 5722 PetscFunctionReturn(0); 5723 } 5724 5725 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5726 { 5727 PetscFunctionBeginHot; 5728 if (!*clPoints) { 5729 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5730 } else { 5731 PetscCall(ISRestoreIndices(*clPoints, clp)); 5732 } 5733 *numPoints = 0; 5734 *points = NULL; 5735 *clSec = NULL; 5736 *clPoints = NULL; 5737 *clp = NULL; 5738 PetscFunctionReturn(0); 5739 } 5740 5741 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5742 { 5743 PetscInt offset = 0, p; 5744 const PetscInt **perms = NULL; 5745 const PetscScalar **flips = NULL; 5746 5747 PetscFunctionBeginHot; 5748 *size = 0; 5749 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5750 for (p = 0; p < numPoints; p++) { 5751 const PetscInt point = points[2 * p]; 5752 const PetscInt *perm = perms ? perms[p] : NULL; 5753 const PetscScalar *flip = flips ? flips[p] : NULL; 5754 PetscInt dof, off, d; 5755 const PetscScalar *varr; 5756 5757 PetscCall(PetscSectionGetDof(section, point, &dof)); 5758 PetscCall(PetscSectionGetOffset(section, point, &off)); 5759 varr = &vArray[off]; 5760 if (clperm) { 5761 if (perm) { 5762 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5763 } else { 5764 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5765 } 5766 if (flip) { 5767 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5768 } 5769 } else { 5770 if (perm) { 5771 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5772 } else { 5773 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5774 } 5775 if (flip) { 5776 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5777 } 5778 } 5779 offset += dof; 5780 } 5781 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5782 *size = offset; 5783 PetscFunctionReturn(0); 5784 } 5785 5786 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[]) 5787 { 5788 PetscInt offset = 0, f; 5789 5790 PetscFunctionBeginHot; 5791 *size = 0; 5792 for (f = 0; f < numFields; ++f) { 5793 PetscInt p; 5794 const PetscInt **perms = NULL; 5795 const PetscScalar **flips = NULL; 5796 5797 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5798 for (p = 0; p < numPoints; p++) { 5799 const PetscInt point = points[2 * p]; 5800 PetscInt fdof, foff, b; 5801 const PetscScalar *varr; 5802 const PetscInt *perm = perms ? perms[p] : NULL; 5803 const PetscScalar *flip = flips ? flips[p] : NULL; 5804 5805 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5806 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5807 varr = &vArray[foff]; 5808 if (clperm) { 5809 if (perm) { 5810 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5811 } else { 5812 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5813 } 5814 if (flip) { 5815 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5816 } 5817 } else { 5818 if (perm) { 5819 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5820 } else { 5821 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5822 } 5823 if (flip) { 5824 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5825 } 5826 } 5827 offset += fdof; 5828 } 5829 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5830 } 5831 *size = offset; 5832 PetscFunctionReturn(0); 5833 } 5834 5835 /*@C 5836 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5837 5838 Not collective 5839 5840 Input Parameters: 5841 + dm - The `DM` 5842 . section - The section describing the layout in v, or NULL to use the default section 5843 . v - The local vector 5844 - point - The point in the `DM` 5845 5846 Input/Output Parameters: 5847 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5848 - values - An array to use for the values, or NULL to have it allocated automatically; 5849 if the user provided NULL, it is a borrowed array and should not be freed 5850 5851 5852 Level: intermediate 5853 5854 Notes: 5855 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to NULL in the 5856 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 5857 assembly function, and a user may already have allocated storage for this operation. 5858 5859 A typical use could be 5860 .vb 5861 values = NULL; 5862 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5863 for (cl = 0; cl < clSize; ++cl) { 5864 <Compute on closure> 5865 } 5866 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5867 .ve 5868 or 5869 .vb 5870 PetscMalloc1(clMaxSize, &values); 5871 for (p = pStart; p < pEnd; ++p) { 5872 clSize = clMaxSize; 5873 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5874 for (cl = 0; cl < clSize; ++cl) { 5875 <Compute on closure> 5876 } 5877 } 5878 PetscFree(values); 5879 .ve 5880 5881 Fortran Note: 5882 The csize argument is not present in the Fortran binding since it is internal to the array. 5883 5884 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5885 @*/ 5886 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5887 { 5888 PetscSection clSection; 5889 IS clPoints; 5890 PetscInt *points = NULL; 5891 const PetscInt *clp, *perm; 5892 PetscInt depth, numFields, numPoints, asize; 5893 5894 PetscFunctionBeginHot; 5895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5896 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5897 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5898 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5899 PetscCall(DMPlexGetDepth(dm, &depth)); 5900 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5901 if (depth == 1 && numFields < 2) { 5902 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5903 PetscFunctionReturn(0); 5904 } 5905 /* Get points */ 5906 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5907 /* Get sizes */ 5908 asize = 0; 5909 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5910 PetscInt dof; 5911 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5912 asize += dof; 5913 } 5914 if (values) { 5915 const PetscScalar *vArray; 5916 PetscInt size; 5917 5918 if (*values) { 5919 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); 5920 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5921 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5922 PetscCall(VecGetArrayRead(v, &vArray)); 5923 /* Get values */ 5924 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5925 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5926 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5927 /* Cleanup array */ 5928 PetscCall(VecRestoreArrayRead(v, &vArray)); 5929 } 5930 if (csize) *csize = asize; 5931 /* Cleanup points */ 5932 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5933 PetscFunctionReturn(0); 5934 } 5935 5936 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5937 { 5938 DMLabel depthLabel; 5939 PetscSection clSection; 5940 IS clPoints; 5941 PetscScalar *array; 5942 const PetscScalar *vArray; 5943 PetscInt *points = NULL; 5944 const PetscInt *clp, *perm = NULL; 5945 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5946 5947 PetscFunctionBeginHot; 5948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5949 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5950 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5951 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5952 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5953 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5954 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5955 if (mdepth == 1 && numFields < 2) { 5956 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5957 PetscFunctionReturn(0); 5958 } 5959 /* Get points */ 5960 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5961 for (clsize = 0, p = 0; p < Np; p++) { 5962 PetscInt dof; 5963 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 5964 clsize += dof; 5965 } 5966 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 5967 /* Filter points */ 5968 for (p = 0; p < numPoints * 2; p += 2) { 5969 PetscInt dep; 5970 5971 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5972 if (dep != depth) continue; 5973 points[Np * 2 + 0] = points[p]; 5974 points[Np * 2 + 1] = points[p + 1]; 5975 ++Np; 5976 } 5977 /* Get array */ 5978 if (!values || !*values) { 5979 PetscInt asize = 0, dof; 5980 5981 for (p = 0; p < Np * 2; p += 2) { 5982 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5983 asize += dof; 5984 } 5985 if (!values) { 5986 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5987 if (csize) *csize = asize; 5988 PetscFunctionReturn(0); 5989 } 5990 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5991 } else { 5992 array = *values; 5993 } 5994 PetscCall(VecGetArrayRead(v, &vArray)); 5995 /* Get values */ 5996 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5997 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5998 /* Cleanup points */ 5999 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6000 /* Cleanup array */ 6001 PetscCall(VecRestoreArrayRead(v, &vArray)); 6002 if (!*values) { 6003 if (csize) *csize = size; 6004 *values = array; 6005 } else { 6006 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6007 *csize = size; 6008 } 6009 PetscFunctionReturn(0); 6010 } 6011 6012 /*@C 6013 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6014 6015 Not collective 6016 6017 Input Parameters: 6018 + dm - The `DM` 6019 . section - The section describing the layout in v, or NULL to use the default section 6020 . v - The local vector 6021 . point - The point in the `DM` 6022 . csize - The number of values in the closure, or NULL 6023 - values - The array of values, which is a borrowed array and should not be freed 6024 6025 Level: intermediate 6026 6027 Note: 6028 The array values are discarded and not copied back into v. In order to copy values back to v, use `DMPlexVecSetClosure()` 6029 6030 Fortran Note: 6031 The csize argument is not present in the Fortran binding since it is internal to the array. 6032 6033 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6034 @*/ 6035 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6036 { 6037 PetscInt size = 0; 6038 6039 PetscFunctionBegin; 6040 /* Should work without recalculating size */ 6041 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6042 *values = NULL; 6043 PetscFunctionReturn(0); 6044 } 6045 6046 static inline void add(PetscScalar *x, PetscScalar y) 6047 { 6048 *x += y; 6049 } 6050 static inline void insert(PetscScalar *x, PetscScalar y) 6051 { 6052 *x = y; 6053 } 6054 6055 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[]) 6056 { 6057 PetscInt cdof; /* The number of constraints on this point */ 6058 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6059 PetscScalar *a; 6060 PetscInt off, cind = 0, k; 6061 6062 PetscFunctionBegin; 6063 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6064 PetscCall(PetscSectionGetOffset(section, point, &off)); 6065 a = &array[off]; 6066 if (!cdof || setBC) { 6067 if (clperm) { 6068 if (perm) { 6069 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6070 } else { 6071 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6072 } 6073 } else { 6074 if (perm) { 6075 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6076 } else { 6077 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6078 } 6079 } 6080 } else { 6081 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6082 if (clperm) { 6083 if (perm) { 6084 for (k = 0; k < dof; ++k) { 6085 if ((cind < cdof) && (k == cdofs[cind])) { 6086 ++cind; 6087 continue; 6088 } 6089 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6090 } 6091 } else { 6092 for (k = 0; k < dof; ++k) { 6093 if ((cind < cdof) && (k == cdofs[cind])) { 6094 ++cind; 6095 continue; 6096 } 6097 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6098 } 6099 } 6100 } else { 6101 if (perm) { 6102 for (k = 0; k < dof; ++k) { 6103 if ((cind < cdof) && (k == cdofs[cind])) { 6104 ++cind; 6105 continue; 6106 } 6107 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6108 } 6109 } else { 6110 for (k = 0; k < dof; ++k) { 6111 if ((cind < cdof) && (k == cdofs[cind])) { 6112 ++cind; 6113 continue; 6114 } 6115 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6116 } 6117 } 6118 } 6119 } 6120 PetscFunctionReturn(0); 6121 } 6122 6123 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[]) 6124 { 6125 PetscInt cdof; /* The number of constraints on this point */ 6126 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6127 PetscScalar *a; 6128 PetscInt off, cind = 0, k; 6129 6130 PetscFunctionBegin; 6131 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6132 PetscCall(PetscSectionGetOffset(section, point, &off)); 6133 a = &array[off]; 6134 if (cdof) { 6135 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6136 if (clperm) { 6137 if (perm) { 6138 for (k = 0; k < dof; ++k) { 6139 if ((cind < cdof) && (k == cdofs[cind])) { 6140 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6141 cind++; 6142 } 6143 } 6144 } else { 6145 for (k = 0; k < dof; ++k) { 6146 if ((cind < cdof) && (k == cdofs[cind])) { 6147 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6148 cind++; 6149 } 6150 } 6151 } 6152 } else { 6153 if (perm) { 6154 for (k = 0; k < dof; ++k) { 6155 if ((cind < cdof) && (k == cdofs[cind])) { 6156 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6157 cind++; 6158 } 6159 } 6160 } else { 6161 for (k = 0; k < dof; ++k) { 6162 if ((cind < cdof) && (k == cdofs[cind])) { 6163 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6164 cind++; 6165 } 6166 } 6167 } 6168 } 6169 } 6170 PetscFunctionReturn(0); 6171 } 6172 6173 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[]) 6174 { 6175 PetscScalar *a; 6176 PetscInt fdof, foff, fcdof, foffset = *offset; 6177 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6178 PetscInt cind = 0, b; 6179 6180 PetscFunctionBegin; 6181 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6182 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6183 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6184 a = &array[foff]; 6185 if (!fcdof || setBC) { 6186 if (clperm) { 6187 if (perm) { 6188 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6189 } else { 6190 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6191 } 6192 } else { 6193 if (perm) { 6194 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6195 } else { 6196 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6197 } 6198 } 6199 } else { 6200 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6201 if (clperm) { 6202 if (perm) { 6203 for (b = 0; b < fdof; b++) { 6204 if ((cind < fcdof) && (b == fcdofs[cind])) { 6205 ++cind; 6206 continue; 6207 } 6208 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6209 } 6210 } else { 6211 for (b = 0; b < fdof; b++) { 6212 if ((cind < fcdof) && (b == fcdofs[cind])) { 6213 ++cind; 6214 continue; 6215 } 6216 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6217 } 6218 } 6219 } else { 6220 if (perm) { 6221 for (b = 0; b < fdof; b++) { 6222 if ((cind < fcdof) && (b == fcdofs[cind])) { 6223 ++cind; 6224 continue; 6225 } 6226 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6227 } 6228 } else { 6229 for (b = 0; b < fdof; b++) { 6230 if ((cind < fcdof) && (b == fcdofs[cind])) { 6231 ++cind; 6232 continue; 6233 } 6234 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6235 } 6236 } 6237 } 6238 } 6239 *offset += fdof; 6240 PetscFunctionReturn(0); 6241 } 6242 6243 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[]) 6244 { 6245 PetscScalar *a; 6246 PetscInt fdof, foff, fcdof, foffset = *offset; 6247 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6248 PetscInt Nc, cind = 0, ncind = 0, b; 6249 PetscBool ncSet, fcSet; 6250 6251 PetscFunctionBegin; 6252 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6253 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6254 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6255 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6256 a = &array[foff]; 6257 if (fcdof) { 6258 /* We just override fcdof and fcdofs with Ncc and comps */ 6259 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6260 if (clperm) { 6261 if (perm) { 6262 if (comps) { 6263 for (b = 0; b < fdof; b++) { 6264 ncSet = fcSet = PETSC_FALSE; 6265 if (b % Nc == comps[ncind]) { 6266 ncind = (ncind + 1) % Ncc; 6267 ncSet = PETSC_TRUE; 6268 } 6269 if ((cind < fcdof) && (b == fcdofs[cind])) { 6270 ++cind; 6271 fcSet = PETSC_TRUE; 6272 } 6273 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6274 } 6275 } else { 6276 for (b = 0; b < fdof; b++) { 6277 if ((cind < fcdof) && (b == fcdofs[cind])) { 6278 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6279 ++cind; 6280 } 6281 } 6282 } 6283 } else { 6284 if (comps) { 6285 for (b = 0; b < fdof; b++) { 6286 ncSet = fcSet = PETSC_FALSE; 6287 if (b % Nc == comps[ncind]) { 6288 ncind = (ncind + 1) % Ncc; 6289 ncSet = PETSC_TRUE; 6290 } 6291 if ((cind < fcdof) && (b == fcdofs[cind])) { 6292 ++cind; 6293 fcSet = PETSC_TRUE; 6294 } 6295 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6296 } 6297 } else { 6298 for (b = 0; b < fdof; b++) { 6299 if ((cind < fcdof) && (b == fcdofs[cind])) { 6300 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6301 ++cind; 6302 } 6303 } 6304 } 6305 } 6306 } else { 6307 if (perm) { 6308 if (comps) { 6309 for (b = 0; b < fdof; b++) { 6310 ncSet = fcSet = PETSC_FALSE; 6311 if (b % Nc == comps[ncind]) { 6312 ncind = (ncind + 1) % Ncc; 6313 ncSet = PETSC_TRUE; 6314 } 6315 if ((cind < fcdof) && (b == fcdofs[cind])) { 6316 ++cind; 6317 fcSet = PETSC_TRUE; 6318 } 6319 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6320 } 6321 } else { 6322 for (b = 0; b < fdof; b++) { 6323 if ((cind < fcdof) && (b == fcdofs[cind])) { 6324 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6325 ++cind; 6326 } 6327 } 6328 } 6329 } else { 6330 if (comps) { 6331 for (b = 0; b < fdof; b++) { 6332 ncSet = fcSet = PETSC_FALSE; 6333 if (b % Nc == comps[ncind]) { 6334 ncind = (ncind + 1) % Ncc; 6335 ncSet = PETSC_TRUE; 6336 } 6337 if ((cind < fcdof) && (b == fcdofs[cind])) { 6338 ++cind; 6339 fcSet = PETSC_TRUE; 6340 } 6341 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6342 } 6343 } else { 6344 for (b = 0; b < fdof; b++) { 6345 if ((cind < fcdof) && (b == fcdofs[cind])) { 6346 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6347 ++cind; 6348 } 6349 } 6350 } 6351 } 6352 } 6353 } 6354 *offset += fdof; 6355 PetscFunctionReturn(0); 6356 } 6357 6358 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6359 { 6360 PetscScalar *array; 6361 const PetscInt *cone, *coneO; 6362 PetscInt pStart, pEnd, p, numPoints, off, dof; 6363 6364 PetscFunctionBeginHot; 6365 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6366 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6367 PetscCall(DMPlexGetCone(dm, point, &cone)); 6368 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6369 PetscCall(VecGetArray(v, &array)); 6370 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6371 const PetscInt cp = !p ? point : cone[p - 1]; 6372 const PetscInt o = !p ? 0 : coneO[p - 1]; 6373 6374 if ((cp < pStart) || (cp >= pEnd)) { 6375 dof = 0; 6376 continue; 6377 } 6378 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6379 /* ADD_VALUES */ 6380 { 6381 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6382 PetscScalar *a; 6383 PetscInt cdof, coff, cind = 0, k; 6384 6385 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6386 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6387 a = &array[coff]; 6388 if (!cdof) { 6389 if (o >= 0) { 6390 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6391 } else { 6392 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6393 } 6394 } else { 6395 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6396 if (o >= 0) { 6397 for (k = 0; k < dof; ++k) { 6398 if ((cind < cdof) && (k == cdofs[cind])) { 6399 ++cind; 6400 continue; 6401 } 6402 a[k] += values[off + k]; 6403 } 6404 } else { 6405 for (k = 0; k < dof; ++k) { 6406 if ((cind < cdof) && (k == cdofs[cind])) { 6407 ++cind; 6408 continue; 6409 } 6410 a[k] += values[off + dof - k - 1]; 6411 } 6412 } 6413 } 6414 } 6415 } 6416 PetscCall(VecRestoreArray(v, &array)); 6417 PetscFunctionReturn(0); 6418 } 6419 6420 /*@C 6421 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6422 6423 Not collective 6424 6425 Input Parameters: 6426 + dm - The `DM` 6427 . section - The section describing the layout in v, or NULL to use the default section 6428 . v - The local vector 6429 . point - The point in the DM 6430 . values - The array of values 6431 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6432 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6433 6434 Level: intermediate 6435 6436 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6437 @*/ 6438 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6439 { 6440 PetscSection clSection; 6441 IS clPoints; 6442 PetscScalar *array; 6443 PetscInt *points = NULL; 6444 const PetscInt *clp, *clperm = NULL; 6445 PetscInt depth, numFields, numPoints, p, clsize; 6446 6447 PetscFunctionBeginHot; 6448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6449 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6450 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6451 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6452 PetscCall(DMPlexGetDepth(dm, &depth)); 6453 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6454 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6455 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6456 PetscFunctionReturn(0); 6457 } 6458 /* Get points */ 6459 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6460 for (clsize = 0, p = 0; p < numPoints; p++) { 6461 PetscInt dof; 6462 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6463 clsize += dof; 6464 } 6465 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6466 /* Get array */ 6467 PetscCall(VecGetArray(v, &array)); 6468 /* Get values */ 6469 if (numFields > 0) { 6470 PetscInt offset = 0, f; 6471 for (f = 0; f < numFields; ++f) { 6472 const PetscInt **perms = NULL; 6473 const PetscScalar **flips = NULL; 6474 6475 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6476 switch (mode) { 6477 case INSERT_VALUES: 6478 for (p = 0; p < numPoints; p++) { 6479 const PetscInt point = points[2 * p]; 6480 const PetscInt *perm = perms ? perms[p] : NULL; 6481 const PetscScalar *flip = flips ? flips[p] : NULL; 6482 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6483 } 6484 break; 6485 case INSERT_ALL_VALUES: 6486 for (p = 0; p < numPoints; p++) { 6487 const PetscInt point = points[2 * p]; 6488 const PetscInt *perm = perms ? perms[p] : NULL; 6489 const PetscScalar *flip = flips ? flips[p] : NULL; 6490 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6491 } 6492 break; 6493 case INSERT_BC_VALUES: 6494 for (p = 0; p < numPoints; p++) { 6495 const PetscInt point = points[2 * p]; 6496 const PetscInt *perm = perms ? perms[p] : NULL; 6497 const PetscScalar *flip = flips ? flips[p] : NULL; 6498 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6499 } 6500 break; 6501 case ADD_VALUES: 6502 for (p = 0; p < numPoints; p++) { 6503 const PetscInt point = points[2 * p]; 6504 const PetscInt *perm = perms ? perms[p] : NULL; 6505 const PetscScalar *flip = flips ? flips[p] : NULL; 6506 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6507 } 6508 break; 6509 case ADD_ALL_VALUES: 6510 for (p = 0; p < numPoints; p++) { 6511 const PetscInt point = points[2 * p]; 6512 const PetscInt *perm = perms ? perms[p] : NULL; 6513 const PetscScalar *flip = flips ? flips[p] : NULL; 6514 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6515 } 6516 break; 6517 case ADD_BC_VALUES: 6518 for (p = 0; p < numPoints; p++) { 6519 const PetscInt point = points[2 * p]; 6520 const PetscInt *perm = perms ? perms[p] : NULL; 6521 const PetscScalar *flip = flips ? flips[p] : NULL; 6522 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6523 } 6524 break; 6525 default: 6526 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6527 } 6528 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6529 } 6530 } else { 6531 PetscInt dof, off; 6532 const PetscInt **perms = NULL; 6533 const PetscScalar **flips = NULL; 6534 6535 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6536 switch (mode) { 6537 case INSERT_VALUES: 6538 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6539 const PetscInt point = points[2 * p]; 6540 const PetscInt *perm = perms ? perms[p] : NULL; 6541 const PetscScalar *flip = flips ? flips[p] : NULL; 6542 PetscCall(PetscSectionGetDof(section, point, &dof)); 6543 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6544 } 6545 break; 6546 case INSERT_ALL_VALUES: 6547 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6548 const PetscInt point = points[2 * p]; 6549 const PetscInt *perm = perms ? perms[p] : NULL; 6550 const PetscScalar *flip = flips ? flips[p] : NULL; 6551 PetscCall(PetscSectionGetDof(section, point, &dof)); 6552 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6553 } 6554 break; 6555 case INSERT_BC_VALUES: 6556 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6557 const PetscInt point = points[2 * p]; 6558 const PetscInt *perm = perms ? perms[p] : NULL; 6559 const PetscScalar *flip = flips ? flips[p] : NULL; 6560 PetscCall(PetscSectionGetDof(section, point, &dof)); 6561 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6562 } 6563 break; 6564 case ADD_VALUES: 6565 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6566 const PetscInt point = points[2 * p]; 6567 const PetscInt *perm = perms ? perms[p] : NULL; 6568 const PetscScalar *flip = flips ? flips[p] : NULL; 6569 PetscCall(PetscSectionGetDof(section, point, &dof)); 6570 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6571 } 6572 break; 6573 case ADD_ALL_VALUES: 6574 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6575 const PetscInt point = points[2 * p]; 6576 const PetscInt *perm = perms ? perms[p] : NULL; 6577 const PetscScalar *flip = flips ? flips[p] : NULL; 6578 PetscCall(PetscSectionGetDof(section, point, &dof)); 6579 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6580 } 6581 break; 6582 case ADD_BC_VALUES: 6583 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6584 const PetscInt point = points[2 * p]; 6585 const PetscInt *perm = perms ? perms[p] : NULL; 6586 const PetscScalar *flip = flips ? flips[p] : NULL; 6587 PetscCall(PetscSectionGetDof(section, point, &dof)); 6588 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6589 } 6590 break; 6591 default: 6592 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6593 } 6594 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6595 } 6596 /* Cleanup points */ 6597 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6598 /* Cleanup array */ 6599 PetscCall(VecRestoreArray(v, &array)); 6600 PetscFunctionReturn(0); 6601 } 6602 6603 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6604 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6605 { 6606 PetscFunctionBegin; 6607 *contains = PETSC_TRUE; 6608 if (label) { 6609 PetscInt fdof; 6610 6611 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6612 if (!*contains) { 6613 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6614 *offset += fdof; 6615 PetscFunctionReturn(0); 6616 } 6617 } 6618 PetscFunctionReturn(0); 6619 } 6620 6621 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6622 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) 6623 { 6624 PetscSection clSection; 6625 IS clPoints; 6626 PetscScalar *array; 6627 PetscInt *points = NULL; 6628 const PetscInt *clp; 6629 PetscInt numFields, numPoints, p; 6630 PetscInt offset = 0, f; 6631 6632 PetscFunctionBeginHot; 6633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6634 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6635 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6636 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6637 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6638 /* Get points */ 6639 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6640 /* Get array */ 6641 PetscCall(VecGetArray(v, &array)); 6642 /* Get values */ 6643 for (f = 0; f < numFields; ++f) { 6644 const PetscInt **perms = NULL; 6645 const PetscScalar **flips = NULL; 6646 PetscBool contains; 6647 6648 if (!fieldActive[f]) { 6649 for (p = 0; p < numPoints * 2; p += 2) { 6650 PetscInt fdof; 6651 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6652 offset += fdof; 6653 } 6654 continue; 6655 } 6656 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6657 switch (mode) { 6658 case INSERT_VALUES: 6659 for (p = 0; p < numPoints; p++) { 6660 const PetscInt point = points[2 * p]; 6661 const PetscInt *perm = perms ? perms[p] : NULL; 6662 const PetscScalar *flip = flips ? flips[p] : NULL; 6663 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6664 if (!contains) continue; 6665 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6666 } 6667 break; 6668 case INSERT_ALL_VALUES: 6669 for (p = 0; p < numPoints; p++) { 6670 const PetscInt point = points[2 * p]; 6671 const PetscInt *perm = perms ? perms[p] : NULL; 6672 const PetscScalar *flip = flips ? flips[p] : NULL; 6673 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6674 if (!contains) continue; 6675 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6676 } 6677 break; 6678 case INSERT_BC_VALUES: 6679 for (p = 0; p < numPoints; p++) { 6680 const PetscInt point = points[2 * p]; 6681 const PetscInt *perm = perms ? perms[p] : NULL; 6682 const PetscScalar *flip = flips ? flips[p] : NULL; 6683 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6684 if (!contains) continue; 6685 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6686 } 6687 break; 6688 case ADD_VALUES: 6689 for (p = 0; p < numPoints; p++) { 6690 const PetscInt point = points[2 * p]; 6691 const PetscInt *perm = perms ? perms[p] : NULL; 6692 const PetscScalar *flip = flips ? flips[p] : NULL; 6693 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6694 if (!contains) continue; 6695 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6696 } 6697 break; 6698 case ADD_ALL_VALUES: 6699 for (p = 0; p < numPoints; p++) { 6700 const PetscInt point = points[2 * p]; 6701 const PetscInt *perm = perms ? perms[p] : NULL; 6702 const PetscScalar *flip = flips ? flips[p] : NULL; 6703 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6704 if (!contains) continue; 6705 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6706 } 6707 break; 6708 default: 6709 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6710 } 6711 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6712 } 6713 /* Cleanup points */ 6714 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6715 /* Cleanup array */ 6716 PetscCall(VecRestoreArray(v, &array)); 6717 PetscFunctionReturn(0); 6718 } 6719 6720 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6721 { 6722 PetscMPIInt rank; 6723 PetscInt i, j; 6724 6725 PetscFunctionBegin; 6726 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6727 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6728 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6729 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6730 numCIndices = numCIndices ? numCIndices : numRIndices; 6731 if (!values) PetscFunctionReturn(0); 6732 for (i = 0; i < numRIndices; i++) { 6733 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6734 for (j = 0; j < numCIndices; j++) { 6735 #if defined(PETSC_USE_COMPLEX) 6736 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6737 #else 6738 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6739 #endif 6740 } 6741 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6742 } 6743 PetscFunctionReturn(0); 6744 } 6745 6746 /* 6747 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6748 6749 Input Parameters: 6750 + section - The section for this data layout 6751 . islocal - Is the section (and thus indices being requested) local or global? 6752 . point - The point contributing dofs with these indices 6753 . off - The global offset of this point 6754 . loff - The local offset of each field 6755 . setBC - The flag determining whether to include indices of boundary values 6756 . perm - A permutation of the dofs on this point, or NULL 6757 - indperm - A permutation of the entire indices array, or NULL 6758 6759 Output Parameter: 6760 . indices - Indices for dofs on this point 6761 6762 Level: developer 6763 6764 Note: The indices could be local or global, depending on the value of 'off'. 6765 */ 6766 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6767 { 6768 PetscInt dof; /* The number of unknowns on this point */ 6769 PetscInt cdof; /* The number of constraints on this point */ 6770 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6771 PetscInt cind = 0, k; 6772 6773 PetscFunctionBegin; 6774 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6775 PetscCall(PetscSectionGetDof(section, point, &dof)); 6776 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6777 if (!cdof || setBC) { 6778 for (k = 0; k < dof; ++k) { 6779 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6780 const PetscInt ind = indperm ? indperm[preind] : preind; 6781 6782 indices[ind] = off + k; 6783 } 6784 } else { 6785 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6786 for (k = 0; k < dof; ++k) { 6787 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6788 const PetscInt ind = indperm ? indperm[preind] : preind; 6789 6790 if ((cind < cdof) && (k == cdofs[cind])) { 6791 /* Insert check for returning constrained indices */ 6792 indices[ind] = -(off + k + 1); 6793 ++cind; 6794 } else { 6795 indices[ind] = off + k - (islocal ? 0 : cind); 6796 } 6797 } 6798 } 6799 *loff += dof; 6800 PetscFunctionReturn(0); 6801 } 6802 6803 /* 6804 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6805 6806 Input Parameters: 6807 + section - a section (global or local) 6808 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6809 . point - point within section 6810 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6811 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6812 . setBC - identify constrained (boundary condition) points via involution. 6813 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6814 . permsoff - offset 6815 - indperm - index permutation 6816 6817 Output Parameter: 6818 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6819 . indices - array to hold indices (as defined by section) of each dof associated with point 6820 6821 Notes: 6822 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6823 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6824 in the local vector. 6825 6826 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6827 significant). It is invalid to call with a global section and setBC=true. 6828 6829 Developer Note: 6830 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6831 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6832 offset could be obtained from the section instead of passing it explicitly as we do now. 6833 6834 Example: 6835 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6836 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6837 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6838 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. 6839 6840 Level: developer 6841 */ 6842 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[]) 6843 { 6844 PetscInt numFields, foff, f; 6845 6846 PetscFunctionBegin; 6847 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6848 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6849 for (f = 0, foff = 0; f < numFields; ++f) { 6850 PetscInt fdof, cfdof; 6851 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6852 PetscInt cind = 0, b; 6853 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6854 6855 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6856 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6857 if (!cfdof || setBC) { 6858 for (b = 0; b < fdof; ++b) { 6859 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6860 const PetscInt ind = indperm ? indperm[preind] : preind; 6861 6862 indices[ind] = off + foff + b; 6863 } 6864 } else { 6865 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6866 for (b = 0; b < fdof; ++b) { 6867 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6868 const PetscInt ind = indperm ? indperm[preind] : preind; 6869 6870 if ((cind < cfdof) && (b == fcdofs[cind])) { 6871 indices[ind] = -(off + foff + b + 1); 6872 ++cind; 6873 } else { 6874 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6875 } 6876 } 6877 } 6878 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6879 foffs[f] += fdof; 6880 } 6881 PetscFunctionReturn(0); 6882 } 6883 6884 /* 6885 This version believes the globalSection offsets for each field, rather than just the point offset 6886 6887 . foffs - The offset into 'indices' for each field, since it is segregated by field 6888 6889 Notes: 6890 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6891 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6892 */ 6893 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6894 { 6895 PetscInt numFields, foff, f; 6896 6897 PetscFunctionBegin; 6898 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6899 for (f = 0; f < numFields; ++f) { 6900 PetscInt fdof, cfdof; 6901 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6902 PetscInt cind = 0, b; 6903 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6904 6905 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6906 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6907 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6908 if (!cfdof) { 6909 for (b = 0; b < fdof; ++b) { 6910 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6911 const PetscInt ind = indperm ? indperm[preind] : preind; 6912 6913 indices[ind] = foff + b; 6914 } 6915 } else { 6916 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6917 for (b = 0; b < fdof; ++b) { 6918 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6919 const PetscInt ind = indperm ? indperm[preind] : preind; 6920 6921 if ((cind < cfdof) && (b == fcdofs[cind])) { 6922 indices[ind] = -(foff + b + 1); 6923 ++cind; 6924 } else { 6925 indices[ind] = foff + b - cind; 6926 } 6927 } 6928 } 6929 foffs[f] += fdof; 6930 } 6931 PetscFunctionReturn(0); 6932 } 6933 6934 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) 6935 { 6936 Mat cMat; 6937 PetscSection aSec, cSec; 6938 IS aIS; 6939 PetscInt aStart = -1, aEnd = -1; 6940 const PetscInt *anchors; 6941 PetscInt numFields, f, p, q, newP = 0; 6942 PetscInt newNumPoints = 0, newNumIndices = 0; 6943 PetscInt *newPoints, *indices, *newIndices; 6944 PetscInt maxAnchor, maxDof; 6945 PetscInt newOffsets[32]; 6946 PetscInt *pointMatOffsets[32]; 6947 PetscInt *newPointOffsets[32]; 6948 PetscScalar *pointMat[32]; 6949 PetscScalar *newValues = NULL, *tmpValues; 6950 PetscBool anyConstrained = PETSC_FALSE; 6951 6952 PetscFunctionBegin; 6953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6954 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6955 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6956 6957 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6958 /* if there are point-to-point constraints */ 6959 if (aSec) { 6960 PetscCall(PetscArrayzero(newOffsets, 32)); 6961 PetscCall(ISGetIndices(aIS, &anchors)); 6962 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6963 /* figure out how many points are going to be in the new element matrix 6964 * (we allow double counting, because it's all just going to be summed 6965 * into the global matrix anyway) */ 6966 for (p = 0; p < 2 * numPoints; p += 2) { 6967 PetscInt b = points[p]; 6968 PetscInt bDof = 0, bSecDof; 6969 6970 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6971 if (!bSecDof) continue; 6972 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6973 if (bDof) { 6974 /* this point is constrained */ 6975 /* it is going to be replaced by its anchors */ 6976 PetscInt bOff, q; 6977 6978 anyConstrained = PETSC_TRUE; 6979 newNumPoints += bDof; 6980 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6981 for (q = 0; q < bDof; q++) { 6982 PetscInt a = anchors[bOff + q]; 6983 PetscInt aDof; 6984 6985 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6986 newNumIndices += aDof; 6987 for (f = 0; f < numFields; ++f) { 6988 PetscInt fDof; 6989 6990 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6991 newOffsets[f + 1] += fDof; 6992 } 6993 } 6994 } else { 6995 /* this point is not constrained */ 6996 newNumPoints++; 6997 newNumIndices += bSecDof; 6998 for (f = 0; f < numFields; ++f) { 6999 PetscInt fDof; 7000 7001 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7002 newOffsets[f + 1] += fDof; 7003 } 7004 } 7005 } 7006 } 7007 if (!anyConstrained) { 7008 if (outNumPoints) *outNumPoints = 0; 7009 if (outNumIndices) *outNumIndices = 0; 7010 if (outPoints) *outPoints = NULL; 7011 if (outValues) *outValues = NULL; 7012 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7013 PetscFunctionReturn(0); 7014 } 7015 7016 if (outNumPoints) *outNumPoints = newNumPoints; 7017 if (outNumIndices) *outNumIndices = newNumIndices; 7018 7019 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7020 7021 if (!outPoints && !outValues) { 7022 if (offsets) { 7023 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7024 } 7025 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7026 PetscFunctionReturn(0); 7027 } 7028 7029 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7030 7031 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7032 7033 /* workspaces */ 7034 if (numFields) { 7035 for (f = 0; f < numFields; f++) { 7036 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7037 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7038 } 7039 } else { 7040 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7041 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7042 } 7043 7044 /* get workspaces for the point-to-point matrices */ 7045 if (numFields) { 7046 PetscInt totalOffset, totalMatOffset; 7047 7048 for (p = 0; p < numPoints; p++) { 7049 PetscInt b = points[2 * p]; 7050 PetscInt bDof = 0, bSecDof; 7051 7052 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7053 if (!bSecDof) { 7054 for (f = 0; f < numFields; f++) { 7055 newPointOffsets[f][p + 1] = 0; 7056 pointMatOffsets[f][p + 1] = 0; 7057 } 7058 continue; 7059 } 7060 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7061 if (bDof) { 7062 for (f = 0; f < numFields; f++) { 7063 PetscInt fDof, q, bOff, allFDof = 0; 7064 7065 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7066 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7067 for (q = 0; q < bDof; q++) { 7068 PetscInt a = anchors[bOff + q]; 7069 PetscInt aFDof; 7070 7071 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7072 allFDof += aFDof; 7073 } 7074 newPointOffsets[f][p + 1] = allFDof; 7075 pointMatOffsets[f][p + 1] = fDof * allFDof; 7076 } 7077 } else { 7078 for (f = 0; f < numFields; f++) { 7079 PetscInt fDof; 7080 7081 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7082 newPointOffsets[f][p + 1] = fDof; 7083 pointMatOffsets[f][p + 1] = 0; 7084 } 7085 } 7086 } 7087 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7088 newPointOffsets[f][0] = totalOffset; 7089 pointMatOffsets[f][0] = totalMatOffset; 7090 for (p = 0; p < numPoints; p++) { 7091 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7092 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7093 } 7094 totalOffset = newPointOffsets[f][numPoints]; 7095 totalMatOffset = pointMatOffsets[f][numPoints]; 7096 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7097 } 7098 } else { 7099 for (p = 0; p < numPoints; p++) { 7100 PetscInt b = points[2 * p]; 7101 PetscInt bDof = 0, bSecDof; 7102 7103 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7104 if (!bSecDof) { 7105 newPointOffsets[0][p + 1] = 0; 7106 pointMatOffsets[0][p + 1] = 0; 7107 continue; 7108 } 7109 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7110 if (bDof) { 7111 PetscInt bOff, q, allDof = 0; 7112 7113 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7114 for (q = 0; q < bDof; q++) { 7115 PetscInt a = anchors[bOff + q], aDof; 7116 7117 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7118 allDof += aDof; 7119 } 7120 newPointOffsets[0][p + 1] = allDof; 7121 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7122 } else { 7123 newPointOffsets[0][p + 1] = bSecDof; 7124 pointMatOffsets[0][p + 1] = 0; 7125 } 7126 } 7127 newPointOffsets[0][0] = 0; 7128 pointMatOffsets[0][0] = 0; 7129 for (p = 0; p < numPoints; p++) { 7130 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7131 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7132 } 7133 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7134 } 7135 7136 /* output arrays */ 7137 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7138 7139 /* get the point-to-point matrices; construct newPoints */ 7140 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7141 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7142 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7143 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7144 if (numFields) { 7145 for (p = 0, newP = 0; p < numPoints; p++) { 7146 PetscInt b = points[2 * p]; 7147 PetscInt o = points[2 * p + 1]; 7148 PetscInt bDof = 0, bSecDof; 7149 7150 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7151 if (!bSecDof) continue; 7152 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7153 if (bDof) { 7154 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7155 7156 fStart[0] = 0; 7157 fEnd[0] = 0; 7158 for (f = 0; f < numFields; f++) { 7159 PetscInt fDof; 7160 7161 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7162 fStart[f + 1] = fStart[f] + fDof; 7163 fEnd[f + 1] = fStart[f + 1]; 7164 } 7165 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7166 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7167 7168 fAnchorStart[0] = 0; 7169 fAnchorEnd[0] = 0; 7170 for (f = 0; f < numFields; f++) { 7171 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7172 7173 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7174 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7175 } 7176 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7177 for (q = 0; q < bDof; q++) { 7178 PetscInt a = anchors[bOff + q], aOff; 7179 7180 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7181 newPoints[2 * (newP + q)] = a; 7182 newPoints[2 * (newP + q) + 1] = 0; 7183 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7184 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7185 } 7186 newP += bDof; 7187 7188 if (outValues) { 7189 /* get the point-to-point submatrix */ 7190 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])); 7191 } 7192 } else { 7193 newPoints[2 * newP] = b; 7194 newPoints[2 * newP + 1] = o; 7195 newP++; 7196 } 7197 } 7198 } else { 7199 for (p = 0; p < numPoints; p++) { 7200 PetscInt b = points[2 * p]; 7201 PetscInt o = points[2 * p + 1]; 7202 PetscInt bDof = 0, bSecDof; 7203 7204 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7205 if (!bSecDof) continue; 7206 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7207 if (bDof) { 7208 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7209 7210 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7211 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7212 7213 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7214 for (q = 0; q < bDof; q++) { 7215 PetscInt a = anchors[bOff + q], aOff; 7216 7217 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7218 7219 newPoints[2 * (newP + q)] = a; 7220 newPoints[2 * (newP + q) + 1] = 0; 7221 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7222 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7223 } 7224 newP += bDof; 7225 7226 /* get the point-to-point submatrix */ 7227 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7228 } else { 7229 newPoints[2 * newP] = b; 7230 newPoints[2 * newP + 1] = o; 7231 newP++; 7232 } 7233 } 7234 } 7235 7236 if (outValues) { 7237 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7238 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7239 /* multiply constraints on the right */ 7240 if (numFields) { 7241 for (f = 0; f < numFields; f++) { 7242 PetscInt oldOff = offsets[f]; 7243 7244 for (p = 0; p < numPoints; p++) { 7245 PetscInt cStart = newPointOffsets[f][p]; 7246 PetscInt b = points[2 * p]; 7247 PetscInt c, r, k; 7248 PetscInt dof; 7249 7250 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7251 if (!dof) continue; 7252 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7253 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7254 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7255 7256 for (r = 0; r < numIndices; r++) { 7257 for (c = 0; c < nCols; c++) { 7258 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7259 } 7260 } 7261 } else { 7262 /* copy this column as is */ 7263 for (r = 0; r < numIndices; r++) { 7264 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7265 } 7266 } 7267 oldOff += dof; 7268 } 7269 } 7270 } else { 7271 PetscInt oldOff = 0; 7272 for (p = 0; p < numPoints; p++) { 7273 PetscInt cStart = newPointOffsets[0][p]; 7274 PetscInt b = points[2 * p]; 7275 PetscInt c, r, k; 7276 PetscInt dof; 7277 7278 PetscCall(PetscSectionGetDof(section, b, &dof)); 7279 if (!dof) continue; 7280 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7281 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7282 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7283 7284 for (r = 0; r < numIndices; r++) { 7285 for (c = 0; c < nCols; c++) { 7286 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7287 } 7288 } 7289 } else { 7290 /* copy this column as is */ 7291 for (r = 0; r < numIndices; r++) { 7292 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7293 } 7294 } 7295 oldOff += dof; 7296 } 7297 } 7298 7299 if (multiplyLeft) { 7300 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7301 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7302 /* multiply constraints transpose on the left */ 7303 if (numFields) { 7304 for (f = 0; f < numFields; f++) { 7305 PetscInt oldOff = offsets[f]; 7306 7307 for (p = 0; p < numPoints; p++) { 7308 PetscInt rStart = newPointOffsets[f][p]; 7309 PetscInt b = points[2 * p]; 7310 PetscInt c, r, k; 7311 PetscInt dof; 7312 7313 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7314 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7315 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7316 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7317 7318 for (r = 0; r < nRows; r++) { 7319 for (c = 0; c < newNumIndices; c++) { 7320 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7321 } 7322 } 7323 } else { 7324 /* copy this row as is */ 7325 for (r = 0; r < dof; r++) { 7326 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7327 } 7328 } 7329 oldOff += dof; 7330 } 7331 } 7332 } else { 7333 PetscInt oldOff = 0; 7334 7335 for (p = 0; p < numPoints; p++) { 7336 PetscInt rStart = newPointOffsets[0][p]; 7337 PetscInt b = points[2 * p]; 7338 PetscInt c, r, k; 7339 PetscInt dof; 7340 7341 PetscCall(PetscSectionGetDof(section, b, &dof)); 7342 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7343 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7344 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7345 7346 for (r = 0; r < nRows; r++) { 7347 for (c = 0; c < newNumIndices; c++) { 7348 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7349 } 7350 } 7351 } else { 7352 /* copy this row as is */ 7353 for (r = 0; r < dof; r++) { 7354 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7355 } 7356 } 7357 oldOff += dof; 7358 } 7359 } 7360 7361 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7362 } else { 7363 newValues = tmpValues; 7364 } 7365 } 7366 7367 /* clean up */ 7368 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7369 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7370 7371 if (numFields) { 7372 for (f = 0; f < numFields; f++) { 7373 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7374 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7375 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7376 } 7377 } else { 7378 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7379 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7380 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7381 } 7382 PetscCall(ISRestoreIndices(aIS, &anchors)); 7383 7384 /* output */ 7385 if (outPoints) { 7386 *outPoints = newPoints; 7387 } else { 7388 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7389 } 7390 if (outValues) *outValues = newValues; 7391 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7392 PetscFunctionReturn(0); 7393 } 7394 7395 /*@C 7396 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7397 7398 Not collective 7399 7400 Input Parameters: 7401 + dm - The `DM` 7402 . section - The `PetscSection` describing the points (a local section) 7403 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7404 . point - The point defining the closure 7405 - useClPerm - Use the closure point permutation if available 7406 7407 Output Parameters: 7408 + numIndices - The number of dof indices in the closure of point with the input sections 7409 . indices - The dof indices 7410 . outOffsets - Array to write the field offsets into, or NULL 7411 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7412 7413 Level: advanced 7414 7415 Notes: 7416 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7417 7418 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7419 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7420 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7421 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7422 indices (with the above semantics) are implied. 7423 7424 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7425 `PetscSection`, `DMGetGlobalSection()` 7426 @*/ 7427 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7428 { 7429 /* Closure ordering */ 7430 PetscSection clSection; 7431 IS clPoints; 7432 const PetscInt *clp; 7433 PetscInt *points; 7434 const PetscInt *clperm = NULL; 7435 /* Dof permutation and sign flips */ 7436 const PetscInt **perms[32] = {NULL}; 7437 const PetscScalar **flips[32] = {NULL}; 7438 PetscScalar *valCopy = NULL; 7439 /* Hanging node constraints */ 7440 PetscInt *pointsC = NULL; 7441 PetscScalar *valuesC = NULL; 7442 PetscInt NclC, NiC; 7443 7444 PetscInt *idx; 7445 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7446 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7447 7448 PetscFunctionBeginHot; 7449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7450 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7451 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7452 if (numIndices) PetscValidIntPointer(numIndices, 6); 7453 if (indices) PetscValidPointer(indices, 7); 7454 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7455 if (values) PetscValidPointer(values, 9); 7456 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7457 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7458 PetscCall(PetscArrayzero(offsets, 32)); 7459 /* 1) Get points in closure */ 7460 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7461 if (useClPerm) { 7462 PetscInt depth, clsize; 7463 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7464 for (clsize = 0, p = 0; p < Ncl; p++) { 7465 PetscInt dof; 7466 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7467 clsize += dof; 7468 } 7469 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7470 } 7471 /* 2) Get number of indices on these points and field offsets from section */ 7472 for (p = 0; p < Ncl * 2; p += 2) { 7473 PetscInt dof, fdof; 7474 7475 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7476 for (f = 0; f < Nf; ++f) { 7477 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7478 offsets[f + 1] += fdof; 7479 } 7480 Ni += dof; 7481 } 7482 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7483 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7484 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7485 for (f = 0; f < PetscMax(1, Nf); ++f) { 7486 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7487 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7488 /* may need to apply sign changes to the element matrix */ 7489 if (values && flips[f]) { 7490 PetscInt foffset = offsets[f]; 7491 7492 for (p = 0; p < Ncl; ++p) { 7493 PetscInt pnt = points[2 * p], fdof; 7494 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7495 7496 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7497 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7498 if (flip) { 7499 PetscInt i, j, k; 7500 7501 if (!valCopy) { 7502 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7503 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7504 *values = valCopy; 7505 } 7506 for (i = 0; i < fdof; ++i) { 7507 PetscScalar fval = flip[i]; 7508 7509 for (k = 0; k < Ni; ++k) { 7510 valCopy[Ni * (foffset + i) + k] *= fval; 7511 valCopy[Ni * k + (foffset + i)] *= fval; 7512 } 7513 } 7514 } 7515 foffset += fdof; 7516 } 7517 } 7518 } 7519 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7520 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7521 if (NclC) { 7522 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7523 for (f = 0; f < PetscMax(1, Nf); ++f) { 7524 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7525 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7526 } 7527 for (f = 0; f < PetscMax(1, Nf); ++f) { 7528 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7529 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7530 } 7531 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7532 Ncl = NclC; 7533 Ni = NiC; 7534 points = pointsC; 7535 if (values) *values = valuesC; 7536 } 7537 /* 5) Calculate indices */ 7538 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7539 if (Nf) { 7540 PetscInt idxOff; 7541 PetscBool useFieldOffsets; 7542 7543 if (outOffsets) { 7544 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7545 } 7546 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7547 if (useFieldOffsets) { 7548 for (p = 0; p < Ncl; ++p) { 7549 const PetscInt pnt = points[p * 2]; 7550 7551 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7552 } 7553 } else { 7554 for (p = 0; p < Ncl; ++p) { 7555 const PetscInt pnt = points[p * 2]; 7556 7557 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7558 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7559 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7560 * global section. */ 7561 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7562 } 7563 } 7564 } else { 7565 PetscInt off = 0, idxOff; 7566 7567 for (p = 0; p < Ncl; ++p) { 7568 const PetscInt pnt = points[p * 2]; 7569 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7570 7571 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7572 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7573 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7574 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7575 } 7576 } 7577 /* 6) Cleanup */ 7578 for (f = 0; f < PetscMax(1, Nf); ++f) { 7579 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7580 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7581 } 7582 if (NclC) { 7583 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7584 } else { 7585 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7586 } 7587 7588 if (numIndices) *numIndices = Ni; 7589 if (indices) *indices = idx; 7590 PetscFunctionReturn(0); 7591 } 7592 7593 /*@C 7594 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7595 7596 Not collective 7597 7598 Input Parameters: 7599 + dm - The `DM` 7600 . section - The `PetscSection` describing the points (a local section) 7601 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7602 . point - The point defining the closure 7603 - useClPerm - Use the closure point permutation if available 7604 7605 Output Parameters: 7606 + numIndices - The number of dof indices in the closure of point with the input sections 7607 . indices - The dof indices 7608 . outOffsets - Array to write the field offsets into, or NULL 7609 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7610 7611 Level: advanced 7612 7613 Notes: 7614 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7615 7616 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7617 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7618 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7619 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7620 indices (with the above semantics) are implied. 7621 7622 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7623 @*/ 7624 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7625 { 7626 PetscFunctionBegin; 7627 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7628 PetscValidPointer(indices, 7); 7629 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7630 PetscFunctionReturn(0); 7631 } 7632 7633 /*@C 7634 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7635 7636 Not collective 7637 7638 Input Parameters: 7639 + dm - The `DM` 7640 . section - The section describing the layout in v, or NULL to use the default section 7641 . globalSection - The section describing the layout in v, or NULL to use the default global section 7642 . A - The matrix 7643 . point - The point in the `DM` 7644 . values - The array of values 7645 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7646 7647 Level: intermediate 7648 7649 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7650 @*/ 7651 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7652 { 7653 DM_Plex *mesh = (DM_Plex *)dm->data; 7654 PetscInt *indices; 7655 PetscInt numIndices; 7656 const PetscScalar *valuesOrig = values; 7657 PetscErrorCode ierr; 7658 7659 PetscFunctionBegin; 7660 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7661 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7662 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7663 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7664 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7665 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7666 7667 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7668 7669 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7670 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7671 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7672 if (ierr) { 7673 PetscMPIInt rank; 7674 7675 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7676 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7677 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7678 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7679 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7680 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7681 } 7682 if (mesh->printFEM > 1) { 7683 PetscInt i; 7684 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7685 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7686 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7687 } 7688 7689 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7690 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7691 PetscFunctionReturn(0); 7692 } 7693 7694 /*@C 7695 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7696 7697 Not collective 7698 7699 Input Parameters: 7700 + dmRow - The `DM` for the row fields 7701 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7702 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7703 . dmCol - The `DM` for the column fields 7704 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7705 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7706 . A - The matrix 7707 . point - The point in the `DM` 7708 . values - The array of values 7709 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7710 7711 Level: intermediate 7712 7713 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7714 @*/ 7715 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7716 { 7717 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7718 PetscInt *indicesRow, *indicesCol; 7719 PetscInt numIndicesRow, numIndicesCol; 7720 const PetscScalar *valuesOrig = values; 7721 PetscErrorCode ierr; 7722 7723 PetscFunctionBegin; 7724 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7725 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7726 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7727 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7728 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7729 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7730 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7731 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7732 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7733 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7734 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7735 7736 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7737 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7738 7739 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7740 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7741 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7742 if (ierr) { 7743 PetscMPIInt rank; 7744 7745 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7746 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7747 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7748 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7749 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7750 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7751 } 7752 7753 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7754 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7755 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7756 PetscFunctionReturn(0); 7757 } 7758 7759 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7760 { 7761 DM_Plex *mesh = (DM_Plex *)dmf->data; 7762 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7763 PetscInt *cpoints = NULL; 7764 PetscInt *findices, *cindices; 7765 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7766 PetscInt foffsets[32], coffsets[32]; 7767 DMPolytopeType ct; 7768 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7769 PetscErrorCode ierr; 7770 7771 PetscFunctionBegin; 7772 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7773 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7774 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7775 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7776 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7777 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7778 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7779 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7780 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7781 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7782 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7783 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7784 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7785 PetscCall(PetscArrayzero(foffsets, 32)); 7786 PetscCall(PetscArrayzero(coffsets, 32)); 7787 /* Column indices */ 7788 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7789 maxFPoints = numCPoints; 7790 /* Compress out points not in the section */ 7791 /* TODO: Squeeze out points with 0 dof as well */ 7792 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7793 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7794 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7795 cpoints[q * 2] = cpoints[p]; 7796 cpoints[q * 2 + 1] = cpoints[p + 1]; 7797 ++q; 7798 } 7799 } 7800 numCPoints = q; 7801 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7802 PetscInt fdof; 7803 7804 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7805 if (!dof) continue; 7806 for (f = 0; f < numFields; ++f) { 7807 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7808 coffsets[f + 1] += fdof; 7809 } 7810 numCIndices += dof; 7811 } 7812 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7813 /* Row indices */ 7814 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7815 { 7816 DMPlexTransform tr; 7817 DMPolytopeType *rct; 7818 PetscInt *rsize, *rcone, *rornt, Nt; 7819 7820 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7821 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7822 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7823 numSubcells = rsize[Nt - 1]; 7824 PetscCall(DMPlexTransformDestroy(&tr)); 7825 } 7826 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7827 for (r = 0, q = 0; r < numSubcells; ++r) { 7828 /* TODO Map from coarse to fine cells */ 7829 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7830 /* Compress out points not in the section */ 7831 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7832 for (p = 0; p < numFPoints * 2; p += 2) { 7833 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7834 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7835 if (!dof) continue; 7836 for (s = 0; s < q; ++s) 7837 if (fpoints[p] == ftotpoints[s * 2]) break; 7838 if (s < q) continue; 7839 ftotpoints[q * 2] = fpoints[p]; 7840 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7841 ++q; 7842 } 7843 } 7844 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7845 } 7846 numFPoints = q; 7847 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7848 PetscInt fdof; 7849 7850 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7851 if (!dof) continue; 7852 for (f = 0; f < numFields; ++f) { 7853 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7854 foffsets[f + 1] += fdof; 7855 } 7856 numFIndices += dof; 7857 } 7858 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7859 7860 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7861 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7862 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7863 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7864 if (numFields) { 7865 const PetscInt **permsF[32] = {NULL}; 7866 const PetscInt **permsC[32] = {NULL}; 7867 7868 for (f = 0; f < numFields; f++) { 7869 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7870 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7871 } 7872 for (p = 0; p < numFPoints; p++) { 7873 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7874 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7875 } 7876 for (p = 0; p < numCPoints; p++) { 7877 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7878 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7879 } 7880 for (f = 0; f < numFields; f++) { 7881 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7882 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7883 } 7884 } else { 7885 const PetscInt **permsF = NULL; 7886 const PetscInt **permsC = NULL; 7887 7888 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7889 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7890 for (p = 0, off = 0; p < numFPoints; p++) { 7891 const PetscInt *perm = permsF ? permsF[p] : NULL; 7892 7893 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7894 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7895 } 7896 for (p = 0, off = 0; p < numCPoints; p++) { 7897 const PetscInt *perm = permsC ? permsC[p] : NULL; 7898 7899 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7900 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7901 } 7902 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7903 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7904 } 7905 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7906 /* TODO: flips */ 7907 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7908 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, 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, numFIndices, findices, numCIndices, cindices, values)); 7915 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7916 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7917 } 7918 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7919 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7920 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7921 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7922 PetscFunctionReturn(0); 7923 } 7924 7925 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7926 { 7927 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7928 PetscInt *cpoints = NULL; 7929 PetscInt foffsets[32], coffsets[32]; 7930 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7931 DMPolytopeType ct; 7932 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7933 7934 PetscFunctionBegin; 7935 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7936 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7937 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7938 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7939 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7940 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7941 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7942 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7943 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7944 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7945 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7946 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7947 PetscCall(PetscArrayzero(foffsets, 32)); 7948 PetscCall(PetscArrayzero(coffsets, 32)); 7949 /* Column indices */ 7950 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7951 maxFPoints = numCPoints; 7952 /* Compress out points not in the section */ 7953 /* TODO: Squeeze out points with 0 dof as well */ 7954 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7955 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7956 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7957 cpoints[q * 2] = cpoints[p]; 7958 cpoints[q * 2 + 1] = cpoints[p + 1]; 7959 ++q; 7960 } 7961 } 7962 numCPoints = q; 7963 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7964 PetscInt fdof; 7965 7966 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7967 if (!dof) continue; 7968 for (f = 0; f < numFields; ++f) { 7969 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7970 coffsets[f + 1] += fdof; 7971 } 7972 numCIndices += dof; 7973 } 7974 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7975 /* Row indices */ 7976 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7977 { 7978 DMPlexTransform tr; 7979 DMPolytopeType *rct; 7980 PetscInt *rsize, *rcone, *rornt, Nt; 7981 7982 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7983 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7984 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7985 numSubcells = rsize[Nt - 1]; 7986 PetscCall(DMPlexTransformDestroy(&tr)); 7987 } 7988 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7989 for (r = 0, q = 0; r < numSubcells; ++r) { 7990 /* TODO Map from coarse to fine cells */ 7991 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7992 /* Compress out points not in the section */ 7993 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7994 for (p = 0; p < numFPoints * 2; p += 2) { 7995 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7996 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7997 if (!dof) continue; 7998 for (s = 0; s < q; ++s) 7999 if (fpoints[p] == ftotpoints[s * 2]) break; 8000 if (s < q) continue; 8001 ftotpoints[q * 2] = fpoints[p]; 8002 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8003 ++q; 8004 } 8005 } 8006 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8007 } 8008 numFPoints = q; 8009 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8010 PetscInt fdof; 8011 8012 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8013 if (!dof) continue; 8014 for (f = 0; f < numFields; ++f) { 8015 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8016 foffsets[f + 1] += fdof; 8017 } 8018 numFIndices += dof; 8019 } 8020 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8021 8022 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8023 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8024 if (numFields) { 8025 const PetscInt **permsF[32] = {NULL}; 8026 const PetscInt **permsC[32] = {NULL}; 8027 8028 for (f = 0; f < numFields; f++) { 8029 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8030 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8031 } 8032 for (p = 0; p < numFPoints; p++) { 8033 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8034 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8035 } 8036 for (p = 0; p < numCPoints; p++) { 8037 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8038 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8039 } 8040 for (f = 0; f < numFields; f++) { 8041 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8042 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8043 } 8044 } else { 8045 const PetscInt **permsF = NULL; 8046 const PetscInt **permsC = NULL; 8047 8048 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8049 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8050 for (p = 0, off = 0; p < numFPoints; p++) { 8051 const PetscInt *perm = permsF ? permsF[p] : NULL; 8052 8053 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8054 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8055 } 8056 for (p = 0, off = 0; p < numCPoints; p++) { 8057 const PetscInt *perm = permsC ? permsC[p] : NULL; 8058 8059 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8060 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8061 } 8062 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8063 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8064 } 8065 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8066 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8067 PetscFunctionReturn(0); 8068 } 8069 8070 /*@C 8071 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8072 8073 Input Parameter: 8074 . dm - The `DMPLEX` object 8075 8076 Output Parameter: 8077 . cellHeight - The height of a cell 8078 8079 Level: developer 8080 8081 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8082 @*/ 8083 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8084 { 8085 DM_Plex *mesh = (DM_Plex *)dm->data; 8086 8087 PetscFunctionBegin; 8088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8089 PetscValidIntPointer(cellHeight, 2); 8090 *cellHeight = mesh->vtkCellHeight; 8091 PetscFunctionReturn(0); 8092 } 8093 8094 /*@C 8095 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8096 8097 Input Parameters: 8098 + dm - The `DMPLEX` object 8099 - cellHeight - The height of a cell 8100 8101 Level: developer 8102 8103 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8104 @*/ 8105 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8106 { 8107 DM_Plex *mesh = (DM_Plex *)dm->data; 8108 8109 PetscFunctionBegin; 8110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8111 mesh->vtkCellHeight = cellHeight; 8112 PetscFunctionReturn(0); 8113 } 8114 8115 /*@ 8116 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8117 8118 Input Parameter: 8119 . dm - The `DMPLEX` object 8120 8121 Output Parameters: 8122 + gcStart - The first ghost cell, or NULL 8123 - gcEnd - The upper bound on ghost cells, or NULL 8124 8125 Level: advanced 8126 8127 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8128 @*/ 8129 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8130 { 8131 DMLabel ctLabel; 8132 8133 PetscFunctionBegin; 8134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8135 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8136 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8137 // Reset label for fast lookup 8138 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8139 PetscFunctionReturn(0); 8140 } 8141 8142 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8143 { 8144 PetscSection section, globalSection; 8145 PetscInt *numbers, p; 8146 8147 PetscFunctionBegin; 8148 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8149 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8150 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8151 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8152 PetscCall(PetscSectionSetUp(section)); 8153 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8154 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8155 for (p = pStart; p < pEnd; ++p) { 8156 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8157 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8158 else numbers[p - pStart] += shift; 8159 } 8160 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8161 if (globalSize) { 8162 PetscLayout layout; 8163 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8164 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8165 PetscCall(PetscLayoutDestroy(&layout)); 8166 } 8167 PetscCall(PetscSectionDestroy(§ion)); 8168 PetscCall(PetscSectionDestroy(&globalSection)); 8169 PetscFunctionReturn(0); 8170 } 8171 8172 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8173 { 8174 PetscInt cellHeight, cStart, cEnd; 8175 8176 PetscFunctionBegin; 8177 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8178 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8179 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8180 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8181 PetscFunctionReturn(0); 8182 } 8183 8184 /*@ 8185 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8186 8187 Input Parameter: 8188 . dm - The `DMPLEX` object 8189 8190 Output Parameter: 8191 . globalCellNumbers - Global cell numbers for all cells on this process 8192 8193 Level: developer 8194 8195 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8196 @*/ 8197 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8198 { 8199 DM_Plex *mesh = (DM_Plex *)dm->data; 8200 8201 PetscFunctionBegin; 8202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8203 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8204 *globalCellNumbers = mesh->globalCellNumbers; 8205 PetscFunctionReturn(0); 8206 } 8207 8208 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8209 { 8210 PetscInt vStart, vEnd; 8211 8212 PetscFunctionBegin; 8213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8214 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8215 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8216 PetscFunctionReturn(0); 8217 } 8218 8219 /*@ 8220 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8221 8222 Input Parameter: 8223 . dm - The `DMPLEX` object 8224 8225 Output Parameter: 8226 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8227 8228 Level: developer 8229 8230 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8231 @*/ 8232 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8233 { 8234 DM_Plex *mesh = (DM_Plex *)dm->data; 8235 8236 PetscFunctionBegin; 8237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8238 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8239 *globalVertexNumbers = mesh->globalVertexNumbers; 8240 PetscFunctionReturn(0); 8241 } 8242 8243 /*@ 8244 DMPlexCreatePointNumbering - Create a global numbering for all points. 8245 8246 Collective on dm 8247 8248 Input Parameter: 8249 . dm - The `DMPLEX` object 8250 8251 Output Parameter: 8252 . globalPointNumbers - Global numbers for all points on this process 8253 8254 Level: developer 8255 8256 Notes: 8257 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8258 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8259 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8260 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8261 8262 The partitioned mesh is 8263 ``` 8264 (2)--0--(3)--1--(4) (1)--0--(2) 8265 ``` 8266 and its global numbering is 8267 ``` 8268 (3)--0--(4)--1--(5)--2--(6) 8269 ``` 8270 Then the global numbering is provided as 8271 ``` 8272 [0] Number of indices in set 5 8273 [0] 0 0 8274 [0] 1 1 8275 [0] 2 3 8276 [0] 3 4 8277 [0] 4 -6 8278 [1] Number of indices in set 3 8279 [1] 0 2 8280 [1] 1 5 8281 [1] 2 6 8282 ``` 8283 8284 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8285 @*/ 8286 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8287 { 8288 IS nums[4]; 8289 PetscInt depths[4], gdepths[4], starts[4]; 8290 PetscInt depth, d, shift = 0; 8291 PetscBool empty = PETSC_FALSE; 8292 8293 PetscFunctionBegin; 8294 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8295 PetscCall(DMPlexGetDepth(dm, &depth)); 8296 // For unstratified meshes use dim instead of depth 8297 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8298 // If any stratum is empty, we must mark all empty 8299 for (d = 0; d <= depth; ++d) { 8300 PetscInt end; 8301 8302 depths[d] = depth - d; 8303 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8304 if (!(starts[d] - end)) empty = PETSC_TRUE; 8305 } 8306 if (empty) 8307 for (d = 0; d <= depth; ++d) { 8308 depths[d] = -1; 8309 starts[d] = -1; 8310 } 8311 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8312 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8313 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]); 8314 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8315 for (d = 0; d <= depth; ++d) { 8316 PetscInt pStart, pEnd, gsize; 8317 8318 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8319 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8320 shift += gsize; 8321 } 8322 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8323 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8324 PetscFunctionReturn(0); 8325 } 8326 8327 /*@ 8328 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8329 8330 Input Parameter: 8331 . dm - The `DMPLEX` object 8332 8333 Output Parameter: 8334 . ranks - The rank field 8335 8336 Options Database Key: 8337 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8338 8339 Level: intermediate 8340 8341 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8342 @*/ 8343 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8344 { 8345 DM rdm; 8346 PetscFE fe; 8347 PetscScalar *r; 8348 PetscMPIInt rank; 8349 DMPolytopeType ct; 8350 PetscInt dim, cStart, cEnd, c; 8351 PetscBool simplex; 8352 8353 PetscFunctionBeginUser; 8354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8355 PetscValidPointer(ranks, 2); 8356 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8357 PetscCall(DMClone(dm, &rdm)); 8358 PetscCall(DMGetDimension(rdm, &dim)); 8359 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8360 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8361 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8362 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8363 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8364 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8365 PetscCall(PetscFEDestroy(&fe)); 8366 PetscCall(DMCreateDS(rdm)); 8367 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8368 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8369 PetscCall(VecGetArray(*ranks, &r)); 8370 for (c = cStart; c < cEnd; ++c) { 8371 PetscScalar *lr; 8372 8373 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8374 if (lr) *lr = rank; 8375 } 8376 PetscCall(VecRestoreArray(*ranks, &r)); 8377 PetscCall(DMDestroy(&rdm)); 8378 PetscFunctionReturn(0); 8379 } 8380 8381 /*@ 8382 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8383 8384 Input Parameters: 8385 + dm - The DMPlex 8386 - label - The DMLabel 8387 8388 Output Parameter: 8389 . val - The label value field 8390 8391 Options Database Keys: 8392 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8393 8394 Level: intermediate 8395 8396 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8397 @*/ 8398 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8399 { 8400 DM rdm; 8401 PetscFE fe; 8402 PetscScalar *v; 8403 PetscInt dim, cStart, cEnd, c; 8404 8405 PetscFunctionBeginUser; 8406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8407 PetscValidPointer(label, 2); 8408 PetscValidPointer(val, 3); 8409 PetscCall(DMClone(dm, &rdm)); 8410 PetscCall(DMGetDimension(rdm, &dim)); 8411 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8412 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8413 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8414 PetscCall(PetscFEDestroy(&fe)); 8415 PetscCall(DMCreateDS(rdm)); 8416 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8417 PetscCall(DMCreateGlobalVector(rdm, val)); 8418 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8419 PetscCall(VecGetArray(*val, &v)); 8420 for (c = cStart; c < cEnd; ++c) { 8421 PetscScalar *lv; 8422 PetscInt cval; 8423 8424 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8425 PetscCall(DMLabelGetValue(label, c, &cval)); 8426 *lv = cval; 8427 } 8428 PetscCall(VecRestoreArray(*val, &v)); 8429 PetscCall(DMDestroy(&rdm)); 8430 PetscFunctionReturn(0); 8431 } 8432 8433 /*@ 8434 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8435 8436 Input Parameter: 8437 . dm - The `DMPLEX` object 8438 8439 Level: developer 8440 8441 Notes: 8442 This is a useful diagnostic when creating meshes programmatically. 8443 8444 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8445 8446 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8447 @*/ 8448 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8449 { 8450 PetscSection coneSection, supportSection; 8451 const PetscInt *cone, *support; 8452 PetscInt coneSize, c, supportSize, s; 8453 PetscInt pStart, pEnd, p, pp, csize, ssize; 8454 PetscBool storagecheck = PETSC_TRUE; 8455 8456 PetscFunctionBegin; 8457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8458 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8459 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8460 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8461 /* Check that point p is found in the support of its cone points, and vice versa */ 8462 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8463 for (p = pStart; p < pEnd; ++p) { 8464 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8465 PetscCall(DMPlexGetCone(dm, p, &cone)); 8466 for (c = 0; c < coneSize; ++c) { 8467 PetscBool dup = PETSC_FALSE; 8468 PetscInt d; 8469 for (d = c - 1; d >= 0; --d) { 8470 if (cone[c] == cone[d]) { 8471 dup = PETSC_TRUE; 8472 break; 8473 } 8474 } 8475 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8476 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8477 for (s = 0; s < supportSize; ++s) { 8478 if (support[s] == p) break; 8479 } 8480 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8481 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8482 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8483 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8484 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8485 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8486 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8487 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]); 8488 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8489 } 8490 } 8491 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8492 if (p != pp) { 8493 storagecheck = PETSC_FALSE; 8494 continue; 8495 } 8496 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8497 PetscCall(DMPlexGetSupport(dm, p, &support)); 8498 for (s = 0; s < supportSize; ++s) { 8499 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8500 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8501 for (c = 0; c < coneSize; ++c) { 8502 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8503 if (cone[c] != pp) { 8504 c = 0; 8505 break; 8506 } 8507 if (cone[c] == p) break; 8508 } 8509 if (c >= coneSize) { 8510 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8511 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8512 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8513 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8514 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8515 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8516 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8517 } 8518 } 8519 } 8520 if (storagecheck) { 8521 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8522 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8523 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8524 } 8525 PetscFunctionReturn(0); 8526 } 8527 8528 /* 8529 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. 8530 */ 8531 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8532 { 8533 DMPolytopeType cct; 8534 PetscInt ptpoints[4]; 8535 const PetscInt *cone, *ccone, *ptcone; 8536 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8537 8538 PetscFunctionBegin; 8539 *unsplit = 0; 8540 switch (ct) { 8541 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8542 ptpoints[npt++] = c; 8543 break; 8544 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8545 PetscCall(DMPlexGetCone(dm, c, &cone)); 8546 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8547 for (cp = 0; cp < coneSize; ++cp) { 8548 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8549 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8550 } 8551 break; 8552 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8553 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8554 PetscCall(DMPlexGetCone(dm, c, &cone)); 8555 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8556 for (cp = 0; cp < coneSize; ++cp) { 8557 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8558 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8559 for (ccp = 0; ccp < cconeSize; ++ccp) { 8560 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8561 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8562 PetscInt p; 8563 for (p = 0; p < npt; ++p) 8564 if (ptpoints[p] == ccone[ccp]) break; 8565 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8566 } 8567 } 8568 } 8569 break; 8570 default: 8571 break; 8572 } 8573 for (pt = 0; pt < npt; ++pt) { 8574 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8575 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8576 } 8577 PetscFunctionReturn(0); 8578 } 8579 8580 /*@ 8581 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8582 8583 Input Parameters: 8584 + dm - The `DMPLEX` object 8585 - cellHeight - Normally 0 8586 8587 Level: developer 8588 8589 Notes: 8590 This is a useful diagnostic when creating meshes programmatically. 8591 Currently applicable only to homogeneous simplex or tensor meshes. 8592 8593 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8594 8595 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8596 @*/ 8597 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8598 { 8599 DMPlexInterpolatedFlag interp; 8600 DMPolytopeType ct; 8601 PetscInt vStart, vEnd, cStart, cEnd, c; 8602 8603 PetscFunctionBegin; 8604 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8605 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8606 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8607 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8608 for (c = cStart; c < cEnd; ++c) { 8609 PetscInt *closure = NULL; 8610 PetscInt coneSize, closureSize, cl, Nv = 0; 8611 8612 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8613 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8614 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8615 if (interp == DMPLEX_INTERPOLATED_FULL) { 8616 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8617 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)); 8618 } 8619 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8620 for (cl = 0; cl < closureSize * 2; cl += 2) { 8621 const PetscInt p = closure[cl]; 8622 if ((p >= vStart) && (p < vEnd)) ++Nv; 8623 } 8624 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8625 /* Special Case: Tensor faces with identified vertices */ 8626 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8627 PetscInt unsplit; 8628 8629 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8630 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8631 } 8632 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)); 8633 } 8634 PetscFunctionReturn(0); 8635 } 8636 8637 /*@ 8638 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8639 8640 Collective on dm 8641 8642 Input Parameters: 8643 + dm - The `DMPLEX` object 8644 - cellHeight - Normally 0 8645 8646 Level: developer 8647 8648 Notes: 8649 This is a useful diagnostic when creating meshes programmatically. 8650 This routine is only relevant for meshes that are fully interpolated across all ranks. 8651 It will error out if a partially interpolated mesh is given on some rank. 8652 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8653 8654 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8655 8656 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8657 @*/ 8658 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8659 { 8660 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8661 DMPlexInterpolatedFlag interpEnum; 8662 8663 PetscFunctionBegin; 8664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8665 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8666 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8667 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8668 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8669 PetscFunctionReturn(0); 8670 } 8671 8672 PetscCall(DMGetDimension(dm, &dim)); 8673 PetscCall(DMPlexGetDepth(dm, &depth)); 8674 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8675 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8676 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8677 for (c = cStart; c < cEnd; ++c) { 8678 const PetscInt *cone, *ornt, *faceSizes, *faces; 8679 const DMPolytopeType *faceTypes; 8680 DMPolytopeType ct; 8681 PetscInt numFaces, coneSize, f; 8682 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8683 8684 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8685 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8686 if (unsplit) continue; 8687 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8688 PetscCall(DMPlexGetCone(dm, c, &cone)); 8689 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8690 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8691 for (cl = 0; cl < closureSize * 2; cl += 2) { 8692 const PetscInt p = closure[cl]; 8693 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8694 } 8695 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8696 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); 8697 for (f = 0; f < numFaces; ++f) { 8698 DMPolytopeType fct; 8699 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8700 8701 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8702 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8703 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8704 const PetscInt p = fclosure[cl]; 8705 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8706 } 8707 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]); 8708 for (v = 0; v < fnumCorners; ++v) { 8709 if (fclosure[v] != faces[fOff + v]) { 8710 PetscInt v1; 8711 8712 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8713 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8714 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8715 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8716 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8717 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]); 8718 } 8719 } 8720 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8721 fOff += faceSizes[f]; 8722 } 8723 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8724 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8725 } 8726 } 8727 PetscFunctionReturn(0); 8728 } 8729 8730 /*@ 8731 DMPlexCheckGeometry - Check the geometry of mesh cells 8732 8733 Input Parameter: 8734 . dm - The `DMPLEX` object 8735 8736 Level: developer 8737 8738 Notes: 8739 This is a useful diagnostic when creating meshes programmatically. 8740 8741 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8742 8743 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8744 @*/ 8745 PetscErrorCode DMPlexCheckGeometry(DM dm) 8746 { 8747 Vec coordinates; 8748 PetscReal detJ, J[9], refVol = 1.0; 8749 PetscReal vol; 8750 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8751 8752 PetscFunctionBegin; 8753 PetscCall(DMGetDimension(dm, &dim)); 8754 PetscCall(DMGetCoordinateDim(dm, &dE)); 8755 if (dim != dE) PetscFunctionReturn(0); 8756 PetscCall(DMPlexGetDepth(dm, &depth)); 8757 for (d = 0; d < dim; ++d) refVol *= 2.0; 8758 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8759 /* Make sure local coordinates are created, because that step is collective */ 8760 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8761 for (c = cStart; c < cEnd; ++c) { 8762 DMPolytopeType ct; 8763 PetscInt unsplit; 8764 PetscBool ignoreZeroVol = PETSC_FALSE; 8765 8766 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8767 switch (ct) { 8768 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8769 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8770 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8771 ignoreZeroVol = PETSC_TRUE; 8772 break; 8773 default: 8774 break; 8775 } 8776 switch (ct) { 8777 case DM_POLYTOPE_TRI_PRISM: 8778 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8779 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8780 case DM_POLYTOPE_PYRAMID: 8781 continue; 8782 default: 8783 break; 8784 } 8785 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8786 if (unsplit) continue; 8787 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8788 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); 8789 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8790 /* This should work with periodicity since DG coordinates should be used */ 8791 if (depth > 1) { 8792 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8793 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); 8794 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8795 } 8796 } 8797 PetscFunctionReturn(0); 8798 } 8799 8800 /*@ 8801 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8802 8803 Collective on dm 8804 8805 Input Parameters: 8806 + dm - The `DMPLEX` object 8807 . pointSF - The `PetscSF`, or NULL for `PointSF` attached to `DM` 8808 - allowExtraRoots - Flag to allow extra points not present in the `DM` 8809 8810 Level: developer 8811 8812 Notes: 8813 This is mainly intended for debugging/testing purposes. 8814 8815 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8816 8817 Extra roots can come from priodic cuts, where additional points appear on the boundary 8818 8819 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 8820 @*/ 8821 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 8822 { 8823 PetscInt l, nleaves, nroots, overlap; 8824 const PetscInt *locals; 8825 const PetscSFNode *remotes; 8826 PetscBool distributed; 8827 MPI_Comm comm; 8828 PetscMPIInt rank; 8829 8830 PetscFunctionBegin; 8831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8832 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8833 else pointSF = dm->sf; 8834 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8835 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8836 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8837 { 8838 PetscMPIInt mpiFlag; 8839 8840 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8841 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8842 } 8843 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8844 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8845 if (!distributed) { 8846 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); 8847 PetscFunctionReturn(0); 8848 } 8849 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); 8850 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8851 8852 /* Check SF graph is compatible with DMPlex chart */ 8853 { 8854 PetscInt pStart, pEnd, maxLeaf; 8855 8856 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8857 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8858 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8859 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8860 } 8861 8862 /* Check Point SF has no local points referenced */ 8863 for (l = 0; l < nleaves; l++) { 8864 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); 8865 } 8866 8867 /* Check there are no cells in interface */ 8868 if (!overlap) { 8869 PetscInt cellHeight, cStart, cEnd; 8870 8871 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8872 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8873 for (l = 0; l < nleaves; ++l) { 8874 const PetscInt point = locals ? locals[l] : l; 8875 8876 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8877 } 8878 } 8879 8880 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8881 { 8882 const PetscInt *rootdegree; 8883 8884 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8885 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8886 for (l = 0; l < nleaves; ++l) { 8887 const PetscInt point = locals ? locals[l] : l; 8888 const PetscInt *cone; 8889 PetscInt coneSize, c, idx; 8890 8891 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8892 PetscCall(DMPlexGetCone(dm, point, &cone)); 8893 for (c = 0; c < coneSize; ++c) { 8894 if (!rootdegree[cone[c]]) { 8895 if (locals) { 8896 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8897 } else { 8898 idx = (cone[c] < nleaves) ? cone[c] : -1; 8899 } 8900 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8901 } 8902 } 8903 } 8904 } 8905 PetscFunctionReturn(0); 8906 } 8907 8908 /*@ 8909 DMPlexCheck - Perform various checks of Plex sanity 8910 8911 Input Parameter: 8912 . dm - The `DMPLEX` object 8913 8914 Level: developer 8915 8916 Notes: 8917 This is a useful diagnostic when creating meshes programmatically. 8918 8919 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8920 8921 Currently does not include DMPlexCheckCellShape(). 8922 8923 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, DMCreate(), DMSetFromOptions() 8924 @*/ 8925 PetscErrorCode DMPlexCheck(DM dm) 8926 { 8927 PetscInt cellHeight; 8928 8929 PetscFunctionBegin; 8930 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8931 PetscCall(DMPlexCheckSymmetry(dm)); 8932 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8933 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8934 PetscCall(DMPlexCheckGeometry(dm)); 8935 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 8936 PetscCall(DMPlexCheckInterfaceCones(dm)); 8937 PetscFunctionReturn(0); 8938 } 8939 8940 typedef struct cell_stats { 8941 PetscReal min, max, sum, squaresum; 8942 PetscInt count; 8943 } cell_stats_t; 8944 8945 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 8946 { 8947 PetscInt i, N = *len; 8948 8949 for (i = 0; i < N; i++) { 8950 cell_stats_t *A = (cell_stats_t *)a; 8951 cell_stats_t *B = (cell_stats_t *)b; 8952 8953 B->min = PetscMin(A->min, B->min); 8954 B->max = PetscMax(A->max, B->max); 8955 B->sum += A->sum; 8956 B->squaresum += A->squaresum; 8957 B->count += A->count; 8958 } 8959 } 8960 8961 /*@ 8962 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8963 8964 Collective on dm 8965 8966 Input Parameters: 8967 + dm - The `DMPLEX` object 8968 . output - If true, statistics will be displayed on stdout 8969 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 8970 8971 Level: developer 8972 8973 Notes: 8974 This is mainly intended for debugging/testing purposes. 8975 8976 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8977 8978 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8979 @*/ 8980 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8981 { 8982 DM dmCoarse; 8983 cell_stats_t stats, globalStats; 8984 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8985 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8986 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8987 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8988 PetscMPIInt rank, size; 8989 8990 PetscFunctionBegin; 8991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8992 stats.min = PETSC_MAX_REAL; 8993 stats.max = PETSC_MIN_REAL; 8994 stats.sum = stats.squaresum = 0.; 8995 stats.count = 0; 8996 8997 PetscCallMPI(MPI_Comm_size(comm, &size)); 8998 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8999 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9000 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9001 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9002 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9003 for (c = cStart; c < cEnd; c++) { 9004 PetscInt i; 9005 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9006 9007 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9008 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9009 for (i = 0; i < PetscSqr(cdim); ++i) { 9010 frobJ += J[i] * J[i]; 9011 frobInvJ += invJ[i] * invJ[i]; 9012 } 9013 cond2 = frobJ * frobInvJ; 9014 cond = PetscSqrtReal(cond2); 9015 9016 stats.min = PetscMin(stats.min, cond); 9017 stats.max = PetscMax(stats.max, cond); 9018 stats.sum += cond; 9019 stats.squaresum += cond2; 9020 stats.count++; 9021 if (output && cond > limit) { 9022 PetscSection coordSection; 9023 Vec coordsLocal; 9024 PetscScalar *coords = NULL; 9025 PetscInt Nv, d, clSize, cl, *closure = NULL; 9026 9027 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9028 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9029 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9030 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9031 for (i = 0; i < Nv / cdim; ++i) { 9032 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9033 for (d = 0; d < cdim; ++d) { 9034 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9035 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9036 } 9037 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9038 } 9039 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9040 for (cl = 0; cl < clSize * 2; cl += 2) { 9041 const PetscInt edge = closure[cl]; 9042 9043 if ((edge >= eStart) && (edge < eEnd)) { 9044 PetscReal len; 9045 9046 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9047 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9048 } 9049 } 9050 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9051 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9052 } 9053 } 9054 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9055 9056 if (size > 1) { 9057 PetscMPIInt blockLengths[2] = {4, 1}; 9058 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9059 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9060 MPI_Op statReduce; 9061 9062 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9063 PetscCallMPI(MPI_Type_commit(&statType)); 9064 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9065 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9066 PetscCallMPI(MPI_Op_free(&statReduce)); 9067 PetscCallMPI(MPI_Type_free(&statType)); 9068 } else { 9069 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9070 } 9071 if (rank == 0) { 9072 count = globalStats.count; 9073 min = globalStats.min; 9074 max = globalStats.max; 9075 mean = globalStats.sum / globalStats.count; 9076 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9077 } 9078 9079 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)); 9080 PetscCall(PetscFree2(J, invJ)); 9081 9082 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9083 if (dmCoarse) { 9084 PetscBool isplex; 9085 9086 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9087 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9088 } 9089 PetscFunctionReturn(0); 9090 } 9091 9092 /*@ 9093 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9094 orthogonal quality below given tolerance. 9095 9096 Collective on dm 9097 9098 Input Parameters: 9099 + dm - The `DMPLEX` object 9100 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9101 - atol - [0, 1] Absolute tolerance for tagging cells. 9102 9103 Output Parameters: 9104 + OrthQual - Vec containing orthogonal quality per cell 9105 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9106 9107 Options Database Keys: 9108 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9109 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9110 9111 Level: intermediate 9112 9113 Notes: 9114 Orthogonal quality is given by the following formula: 9115 9116 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9117 9118 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 9119 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9120 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9121 calculating the cosine of the angle between these vectors. 9122 9123 Orthogonal quality ranges from 1 (best) to 0 (worst). 9124 9125 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9126 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9127 9128 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9129 9130 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9131 @*/ 9132 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9133 { 9134 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9135 PetscInt *idx; 9136 PetscScalar *oqVals; 9137 const PetscScalar *cellGeomArr, *faceGeomArr; 9138 PetscReal *ci, *fi, *Ai; 9139 MPI_Comm comm; 9140 Vec cellgeom, facegeom; 9141 DM dmFace, dmCell; 9142 IS glob; 9143 ISLocalToGlobalMapping ltog; 9144 PetscViewer vwr; 9145 9146 PetscFunctionBegin; 9147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9148 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9149 PetscValidPointer(OrthQual, 4); 9150 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9151 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9152 PetscCall(DMGetDimension(dm, &nc)); 9153 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9154 { 9155 DMPlexInterpolatedFlag interpFlag; 9156 9157 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9158 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9159 PetscMPIInt rank; 9160 9161 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9162 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9163 } 9164 } 9165 if (OrthQualLabel) { 9166 PetscValidPointer(OrthQualLabel, 5); 9167 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9168 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9169 } else { 9170 *OrthQualLabel = NULL; 9171 } 9172 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9173 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9174 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9175 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9176 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9177 PetscCall(VecCreate(comm, OrthQual)); 9178 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9179 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9180 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9181 PetscCall(VecSetUp(*OrthQual)); 9182 PetscCall(ISDestroy(&glob)); 9183 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9184 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9185 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9186 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9187 PetscCall(VecGetDM(cellgeom, &dmCell)); 9188 PetscCall(VecGetDM(facegeom, &dmFace)); 9189 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9190 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9191 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9192 PetscInt cellarr[2], *adj = NULL; 9193 PetscScalar *cArr, *fArr; 9194 PetscReal minvalc = 1.0, minvalf = 1.0; 9195 PetscFVCellGeom *cg; 9196 9197 idx[cellIter] = cell - cStart; 9198 cellarr[0] = cell; 9199 /* Make indexing into cellGeom easier */ 9200 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9201 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9202 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9203 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9204 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9205 PetscInt i; 9206 const PetscInt neigh = adj[cellneigh]; 9207 PetscReal normci = 0, normfi = 0, normai = 0; 9208 PetscFVCellGeom *cgneigh; 9209 PetscFVFaceGeom *fg; 9210 9211 /* Don't count ourselves in the neighbor list */ 9212 if (neigh == cell) continue; 9213 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9214 cellarr[1] = neigh; 9215 { 9216 PetscInt numcovpts; 9217 const PetscInt *covpts; 9218 9219 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9220 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9221 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9222 } 9223 9224 /* Compute c_i, f_i and their norms */ 9225 for (i = 0; i < nc; i++) { 9226 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9227 fi[i] = fg->centroid[i] - cg->centroid[i]; 9228 Ai[i] = fg->normal[i]; 9229 normci += PetscPowReal(ci[i], 2); 9230 normfi += PetscPowReal(fi[i], 2); 9231 normai += PetscPowReal(Ai[i], 2); 9232 } 9233 normci = PetscSqrtReal(normci); 9234 normfi = PetscSqrtReal(normfi); 9235 normai = PetscSqrtReal(normai); 9236 9237 /* Normalize and compute for each face-cell-normal pair */ 9238 for (i = 0; i < nc; i++) { 9239 ci[i] = ci[i] / normci; 9240 fi[i] = fi[i] / normfi; 9241 Ai[i] = Ai[i] / normai; 9242 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9243 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9244 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9245 } 9246 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9247 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9248 } 9249 PetscCall(PetscFree(adj)); 9250 PetscCall(PetscFree2(cArr, fArr)); 9251 /* Defer to cell if they're equal */ 9252 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9253 if (OrthQualLabel) { 9254 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9255 } 9256 } 9257 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9258 PetscCall(VecAssemblyBegin(*OrthQual)); 9259 PetscCall(VecAssemblyEnd(*OrthQual)); 9260 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9261 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9262 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9263 if (OrthQualLabel) { 9264 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9265 } 9266 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9267 PetscCall(PetscViewerDestroy(&vwr)); 9268 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9269 PetscFunctionReturn(0); 9270 } 9271 9272 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9273 * interpolator construction */ 9274 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9275 { 9276 PetscSection section, newSection, gsection; 9277 PetscSF sf; 9278 PetscBool hasConstraints, ghasConstraints; 9279 9280 PetscFunctionBegin; 9281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9282 PetscValidPointer(odm, 2); 9283 PetscCall(DMGetLocalSection(dm, §ion)); 9284 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9285 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9286 if (!ghasConstraints) { 9287 PetscCall(PetscObjectReference((PetscObject)dm)); 9288 *odm = dm; 9289 PetscFunctionReturn(0); 9290 } 9291 PetscCall(DMClone(dm, odm)); 9292 PetscCall(DMCopyFields(dm, *odm)); 9293 PetscCall(DMGetLocalSection(*odm, &newSection)); 9294 PetscCall(DMGetPointSF(*odm, &sf)); 9295 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9296 PetscCall(DMSetGlobalSection(*odm, gsection)); 9297 PetscCall(PetscSectionDestroy(&gsection)); 9298 PetscFunctionReturn(0); 9299 } 9300 9301 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9302 { 9303 DM dmco, dmfo; 9304 Mat interpo; 9305 Vec rscale; 9306 Vec cglobalo, clocal; 9307 Vec fglobal, fglobalo, flocal; 9308 PetscBool regular; 9309 9310 PetscFunctionBegin; 9311 PetscCall(DMGetFullDM(dmc, &dmco)); 9312 PetscCall(DMGetFullDM(dmf, &dmfo)); 9313 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9314 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9315 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9316 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9317 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9318 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9319 PetscCall(VecSet(cglobalo, 0.)); 9320 PetscCall(VecSet(clocal, 0.)); 9321 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9322 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9323 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9324 PetscCall(VecSet(fglobal, 0.)); 9325 PetscCall(VecSet(fglobalo, 0.)); 9326 PetscCall(VecSet(flocal, 0.)); 9327 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9328 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9329 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9330 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9331 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9332 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9333 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9334 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9335 *shift = fglobal; 9336 PetscCall(VecDestroy(&flocal)); 9337 PetscCall(VecDestroy(&fglobalo)); 9338 PetscCall(VecDestroy(&clocal)); 9339 PetscCall(VecDestroy(&cglobalo)); 9340 PetscCall(VecDestroy(&rscale)); 9341 PetscCall(MatDestroy(&interpo)); 9342 PetscCall(DMDestroy(&dmfo)); 9343 PetscCall(DMDestroy(&dmco)); 9344 PetscFunctionReturn(0); 9345 } 9346 9347 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9348 { 9349 PetscObject shifto; 9350 Vec shift; 9351 9352 PetscFunctionBegin; 9353 if (!interp) { 9354 Vec rscale; 9355 9356 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9357 PetscCall(VecDestroy(&rscale)); 9358 } else { 9359 PetscCall(PetscObjectReference((PetscObject)interp)); 9360 } 9361 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9362 if (!shifto) { 9363 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9364 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9365 shifto = (PetscObject)shift; 9366 PetscCall(VecDestroy(&shift)); 9367 } 9368 shift = (Vec)shifto; 9369 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9370 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9371 PetscCall(MatDestroy(&interp)); 9372 PetscFunctionReturn(0); 9373 } 9374 9375 /* Pointwise interpolation 9376 Just code FEM for now 9377 u^f = I u^c 9378 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9379 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9380 I_{ij} = psi^f_i phi^c_j 9381 */ 9382 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9383 { 9384 PetscSection gsc, gsf; 9385 PetscInt m, n; 9386 void *ctx; 9387 DM cdm; 9388 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9389 9390 PetscFunctionBegin; 9391 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9392 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9393 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9394 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9395 9396 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9397 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9398 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9399 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9400 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9401 9402 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9403 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9404 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9405 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9406 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9407 if (scaling) { 9408 /* Use naive scaling */ 9409 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9410 } 9411 PetscFunctionReturn(0); 9412 } 9413 9414 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9415 { 9416 VecScatter ctx; 9417 9418 PetscFunctionBegin; 9419 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9420 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9421 PetscCall(VecScatterDestroy(&ctx)); 9422 PetscFunctionReturn(0); 9423 } 9424 9425 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[]) 9426 { 9427 const PetscInt Nc = uOff[1] - uOff[0]; 9428 PetscInt c; 9429 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9430 } 9431 9432 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9433 { 9434 DM dmc; 9435 PetscDS ds; 9436 Vec ones, locmass; 9437 IS cellIS; 9438 PetscFormKey key; 9439 PetscInt depth; 9440 9441 PetscFunctionBegin; 9442 PetscCall(DMClone(dm, &dmc)); 9443 PetscCall(DMCopyDisc(dm, dmc)); 9444 PetscCall(DMGetDS(dmc, &ds)); 9445 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9446 PetscCall(DMCreateGlobalVector(dmc, mass)); 9447 PetscCall(DMGetLocalVector(dmc, &ones)); 9448 PetscCall(DMGetLocalVector(dmc, &locmass)); 9449 PetscCall(DMPlexGetDepth(dmc, &depth)); 9450 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9451 PetscCall(VecSet(locmass, 0.0)); 9452 PetscCall(VecSet(ones, 1.0)); 9453 key.label = NULL; 9454 key.value = 0; 9455 key.field = 0; 9456 key.part = 0; 9457 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9458 PetscCall(ISDestroy(&cellIS)); 9459 PetscCall(VecSet(*mass, 0.0)); 9460 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9461 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9462 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9463 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9464 PetscCall(DMDestroy(&dmc)); 9465 PetscFunctionReturn(0); 9466 } 9467 9468 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9469 { 9470 PetscSection gsc, gsf; 9471 PetscInt m, n; 9472 void *ctx; 9473 DM cdm; 9474 PetscBool regular; 9475 9476 PetscFunctionBegin; 9477 if (dmFine == dmCoarse) { 9478 DM dmc; 9479 PetscDS ds; 9480 PetscWeakForm wf; 9481 Vec u; 9482 IS cellIS; 9483 PetscFormKey key; 9484 PetscInt depth; 9485 9486 PetscCall(DMClone(dmFine, &dmc)); 9487 PetscCall(DMCopyDisc(dmFine, dmc)); 9488 PetscCall(DMGetDS(dmc, &ds)); 9489 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9490 PetscCall(PetscWeakFormClear(wf)); 9491 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9492 PetscCall(DMCreateMatrix(dmc, mass)); 9493 PetscCall(DMGetLocalVector(dmc, &u)); 9494 PetscCall(DMPlexGetDepth(dmc, &depth)); 9495 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9496 PetscCall(MatZeroEntries(*mass)); 9497 key.label = NULL; 9498 key.value = 0; 9499 key.field = 0; 9500 key.part = 0; 9501 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9502 PetscCall(ISDestroy(&cellIS)); 9503 PetscCall(DMRestoreLocalVector(dmc, &u)); 9504 PetscCall(DMDestroy(&dmc)); 9505 } else { 9506 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9507 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9508 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9509 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9510 9511 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9512 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9513 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9514 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9515 9516 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9517 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9518 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9519 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9520 } 9521 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9522 PetscFunctionReturn(0); 9523 } 9524 9525 /*@ 9526 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9527 9528 Input Parameter: 9529 . dm - The `DMPLEX` object 9530 9531 Output Parameter: 9532 . regular - The flag 9533 9534 Level: intermediate 9535 9536 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9537 @*/ 9538 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9539 { 9540 PetscFunctionBegin; 9541 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9542 PetscValidBoolPointer(regular, 2); 9543 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9544 PetscFunctionReturn(0); 9545 } 9546 9547 /*@ 9548 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9549 9550 Input Parameters: 9551 + dm - The `DMPLEX` object 9552 - regular - The flag 9553 9554 Level: intermediate 9555 9556 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9557 @*/ 9558 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9559 { 9560 PetscFunctionBegin; 9561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9562 ((DM_Plex *)dm->data)->regularRefinement = regular; 9563 PetscFunctionReturn(0); 9564 } 9565 9566 /*@ 9567 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9568 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9569 9570 Not Collective 9571 9572 Input Parameter: 9573 . dm - The `DMPLEX` object 9574 9575 Output Parameters: 9576 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9577 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9578 9579 Level: intermediate 9580 9581 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9582 @*/ 9583 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9584 { 9585 DM_Plex *plex = (DM_Plex *)dm->data; 9586 9587 PetscFunctionBegin; 9588 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9589 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9590 if (anchorSection) *anchorSection = plex->anchorSection; 9591 if (anchorIS) *anchorIS = plex->anchorIS; 9592 PetscFunctionReturn(0); 9593 } 9594 9595 /*@ 9596 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9597 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9598 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9599 9600 Collective on dm 9601 9602 Input Parameters: 9603 + dm - The `DMPLEX` object 9604 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9605 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9606 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9607 9608 Level: intermediate 9609 9610 Notes: 9611 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9612 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9613 9614 The reference counts of anchorSection and anchorIS are incremented. 9615 9616 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9617 @*/ 9618 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9619 { 9620 DM_Plex *plex = (DM_Plex *)dm->data; 9621 PetscMPIInt result; 9622 9623 PetscFunctionBegin; 9624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9625 if (anchorSection) { 9626 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9627 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9628 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9629 } 9630 if (anchorIS) { 9631 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9632 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9633 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9634 } 9635 9636 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9637 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9638 plex->anchorSection = anchorSection; 9639 9640 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9641 PetscCall(ISDestroy(&plex->anchorIS)); 9642 plex->anchorIS = anchorIS; 9643 9644 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9645 PetscInt size, a, pStart, pEnd; 9646 const PetscInt *anchors; 9647 9648 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9649 PetscCall(ISGetLocalSize(anchorIS, &size)); 9650 PetscCall(ISGetIndices(anchorIS, &anchors)); 9651 for (a = 0; a < size; a++) { 9652 PetscInt p; 9653 9654 p = anchors[a]; 9655 if (p >= pStart && p < pEnd) { 9656 PetscInt dof; 9657 9658 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9659 if (dof) { 9660 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9661 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9662 } 9663 } 9664 } 9665 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9666 } 9667 /* reset the generic constraints */ 9668 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9669 PetscFunctionReturn(0); 9670 } 9671 9672 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9673 { 9674 PetscSection anchorSection; 9675 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9676 9677 PetscFunctionBegin; 9678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9679 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9680 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9681 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9682 if (numFields) { 9683 PetscInt f; 9684 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9685 9686 for (f = 0; f < numFields; f++) { 9687 PetscInt numComp; 9688 9689 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9690 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9691 } 9692 } 9693 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9694 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9695 pStart = PetscMax(pStart, sStart); 9696 pEnd = PetscMin(pEnd, sEnd); 9697 pEnd = PetscMax(pStart, pEnd); 9698 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9699 for (p = pStart; p < pEnd; p++) { 9700 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9701 if (dof) { 9702 PetscCall(PetscSectionGetDof(section, p, &dof)); 9703 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9704 for (f = 0; f < numFields; f++) { 9705 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9706 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9707 } 9708 } 9709 } 9710 PetscCall(PetscSectionSetUp(*cSec)); 9711 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9712 PetscFunctionReturn(0); 9713 } 9714 9715 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9716 { 9717 PetscSection aSec; 9718 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9719 const PetscInt *anchors; 9720 PetscInt numFields, f; 9721 IS aIS; 9722 MatType mtype; 9723 PetscBool iscuda, iskokkos; 9724 9725 PetscFunctionBegin; 9726 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9727 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9728 PetscCall(PetscSectionGetStorageSize(section, &n)); 9729 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9730 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9731 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9732 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9733 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9734 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9735 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9736 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9737 else mtype = MATSEQAIJ; 9738 PetscCall(MatSetType(*cMat, mtype)); 9739 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9740 PetscCall(ISGetIndices(aIS, &anchors)); 9741 /* cSec will be a subset of aSec and section */ 9742 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9743 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9744 PetscCall(PetscMalloc1(m + 1, &i)); 9745 i[0] = 0; 9746 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9747 for (p = pStart; p < pEnd; p++) { 9748 PetscInt rDof, rOff, r; 9749 9750 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9751 if (!rDof) continue; 9752 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9753 if (numFields) { 9754 for (f = 0; f < numFields; f++) { 9755 annz = 0; 9756 for (r = 0; r < rDof; r++) { 9757 a = anchors[rOff + r]; 9758 if (a < sStart || a >= sEnd) continue; 9759 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9760 annz += aDof; 9761 } 9762 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9763 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9764 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9765 } 9766 } else { 9767 annz = 0; 9768 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9769 for (q = 0; q < dof; q++) { 9770 a = anchors[rOff + q]; 9771 if (a < sStart || a >= sEnd) continue; 9772 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9773 annz += aDof; 9774 } 9775 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9776 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9777 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9778 } 9779 } 9780 nnz = i[m]; 9781 PetscCall(PetscMalloc1(nnz, &j)); 9782 offset = 0; 9783 for (p = pStart; p < pEnd; p++) { 9784 if (numFields) { 9785 for (f = 0; f < numFields; f++) { 9786 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9787 for (q = 0; q < dof; q++) { 9788 PetscInt rDof, rOff, r; 9789 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9790 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9791 for (r = 0; r < rDof; r++) { 9792 PetscInt s; 9793 9794 a = anchors[rOff + r]; 9795 if (a < sStart || a >= sEnd) continue; 9796 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9797 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9798 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9799 } 9800 } 9801 } 9802 } else { 9803 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9804 for (q = 0; q < dof; q++) { 9805 PetscInt rDof, rOff, r; 9806 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9807 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9808 for (r = 0; r < rDof; r++) { 9809 PetscInt s; 9810 9811 a = anchors[rOff + r]; 9812 if (a < sStart || a >= sEnd) continue; 9813 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9814 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9815 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9816 } 9817 } 9818 } 9819 } 9820 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9821 PetscCall(PetscFree(i)); 9822 PetscCall(PetscFree(j)); 9823 PetscCall(ISRestoreIndices(aIS, &anchors)); 9824 PetscFunctionReturn(0); 9825 } 9826 9827 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9828 { 9829 DM_Plex *plex = (DM_Plex *)dm->data; 9830 PetscSection anchorSection, section, cSec; 9831 Mat cMat; 9832 9833 PetscFunctionBegin; 9834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9835 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9836 if (anchorSection) { 9837 PetscInt Nf; 9838 9839 PetscCall(DMGetLocalSection(dm, §ion)); 9840 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9841 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9842 PetscCall(DMGetNumFields(dm, &Nf)); 9843 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9844 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9845 PetscCall(PetscSectionDestroy(&cSec)); 9846 PetscCall(MatDestroy(&cMat)); 9847 } 9848 PetscFunctionReturn(0); 9849 } 9850 9851 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9852 { 9853 IS subis; 9854 PetscSection section, subsection; 9855 9856 PetscFunctionBegin; 9857 PetscCall(DMGetLocalSection(dm, §ion)); 9858 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9859 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9860 /* Create subdomain */ 9861 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9862 /* Create submodel */ 9863 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9864 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9865 PetscCall(DMSetLocalSection(*subdm, subsection)); 9866 PetscCall(PetscSectionDestroy(&subsection)); 9867 PetscCall(DMCopyDisc(dm, *subdm)); 9868 /* Create map from submodel to global model */ 9869 if (is) { 9870 PetscSection sectionGlobal, subsectionGlobal; 9871 IS spIS; 9872 const PetscInt *spmap; 9873 PetscInt *subIndices; 9874 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9875 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9876 9877 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9878 PetscCall(ISGetIndices(spIS, &spmap)); 9879 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9880 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9881 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9882 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9883 for (p = pStart; p < pEnd; ++p) { 9884 PetscInt gdof, pSubSize = 0; 9885 9886 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9887 if (gdof > 0) { 9888 for (f = 0; f < Nf; ++f) { 9889 PetscInt fdof, fcdof; 9890 9891 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9892 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9893 pSubSize += fdof - fcdof; 9894 } 9895 subSize += pSubSize; 9896 if (pSubSize) { 9897 if (bs < 0) { 9898 bs = pSubSize; 9899 } else if (bs != pSubSize) { 9900 /* Layout does not admit a pointwise block size */ 9901 bs = 1; 9902 } 9903 } 9904 } 9905 } 9906 /* Must have same blocksize on all procs (some might have no points) */ 9907 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9908 bsLocal[1] = bs; 9909 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9910 if (bsMinMax[0] != bsMinMax[1]) { 9911 bs = 1; 9912 } else { 9913 bs = bsMinMax[0]; 9914 } 9915 PetscCall(PetscMalloc1(subSize, &subIndices)); 9916 for (p = pStart; p < pEnd; ++p) { 9917 PetscInt gdof, goff; 9918 9919 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9920 if (gdof > 0) { 9921 const PetscInt point = spmap[p]; 9922 9923 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9924 for (f = 0; f < Nf; ++f) { 9925 PetscInt fdof, fcdof, fc, f2, poff = 0; 9926 9927 /* Can get rid of this loop by storing field information in the global section */ 9928 for (f2 = 0; f2 < f; ++f2) { 9929 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9930 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9931 poff += fdof - fcdof; 9932 } 9933 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9934 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9935 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 9936 } 9937 } 9938 } 9939 PetscCall(ISRestoreIndices(spIS, &spmap)); 9940 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9941 if (bs > 1) { 9942 /* We need to check that the block size does not come from non-contiguous fields */ 9943 PetscInt i, j, set = 1; 9944 for (i = 0; i < subSize; i += bs) { 9945 for (j = 0; j < bs; ++j) { 9946 if (subIndices[i + j] != subIndices[i] + j) { 9947 set = 0; 9948 break; 9949 } 9950 } 9951 } 9952 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9953 } 9954 /* Attach nullspace */ 9955 for (f = 0; f < Nf; ++f) { 9956 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9957 if ((*subdm)->nullspaceConstructors[f]) break; 9958 } 9959 if (f < Nf) { 9960 MatNullSpace nullSpace; 9961 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9962 9963 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9964 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9965 } 9966 } 9967 PetscFunctionReturn(0); 9968 } 9969 9970 /*@ 9971 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9972 9973 Input Parameters: 9974 + dm - The `DM` 9975 - dummy - unused argument 9976 9977 Options Database Key: 9978 . -dm_plex_monitor_throughput - Activate the monitor 9979 9980 Level: developer 9981 9982 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 9983 @*/ 9984 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9985 { 9986 #if defined(PETSC_USE_LOG) 9987 PetscStageLog stageLog; 9988 PetscLogEvent event; 9989 PetscLogStage stage; 9990 PetscEventPerfInfo eventInfo; 9991 PetscReal cellRate, flopRate; 9992 PetscInt cStart, cEnd, Nf, N; 9993 const char *name; 9994 #endif 9995 9996 PetscFunctionBegin; 9997 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9998 #if defined(PETSC_USE_LOG) 9999 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10000 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10001 PetscCall(DMGetNumFields(dm, &Nf)); 10002 PetscCall(PetscLogGetStageLog(&stageLog)); 10003 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10004 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10005 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10006 N = (cEnd - cStart) * Nf * eventInfo.count; 10007 flopRate = eventInfo.flops / eventInfo.time; 10008 cellRate = N / eventInfo.time; 10009 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))); 10010 #else 10011 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10012 #endif 10013 PetscFunctionReturn(0); 10014 } 10015