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 Level: intermediate 5852 5853 Notes: 5854 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to NULL in the 5855 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 5856 assembly function, and a user may already have allocated storage for this operation. 5857 5858 A typical use could be 5859 .vb 5860 values = NULL; 5861 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5862 for (cl = 0; cl < clSize; ++cl) { 5863 <Compute on closure> 5864 } 5865 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5866 .ve 5867 or 5868 .vb 5869 PetscMalloc1(clMaxSize, &values); 5870 for (p = pStart; p < pEnd; ++p) { 5871 clSize = clMaxSize; 5872 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5873 for (cl = 0; cl < clSize; ++cl) { 5874 <Compute on closure> 5875 } 5876 } 5877 PetscFree(values); 5878 .ve 5879 5880 Fortran Note: 5881 The csize argument is not present in the Fortran binding since it is internal to the array. 5882 5883 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5884 @*/ 5885 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5886 { 5887 PetscSection clSection; 5888 IS clPoints; 5889 PetscInt *points = NULL; 5890 const PetscInt *clp, *perm; 5891 PetscInt depth, numFields, numPoints, asize; 5892 5893 PetscFunctionBeginHot; 5894 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5895 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5896 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5897 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5898 PetscCall(DMPlexGetDepth(dm, &depth)); 5899 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5900 if (depth == 1 && numFields < 2) { 5901 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5902 PetscFunctionReturn(0); 5903 } 5904 /* Get points */ 5905 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5906 /* Get sizes */ 5907 asize = 0; 5908 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5909 PetscInt dof; 5910 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5911 asize += dof; 5912 } 5913 if (values) { 5914 const PetscScalar *vArray; 5915 PetscInt size; 5916 5917 if (*values) { 5918 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); 5919 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5920 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5921 PetscCall(VecGetArrayRead(v, &vArray)); 5922 /* Get values */ 5923 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5924 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5925 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5926 /* Cleanup array */ 5927 PetscCall(VecRestoreArrayRead(v, &vArray)); 5928 } 5929 if (csize) *csize = asize; 5930 /* Cleanup points */ 5931 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5932 PetscFunctionReturn(0); 5933 } 5934 5935 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5936 { 5937 DMLabel depthLabel; 5938 PetscSection clSection; 5939 IS clPoints; 5940 PetscScalar *array; 5941 const PetscScalar *vArray; 5942 PetscInt *points = NULL; 5943 const PetscInt *clp, *perm = NULL; 5944 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5945 5946 PetscFunctionBeginHot; 5947 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5948 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5949 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5950 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5951 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5952 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5953 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5954 if (mdepth == 1 && numFields < 2) { 5955 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5956 PetscFunctionReturn(0); 5957 } 5958 /* Get points */ 5959 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5960 for (clsize = 0, p = 0; p < Np; p++) { 5961 PetscInt dof; 5962 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 5963 clsize += dof; 5964 } 5965 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 5966 /* Filter points */ 5967 for (p = 0; p < numPoints * 2; p += 2) { 5968 PetscInt dep; 5969 5970 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5971 if (dep != depth) continue; 5972 points[Np * 2 + 0] = points[p]; 5973 points[Np * 2 + 1] = points[p + 1]; 5974 ++Np; 5975 } 5976 /* Get array */ 5977 if (!values || !*values) { 5978 PetscInt asize = 0, dof; 5979 5980 for (p = 0; p < Np * 2; p += 2) { 5981 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5982 asize += dof; 5983 } 5984 if (!values) { 5985 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5986 if (csize) *csize = asize; 5987 PetscFunctionReturn(0); 5988 } 5989 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5990 } else { 5991 array = *values; 5992 } 5993 PetscCall(VecGetArrayRead(v, &vArray)); 5994 /* Get values */ 5995 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5996 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5997 /* Cleanup points */ 5998 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5999 /* Cleanup array */ 6000 PetscCall(VecRestoreArrayRead(v, &vArray)); 6001 if (!*values) { 6002 if (csize) *csize = size; 6003 *values = array; 6004 } else { 6005 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6006 *csize = size; 6007 } 6008 PetscFunctionReturn(0); 6009 } 6010 6011 /*@C 6012 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6013 6014 Not collective 6015 6016 Input Parameters: 6017 + dm - The `DM` 6018 . section - The section describing the layout in v, or NULL to use the default section 6019 . v - The local vector 6020 . point - The point in the `DM` 6021 . csize - The number of values in the closure, or NULL 6022 - values - The array of values, which is a borrowed array and should not be freed 6023 6024 Level: intermediate 6025 6026 Note: 6027 The array values are discarded and not copied back into v. In order to copy values back to v, use `DMPlexVecSetClosure()` 6028 6029 Fortran Note: 6030 The csize argument is not present in the Fortran binding since it is internal to the array. 6031 6032 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6033 @*/ 6034 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6035 { 6036 PetscInt size = 0; 6037 6038 PetscFunctionBegin; 6039 /* Should work without recalculating size */ 6040 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6041 *values = NULL; 6042 PetscFunctionReturn(0); 6043 } 6044 6045 static inline void add(PetscScalar *x, PetscScalar y) 6046 { 6047 *x += y; 6048 } 6049 static inline void insert(PetscScalar *x, PetscScalar y) 6050 { 6051 *x = y; 6052 } 6053 6054 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[]) 6055 { 6056 PetscInt cdof; /* The number of constraints on this point */ 6057 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6058 PetscScalar *a; 6059 PetscInt off, cind = 0, k; 6060 6061 PetscFunctionBegin; 6062 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6063 PetscCall(PetscSectionGetOffset(section, point, &off)); 6064 a = &array[off]; 6065 if (!cdof || setBC) { 6066 if (clperm) { 6067 if (perm) { 6068 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6069 } else { 6070 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6071 } 6072 } else { 6073 if (perm) { 6074 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6075 } else { 6076 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6077 } 6078 } 6079 } else { 6080 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6081 if (clperm) { 6082 if (perm) { 6083 for (k = 0; k < dof; ++k) { 6084 if ((cind < cdof) && (k == cdofs[cind])) { 6085 ++cind; 6086 continue; 6087 } 6088 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6089 } 6090 } else { 6091 for (k = 0; k < dof; ++k) { 6092 if ((cind < cdof) && (k == cdofs[cind])) { 6093 ++cind; 6094 continue; 6095 } 6096 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6097 } 6098 } 6099 } else { 6100 if (perm) { 6101 for (k = 0; k < dof; ++k) { 6102 if ((cind < cdof) && (k == cdofs[cind])) { 6103 ++cind; 6104 continue; 6105 } 6106 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6107 } 6108 } else { 6109 for (k = 0; k < dof; ++k) { 6110 if ((cind < cdof) && (k == cdofs[cind])) { 6111 ++cind; 6112 continue; 6113 } 6114 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6115 } 6116 } 6117 } 6118 } 6119 PetscFunctionReturn(0); 6120 } 6121 6122 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[]) 6123 { 6124 PetscInt cdof; /* The number of constraints on this point */ 6125 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6126 PetscScalar *a; 6127 PetscInt off, cind = 0, k; 6128 6129 PetscFunctionBegin; 6130 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6131 PetscCall(PetscSectionGetOffset(section, point, &off)); 6132 a = &array[off]; 6133 if (cdof) { 6134 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6135 if (clperm) { 6136 if (perm) { 6137 for (k = 0; k < dof; ++k) { 6138 if ((cind < cdof) && (k == cdofs[cind])) { 6139 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6140 cind++; 6141 } 6142 } 6143 } else { 6144 for (k = 0; k < dof; ++k) { 6145 if ((cind < cdof) && (k == cdofs[cind])) { 6146 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6147 cind++; 6148 } 6149 } 6150 } 6151 } else { 6152 if (perm) { 6153 for (k = 0; k < dof; ++k) { 6154 if ((cind < cdof) && (k == cdofs[cind])) { 6155 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6156 cind++; 6157 } 6158 } 6159 } else { 6160 for (k = 0; k < dof; ++k) { 6161 if ((cind < cdof) && (k == cdofs[cind])) { 6162 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6163 cind++; 6164 } 6165 } 6166 } 6167 } 6168 } 6169 PetscFunctionReturn(0); 6170 } 6171 6172 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[]) 6173 { 6174 PetscScalar *a; 6175 PetscInt fdof, foff, fcdof, foffset = *offset; 6176 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6177 PetscInt cind = 0, b; 6178 6179 PetscFunctionBegin; 6180 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6181 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6182 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6183 a = &array[foff]; 6184 if (!fcdof || setBC) { 6185 if (clperm) { 6186 if (perm) { 6187 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6188 } else { 6189 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6190 } 6191 } else { 6192 if (perm) { 6193 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6194 } else { 6195 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6196 } 6197 } 6198 } else { 6199 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6200 if (clperm) { 6201 if (perm) { 6202 for (b = 0; b < fdof; b++) { 6203 if ((cind < fcdof) && (b == fcdofs[cind])) { 6204 ++cind; 6205 continue; 6206 } 6207 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6208 } 6209 } else { 6210 for (b = 0; b < fdof; b++) { 6211 if ((cind < fcdof) && (b == fcdofs[cind])) { 6212 ++cind; 6213 continue; 6214 } 6215 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6216 } 6217 } 6218 } else { 6219 if (perm) { 6220 for (b = 0; b < fdof; b++) { 6221 if ((cind < fcdof) && (b == fcdofs[cind])) { 6222 ++cind; 6223 continue; 6224 } 6225 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6226 } 6227 } else { 6228 for (b = 0; b < fdof; b++) { 6229 if ((cind < fcdof) && (b == fcdofs[cind])) { 6230 ++cind; 6231 continue; 6232 } 6233 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6234 } 6235 } 6236 } 6237 } 6238 *offset += fdof; 6239 PetscFunctionReturn(0); 6240 } 6241 6242 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[]) 6243 { 6244 PetscScalar *a; 6245 PetscInt fdof, foff, fcdof, foffset = *offset; 6246 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6247 PetscInt Nc, cind = 0, ncind = 0, b; 6248 PetscBool ncSet, fcSet; 6249 6250 PetscFunctionBegin; 6251 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6252 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6253 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6254 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6255 a = &array[foff]; 6256 if (fcdof) { 6257 /* We just override fcdof and fcdofs with Ncc and comps */ 6258 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6259 if (clperm) { 6260 if (perm) { 6261 if (comps) { 6262 for (b = 0; b < fdof; b++) { 6263 ncSet = fcSet = PETSC_FALSE; 6264 if (b % Nc == comps[ncind]) { 6265 ncind = (ncind + 1) % Ncc; 6266 ncSet = PETSC_TRUE; 6267 } 6268 if ((cind < fcdof) && (b == fcdofs[cind])) { 6269 ++cind; 6270 fcSet = PETSC_TRUE; 6271 } 6272 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6273 } 6274 } else { 6275 for (b = 0; b < fdof; b++) { 6276 if ((cind < fcdof) && (b == fcdofs[cind])) { 6277 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6278 ++cind; 6279 } 6280 } 6281 } 6282 } else { 6283 if (comps) { 6284 for (b = 0; b < fdof; b++) { 6285 ncSet = fcSet = PETSC_FALSE; 6286 if (b % Nc == comps[ncind]) { 6287 ncind = (ncind + 1) % Ncc; 6288 ncSet = PETSC_TRUE; 6289 } 6290 if ((cind < fcdof) && (b == fcdofs[cind])) { 6291 ++cind; 6292 fcSet = PETSC_TRUE; 6293 } 6294 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6295 } 6296 } else { 6297 for (b = 0; b < fdof; b++) { 6298 if ((cind < fcdof) && (b == fcdofs[cind])) { 6299 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6300 ++cind; 6301 } 6302 } 6303 } 6304 } 6305 } else { 6306 if (perm) { 6307 if (comps) { 6308 for (b = 0; b < fdof; b++) { 6309 ncSet = fcSet = PETSC_FALSE; 6310 if (b % Nc == comps[ncind]) { 6311 ncind = (ncind + 1) % Ncc; 6312 ncSet = PETSC_TRUE; 6313 } 6314 if ((cind < fcdof) && (b == fcdofs[cind])) { 6315 ++cind; 6316 fcSet = PETSC_TRUE; 6317 } 6318 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6319 } 6320 } else { 6321 for (b = 0; b < fdof; b++) { 6322 if ((cind < fcdof) && (b == fcdofs[cind])) { 6323 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6324 ++cind; 6325 } 6326 } 6327 } 6328 } else { 6329 if (comps) { 6330 for (b = 0; b < fdof; b++) { 6331 ncSet = fcSet = PETSC_FALSE; 6332 if (b % Nc == comps[ncind]) { 6333 ncind = (ncind + 1) % Ncc; 6334 ncSet = PETSC_TRUE; 6335 } 6336 if ((cind < fcdof) && (b == fcdofs[cind])) { 6337 ++cind; 6338 fcSet = PETSC_TRUE; 6339 } 6340 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6341 } 6342 } else { 6343 for (b = 0; b < fdof; b++) { 6344 if ((cind < fcdof) && (b == fcdofs[cind])) { 6345 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6346 ++cind; 6347 } 6348 } 6349 } 6350 } 6351 } 6352 } 6353 *offset += fdof; 6354 PetscFunctionReturn(0); 6355 } 6356 6357 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6358 { 6359 PetscScalar *array; 6360 const PetscInt *cone, *coneO; 6361 PetscInt pStart, pEnd, p, numPoints, off, dof; 6362 6363 PetscFunctionBeginHot; 6364 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6365 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6366 PetscCall(DMPlexGetCone(dm, point, &cone)); 6367 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6368 PetscCall(VecGetArray(v, &array)); 6369 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6370 const PetscInt cp = !p ? point : cone[p - 1]; 6371 const PetscInt o = !p ? 0 : coneO[p - 1]; 6372 6373 if ((cp < pStart) || (cp >= pEnd)) { 6374 dof = 0; 6375 continue; 6376 } 6377 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6378 /* ADD_VALUES */ 6379 { 6380 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6381 PetscScalar *a; 6382 PetscInt cdof, coff, cind = 0, k; 6383 6384 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6385 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6386 a = &array[coff]; 6387 if (!cdof) { 6388 if (o >= 0) { 6389 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6390 } else { 6391 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6392 } 6393 } else { 6394 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6395 if (o >= 0) { 6396 for (k = 0; k < dof; ++k) { 6397 if ((cind < cdof) && (k == cdofs[cind])) { 6398 ++cind; 6399 continue; 6400 } 6401 a[k] += values[off + k]; 6402 } 6403 } else { 6404 for (k = 0; k < dof; ++k) { 6405 if ((cind < cdof) && (k == cdofs[cind])) { 6406 ++cind; 6407 continue; 6408 } 6409 a[k] += values[off + dof - k - 1]; 6410 } 6411 } 6412 } 6413 } 6414 } 6415 PetscCall(VecRestoreArray(v, &array)); 6416 PetscFunctionReturn(0); 6417 } 6418 6419 /*@C 6420 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6421 6422 Not collective 6423 6424 Input Parameters: 6425 + dm - The `DM` 6426 . section - The section describing the layout in v, or NULL to use the default section 6427 . v - The local vector 6428 . point - The point in the DM 6429 . values - The array of values 6430 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6431 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6432 6433 Level: intermediate 6434 6435 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6436 @*/ 6437 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6438 { 6439 PetscSection clSection; 6440 IS clPoints; 6441 PetscScalar *array; 6442 PetscInt *points = NULL; 6443 const PetscInt *clp, *clperm = NULL; 6444 PetscInt depth, numFields, numPoints, p, clsize; 6445 6446 PetscFunctionBeginHot; 6447 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6448 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6449 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6450 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6451 PetscCall(DMPlexGetDepth(dm, &depth)); 6452 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6453 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6454 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6455 PetscFunctionReturn(0); 6456 } 6457 /* Get points */ 6458 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6459 for (clsize = 0, p = 0; p < numPoints; p++) { 6460 PetscInt dof; 6461 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6462 clsize += dof; 6463 } 6464 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6465 /* Get array */ 6466 PetscCall(VecGetArray(v, &array)); 6467 /* Get values */ 6468 if (numFields > 0) { 6469 PetscInt offset = 0, f; 6470 for (f = 0; f < numFields; ++f) { 6471 const PetscInt **perms = NULL; 6472 const PetscScalar **flips = NULL; 6473 6474 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6475 switch (mode) { 6476 case INSERT_VALUES: 6477 for (p = 0; p < numPoints; p++) { 6478 const PetscInt point = points[2 * p]; 6479 const PetscInt *perm = perms ? perms[p] : NULL; 6480 const PetscScalar *flip = flips ? flips[p] : NULL; 6481 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6482 } 6483 break; 6484 case INSERT_ALL_VALUES: 6485 for (p = 0; p < numPoints; p++) { 6486 const PetscInt point = points[2 * p]; 6487 const PetscInt *perm = perms ? perms[p] : NULL; 6488 const PetscScalar *flip = flips ? flips[p] : NULL; 6489 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6490 } 6491 break; 6492 case INSERT_BC_VALUES: 6493 for (p = 0; p < numPoints; p++) { 6494 const PetscInt point = points[2 * p]; 6495 const PetscInt *perm = perms ? perms[p] : NULL; 6496 const PetscScalar *flip = flips ? flips[p] : NULL; 6497 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6498 } 6499 break; 6500 case ADD_VALUES: 6501 for (p = 0; p < numPoints; p++) { 6502 const PetscInt point = points[2 * p]; 6503 const PetscInt *perm = perms ? perms[p] : NULL; 6504 const PetscScalar *flip = flips ? flips[p] : NULL; 6505 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6506 } 6507 break; 6508 case ADD_ALL_VALUES: 6509 for (p = 0; p < numPoints; p++) { 6510 const PetscInt point = points[2 * p]; 6511 const PetscInt *perm = perms ? perms[p] : NULL; 6512 const PetscScalar *flip = flips ? flips[p] : NULL; 6513 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6514 } 6515 break; 6516 case ADD_BC_VALUES: 6517 for (p = 0; p < numPoints; p++) { 6518 const PetscInt point = points[2 * p]; 6519 const PetscInt *perm = perms ? perms[p] : NULL; 6520 const PetscScalar *flip = flips ? flips[p] : NULL; 6521 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6522 } 6523 break; 6524 default: 6525 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6526 } 6527 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6528 } 6529 } else { 6530 PetscInt dof, off; 6531 const PetscInt **perms = NULL; 6532 const PetscScalar **flips = NULL; 6533 6534 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6535 switch (mode) { 6536 case INSERT_VALUES: 6537 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6538 const PetscInt point = points[2 * p]; 6539 const PetscInt *perm = perms ? perms[p] : NULL; 6540 const PetscScalar *flip = flips ? flips[p] : NULL; 6541 PetscCall(PetscSectionGetDof(section, point, &dof)); 6542 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6543 } 6544 break; 6545 case INSERT_ALL_VALUES: 6546 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6547 const PetscInt point = points[2 * p]; 6548 const PetscInt *perm = perms ? perms[p] : NULL; 6549 const PetscScalar *flip = flips ? flips[p] : NULL; 6550 PetscCall(PetscSectionGetDof(section, point, &dof)); 6551 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6552 } 6553 break; 6554 case INSERT_BC_VALUES: 6555 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6556 const PetscInt point = points[2 * p]; 6557 const PetscInt *perm = perms ? perms[p] : NULL; 6558 const PetscScalar *flip = flips ? flips[p] : NULL; 6559 PetscCall(PetscSectionGetDof(section, point, &dof)); 6560 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6561 } 6562 break; 6563 case ADD_VALUES: 6564 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6565 const PetscInt point = points[2 * p]; 6566 const PetscInt *perm = perms ? perms[p] : NULL; 6567 const PetscScalar *flip = flips ? flips[p] : NULL; 6568 PetscCall(PetscSectionGetDof(section, point, &dof)); 6569 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6570 } 6571 break; 6572 case ADD_ALL_VALUES: 6573 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6574 const PetscInt point = points[2 * p]; 6575 const PetscInt *perm = perms ? perms[p] : NULL; 6576 const PetscScalar *flip = flips ? flips[p] : NULL; 6577 PetscCall(PetscSectionGetDof(section, point, &dof)); 6578 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6579 } 6580 break; 6581 case ADD_BC_VALUES: 6582 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6583 const PetscInt point = points[2 * p]; 6584 const PetscInt *perm = perms ? perms[p] : NULL; 6585 const PetscScalar *flip = flips ? flips[p] : NULL; 6586 PetscCall(PetscSectionGetDof(section, point, &dof)); 6587 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6588 } 6589 break; 6590 default: 6591 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6592 } 6593 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6594 } 6595 /* Cleanup points */ 6596 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6597 /* Cleanup array */ 6598 PetscCall(VecRestoreArray(v, &array)); 6599 PetscFunctionReturn(0); 6600 } 6601 6602 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6603 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6604 { 6605 PetscFunctionBegin; 6606 *contains = PETSC_TRUE; 6607 if (label) { 6608 PetscInt fdof; 6609 6610 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6611 if (!*contains) { 6612 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6613 *offset += fdof; 6614 PetscFunctionReturn(0); 6615 } 6616 } 6617 PetscFunctionReturn(0); 6618 } 6619 6620 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6621 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) 6622 { 6623 PetscSection clSection; 6624 IS clPoints; 6625 PetscScalar *array; 6626 PetscInt *points = NULL; 6627 const PetscInt *clp; 6628 PetscInt numFields, numPoints, p; 6629 PetscInt offset = 0, f; 6630 6631 PetscFunctionBeginHot; 6632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6633 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6634 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6635 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6636 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6637 /* Get points */ 6638 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6639 /* Get array */ 6640 PetscCall(VecGetArray(v, &array)); 6641 /* Get values */ 6642 for (f = 0; f < numFields; ++f) { 6643 const PetscInt **perms = NULL; 6644 const PetscScalar **flips = NULL; 6645 PetscBool contains; 6646 6647 if (!fieldActive[f]) { 6648 for (p = 0; p < numPoints * 2; p += 2) { 6649 PetscInt fdof; 6650 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6651 offset += fdof; 6652 } 6653 continue; 6654 } 6655 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6656 switch (mode) { 6657 case INSERT_VALUES: 6658 for (p = 0; p < numPoints; p++) { 6659 const PetscInt point = points[2 * p]; 6660 const PetscInt *perm = perms ? perms[p] : NULL; 6661 const PetscScalar *flip = flips ? flips[p] : NULL; 6662 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6663 if (!contains) continue; 6664 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6665 } 6666 break; 6667 case INSERT_ALL_VALUES: 6668 for (p = 0; p < numPoints; p++) { 6669 const PetscInt point = points[2 * p]; 6670 const PetscInt *perm = perms ? perms[p] : NULL; 6671 const PetscScalar *flip = flips ? flips[p] : NULL; 6672 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6673 if (!contains) continue; 6674 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6675 } 6676 break; 6677 case INSERT_BC_VALUES: 6678 for (p = 0; p < numPoints; p++) { 6679 const PetscInt point = points[2 * p]; 6680 const PetscInt *perm = perms ? perms[p] : NULL; 6681 const PetscScalar *flip = flips ? flips[p] : NULL; 6682 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6683 if (!contains) continue; 6684 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6685 } 6686 break; 6687 case ADD_VALUES: 6688 for (p = 0; p < numPoints; p++) { 6689 const PetscInt point = points[2 * p]; 6690 const PetscInt *perm = perms ? perms[p] : NULL; 6691 const PetscScalar *flip = flips ? flips[p] : NULL; 6692 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6693 if (!contains) continue; 6694 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6695 } 6696 break; 6697 case ADD_ALL_VALUES: 6698 for (p = 0; p < numPoints; p++) { 6699 const PetscInt point = points[2 * p]; 6700 const PetscInt *perm = perms ? perms[p] : NULL; 6701 const PetscScalar *flip = flips ? flips[p] : NULL; 6702 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6703 if (!contains) continue; 6704 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6705 } 6706 break; 6707 default: 6708 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6709 } 6710 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6711 } 6712 /* Cleanup points */ 6713 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6714 /* Cleanup array */ 6715 PetscCall(VecRestoreArray(v, &array)); 6716 PetscFunctionReturn(0); 6717 } 6718 6719 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6720 { 6721 PetscMPIInt rank; 6722 PetscInt i, j; 6723 6724 PetscFunctionBegin; 6725 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6726 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6727 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6728 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6729 numCIndices = numCIndices ? numCIndices : numRIndices; 6730 if (!values) PetscFunctionReturn(0); 6731 for (i = 0; i < numRIndices; i++) { 6732 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6733 for (j = 0; j < numCIndices; j++) { 6734 #if defined(PETSC_USE_COMPLEX) 6735 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6736 #else 6737 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6738 #endif 6739 } 6740 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6741 } 6742 PetscFunctionReturn(0); 6743 } 6744 6745 /* 6746 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6747 6748 Input Parameters: 6749 + section - The section for this data layout 6750 . islocal - Is the section (and thus indices being requested) local or global? 6751 . point - The point contributing dofs with these indices 6752 . off - The global offset of this point 6753 . loff - The local offset of each field 6754 . setBC - The flag determining whether to include indices of boundary values 6755 . perm - A permutation of the dofs on this point, or NULL 6756 - indperm - A permutation of the entire indices array, or NULL 6757 6758 Output Parameter: 6759 . indices - Indices for dofs on this point 6760 6761 Level: developer 6762 6763 Note: The indices could be local or global, depending on the value of 'off'. 6764 */ 6765 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6766 { 6767 PetscInt dof; /* The number of unknowns on this point */ 6768 PetscInt cdof; /* The number of constraints on this point */ 6769 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6770 PetscInt cind = 0, k; 6771 6772 PetscFunctionBegin; 6773 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6774 PetscCall(PetscSectionGetDof(section, point, &dof)); 6775 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6776 if (!cdof || setBC) { 6777 for (k = 0; k < dof; ++k) { 6778 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6779 const PetscInt ind = indperm ? indperm[preind] : preind; 6780 6781 indices[ind] = off + k; 6782 } 6783 } else { 6784 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6785 for (k = 0; k < dof; ++k) { 6786 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6787 const PetscInt ind = indperm ? indperm[preind] : preind; 6788 6789 if ((cind < cdof) && (k == cdofs[cind])) { 6790 /* Insert check for returning constrained indices */ 6791 indices[ind] = -(off + k + 1); 6792 ++cind; 6793 } else { 6794 indices[ind] = off + k - (islocal ? 0 : cind); 6795 } 6796 } 6797 } 6798 *loff += dof; 6799 PetscFunctionReturn(0); 6800 } 6801 6802 /* 6803 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6804 6805 Input Parameters: 6806 + section - a section (global or local) 6807 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6808 . point - point within section 6809 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6810 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6811 . setBC - identify constrained (boundary condition) points via involution. 6812 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6813 . permsoff - offset 6814 - indperm - index permutation 6815 6816 Output Parameter: 6817 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6818 . indices - array to hold indices (as defined by section) of each dof associated with point 6819 6820 Notes: 6821 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6822 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6823 in the local vector. 6824 6825 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6826 significant). It is invalid to call with a global section and setBC=true. 6827 6828 Developer Note: 6829 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6830 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6831 offset could be obtained from the section instead of passing it explicitly as we do now. 6832 6833 Example: 6834 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6835 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6836 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6837 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. 6838 6839 Level: developer 6840 */ 6841 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[]) 6842 { 6843 PetscInt numFields, foff, f; 6844 6845 PetscFunctionBegin; 6846 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6847 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6848 for (f = 0, foff = 0; f < numFields; ++f) { 6849 PetscInt fdof, cfdof; 6850 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6851 PetscInt cind = 0, b; 6852 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6853 6854 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6855 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6856 if (!cfdof || setBC) { 6857 for (b = 0; b < fdof; ++b) { 6858 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6859 const PetscInt ind = indperm ? indperm[preind] : preind; 6860 6861 indices[ind] = off + foff + b; 6862 } 6863 } else { 6864 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6865 for (b = 0; b < fdof; ++b) { 6866 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6867 const PetscInt ind = indperm ? indperm[preind] : preind; 6868 6869 if ((cind < cfdof) && (b == fcdofs[cind])) { 6870 indices[ind] = -(off + foff + b + 1); 6871 ++cind; 6872 } else { 6873 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6874 } 6875 } 6876 } 6877 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6878 foffs[f] += fdof; 6879 } 6880 PetscFunctionReturn(0); 6881 } 6882 6883 /* 6884 This version believes the globalSection offsets for each field, rather than just the point offset 6885 6886 . foffs - The offset into 'indices' for each field, since it is segregated by field 6887 6888 Notes: 6889 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6890 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6891 */ 6892 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6893 { 6894 PetscInt numFields, foff, f; 6895 6896 PetscFunctionBegin; 6897 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6898 for (f = 0; f < numFields; ++f) { 6899 PetscInt fdof, cfdof; 6900 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6901 PetscInt cind = 0, b; 6902 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6903 6904 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6905 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6906 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6907 if (!cfdof) { 6908 for (b = 0; b < fdof; ++b) { 6909 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6910 const PetscInt ind = indperm ? indperm[preind] : preind; 6911 6912 indices[ind] = foff + b; 6913 } 6914 } else { 6915 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6916 for (b = 0; b < fdof; ++b) { 6917 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6918 const PetscInt ind = indperm ? indperm[preind] : preind; 6919 6920 if ((cind < cfdof) && (b == fcdofs[cind])) { 6921 indices[ind] = -(foff + b + 1); 6922 ++cind; 6923 } else { 6924 indices[ind] = foff + b - cind; 6925 } 6926 } 6927 } 6928 foffs[f] += fdof; 6929 } 6930 PetscFunctionReturn(0); 6931 } 6932 6933 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) 6934 { 6935 Mat cMat; 6936 PetscSection aSec, cSec; 6937 IS aIS; 6938 PetscInt aStart = -1, aEnd = -1; 6939 const PetscInt *anchors; 6940 PetscInt numFields, f, p, q, newP = 0; 6941 PetscInt newNumPoints = 0, newNumIndices = 0; 6942 PetscInt *newPoints, *indices, *newIndices; 6943 PetscInt maxAnchor, maxDof; 6944 PetscInt newOffsets[32]; 6945 PetscInt *pointMatOffsets[32]; 6946 PetscInt *newPointOffsets[32]; 6947 PetscScalar *pointMat[32]; 6948 PetscScalar *newValues = NULL, *tmpValues; 6949 PetscBool anyConstrained = PETSC_FALSE; 6950 6951 PetscFunctionBegin; 6952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6953 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6954 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6955 6956 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6957 /* if there are point-to-point constraints */ 6958 if (aSec) { 6959 PetscCall(PetscArrayzero(newOffsets, 32)); 6960 PetscCall(ISGetIndices(aIS, &anchors)); 6961 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6962 /* figure out how many points are going to be in the new element matrix 6963 * (we allow double counting, because it's all just going to be summed 6964 * into the global matrix anyway) */ 6965 for (p = 0; p < 2 * numPoints; p += 2) { 6966 PetscInt b = points[p]; 6967 PetscInt bDof = 0, bSecDof; 6968 6969 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6970 if (!bSecDof) continue; 6971 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6972 if (bDof) { 6973 /* this point is constrained */ 6974 /* it is going to be replaced by its anchors */ 6975 PetscInt bOff, q; 6976 6977 anyConstrained = PETSC_TRUE; 6978 newNumPoints += bDof; 6979 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6980 for (q = 0; q < bDof; q++) { 6981 PetscInt a = anchors[bOff + q]; 6982 PetscInt aDof; 6983 6984 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6985 newNumIndices += aDof; 6986 for (f = 0; f < numFields; ++f) { 6987 PetscInt fDof; 6988 6989 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6990 newOffsets[f + 1] += fDof; 6991 } 6992 } 6993 } else { 6994 /* this point is not constrained */ 6995 newNumPoints++; 6996 newNumIndices += bSecDof; 6997 for (f = 0; f < numFields; ++f) { 6998 PetscInt fDof; 6999 7000 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7001 newOffsets[f + 1] += fDof; 7002 } 7003 } 7004 } 7005 } 7006 if (!anyConstrained) { 7007 if (outNumPoints) *outNumPoints = 0; 7008 if (outNumIndices) *outNumIndices = 0; 7009 if (outPoints) *outPoints = NULL; 7010 if (outValues) *outValues = NULL; 7011 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7012 PetscFunctionReturn(0); 7013 } 7014 7015 if (outNumPoints) *outNumPoints = newNumPoints; 7016 if (outNumIndices) *outNumIndices = newNumIndices; 7017 7018 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7019 7020 if (!outPoints && !outValues) { 7021 if (offsets) { 7022 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7023 } 7024 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7025 PetscFunctionReturn(0); 7026 } 7027 7028 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7029 7030 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7031 7032 /* workspaces */ 7033 if (numFields) { 7034 for (f = 0; f < numFields; f++) { 7035 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7036 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7037 } 7038 } else { 7039 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7040 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7041 } 7042 7043 /* get workspaces for the point-to-point matrices */ 7044 if (numFields) { 7045 PetscInt totalOffset, totalMatOffset; 7046 7047 for (p = 0; p < numPoints; p++) { 7048 PetscInt b = points[2 * p]; 7049 PetscInt bDof = 0, bSecDof; 7050 7051 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7052 if (!bSecDof) { 7053 for (f = 0; f < numFields; f++) { 7054 newPointOffsets[f][p + 1] = 0; 7055 pointMatOffsets[f][p + 1] = 0; 7056 } 7057 continue; 7058 } 7059 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7060 if (bDof) { 7061 for (f = 0; f < numFields; f++) { 7062 PetscInt fDof, q, bOff, allFDof = 0; 7063 7064 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7065 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7066 for (q = 0; q < bDof; q++) { 7067 PetscInt a = anchors[bOff + q]; 7068 PetscInt aFDof; 7069 7070 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7071 allFDof += aFDof; 7072 } 7073 newPointOffsets[f][p + 1] = allFDof; 7074 pointMatOffsets[f][p + 1] = fDof * allFDof; 7075 } 7076 } else { 7077 for (f = 0; f < numFields; f++) { 7078 PetscInt fDof; 7079 7080 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7081 newPointOffsets[f][p + 1] = fDof; 7082 pointMatOffsets[f][p + 1] = 0; 7083 } 7084 } 7085 } 7086 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7087 newPointOffsets[f][0] = totalOffset; 7088 pointMatOffsets[f][0] = totalMatOffset; 7089 for (p = 0; p < numPoints; p++) { 7090 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7091 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7092 } 7093 totalOffset = newPointOffsets[f][numPoints]; 7094 totalMatOffset = pointMatOffsets[f][numPoints]; 7095 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7096 } 7097 } else { 7098 for (p = 0; p < numPoints; p++) { 7099 PetscInt b = points[2 * p]; 7100 PetscInt bDof = 0, bSecDof; 7101 7102 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7103 if (!bSecDof) { 7104 newPointOffsets[0][p + 1] = 0; 7105 pointMatOffsets[0][p + 1] = 0; 7106 continue; 7107 } 7108 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7109 if (bDof) { 7110 PetscInt bOff, q, allDof = 0; 7111 7112 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7113 for (q = 0; q < bDof; q++) { 7114 PetscInt a = anchors[bOff + q], aDof; 7115 7116 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7117 allDof += aDof; 7118 } 7119 newPointOffsets[0][p + 1] = allDof; 7120 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7121 } else { 7122 newPointOffsets[0][p + 1] = bSecDof; 7123 pointMatOffsets[0][p + 1] = 0; 7124 } 7125 } 7126 newPointOffsets[0][0] = 0; 7127 pointMatOffsets[0][0] = 0; 7128 for (p = 0; p < numPoints; p++) { 7129 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7130 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7131 } 7132 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7133 } 7134 7135 /* output arrays */ 7136 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7137 7138 /* get the point-to-point matrices; construct newPoints */ 7139 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7140 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7141 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7142 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7143 if (numFields) { 7144 for (p = 0, newP = 0; p < numPoints; p++) { 7145 PetscInt b = points[2 * p]; 7146 PetscInt o = points[2 * p + 1]; 7147 PetscInt bDof = 0, bSecDof; 7148 7149 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7150 if (!bSecDof) continue; 7151 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7152 if (bDof) { 7153 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7154 7155 fStart[0] = 0; 7156 fEnd[0] = 0; 7157 for (f = 0; f < numFields; f++) { 7158 PetscInt fDof; 7159 7160 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7161 fStart[f + 1] = fStart[f] + fDof; 7162 fEnd[f + 1] = fStart[f + 1]; 7163 } 7164 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7165 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7166 7167 fAnchorStart[0] = 0; 7168 fAnchorEnd[0] = 0; 7169 for (f = 0; f < numFields; f++) { 7170 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7171 7172 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7173 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7174 } 7175 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7176 for (q = 0; q < bDof; q++) { 7177 PetscInt a = anchors[bOff + q], aOff; 7178 7179 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7180 newPoints[2 * (newP + q)] = a; 7181 newPoints[2 * (newP + q) + 1] = 0; 7182 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7183 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7184 } 7185 newP += bDof; 7186 7187 if (outValues) { 7188 /* get the point-to-point submatrix */ 7189 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])); 7190 } 7191 } else { 7192 newPoints[2 * newP] = b; 7193 newPoints[2 * newP + 1] = o; 7194 newP++; 7195 } 7196 } 7197 } else { 7198 for (p = 0; p < numPoints; p++) { 7199 PetscInt b = points[2 * p]; 7200 PetscInt o = points[2 * p + 1]; 7201 PetscInt bDof = 0, bSecDof; 7202 7203 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7204 if (!bSecDof) continue; 7205 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7206 if (bDof) { 7207 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7208 7209 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7210 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7211 7212 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7213 for (q = 0; q < bDof; q++) { 7214 PetscInt a = anchors[bOff + q], aOff; 7215 7216 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7217 7218 newPoints[2 * (newP + q)] = a; 7219 newPoints[2 * (newP + q) + 1] = 0; 7220 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7221 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7222 } 7223 newP += bDof; 7224 7225 /* get the point-to-point submatrix */ 7226 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7227 } else { 7228 newPoints[2 * newP] = b; 7229 newPoints[2 * newP + 1] = o; 7230 newP++; 7231 } 7232 } 7233 } 7234 7235 if (outValues) { 7236 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7237 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7238 /* multiply constraints on the right */ 7239 if (numFields) { 7240 for (f = 0; f < numFields; f++) { 7241 PetscInt oldOff = offsets[f]; 7242 7243 for (p = 0; p < numPoints; p++) { 7244 PetscInt cStart = newPointOffsets[f][p]; 7245 PetscInt b = points[2 * p]; 7246 PetscInt c, r, k; 7247 PetscInt dof; 7248 7249 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7250 if (!dof) continue; 7251 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7252 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7253 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7254 7255 for (r = 0; r < numIndices; r++) { 7256 for (c = 0; c < nCols; c++) { 7257 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7258 } 7259 } 7260 } else { 7261 /* copy this column as is */ 7262 for (r = 0; r < numIndices; r++) { 7263 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7264 } 7265 } 7266 oldOff += dof; 7267 } 7268 } 7269 } else { 7270 PetscInt oldOff = 0; 7271 for (p = 0; p < numPoints; p++) { 7272 PetscInt cStart = newPointOffsets[0][p]; 7273 PetscInt b = points[2 * p]; 7274 PetscInt c, r, k; 7275 PetscInt dof; 7276 7277 PetscCall(PetscSectionGetDof(section, b, &dof)); 7278 if (!dof) continue; 7279 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7280 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7281 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7282 7283 for (r = 0; r < numIndices; r++) { 7284 for (c = 0; c < nCols; c++) { 7285 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7286 } 7287 } 7288 } else { 7289 /* copy this column as is */ 7290 for (r = 0; r < numIndices; r++) { 7291 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7292 } 7293 } 7294 oldOff += dof; 7295 } 7296 } 7297 7298 if (multiplyLeft) { 7299 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7300 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7301 /* multiply constraints transpose on the left */ 7302 if (numFields) { 7303 for (f = 0; f < numFields; f++) { 7304 PetscInt oldOff = offsets[f]; 7305 7306 for (p = 0; p < numPoints; p++) { 7307 PetscInt rStart = newPointOffsets[f][p]; 7308 PetscInt b = points[2 * p]; 7309 PetscInt c, r, k; 7310 PetscInt dof; 7311 7312 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7313 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7314 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7315 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7316 7317 for (r = 0; r < nRows; r++) { 7318 for (c = 0; c < newNumIndices; c++) { 7319 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7320 } 7321 } 7322 } else { 7323 /* copy this row as is */ 7324 for (r = 0; r < dof; r++) { 7325 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7326 } 7327 } 7328 oldOff += dof; 7329 } 7330 } 7331 } else { 7332 PetscInt oldOff = 0; 7333 7334 for (p = 0; p < numPoints; p++) { 7335 PetscInt rStart = newPointOffsets[0][p]; 7336 PetscInt b = points[2 * p]; 7337 PetscInt c, r, k; 7338 PetscInt dof; 7339 7340 PetscCall(PetscSectionGetDof(section, b, &dof)); 7341 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7342 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7343 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7344 7345 for (r = 0; r < nRows; r++) { 7346 for (c = 0; c < newNumIndices; c++) { 7347 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7348 } 7349 } 7350 } else { 7351 /* copy this row as is */ 7352 for (r = 0; r < dof; r++) { 7353 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7354 } 7355 } 7356 oldOff += dof; 7357 } 7358 } 7359 7360 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7361 } else { 7362 newValues = tmpValues; 7363 } 7364 } 7365 7366 /* clean up */ 7367 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7368 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7369 7370 if (numFields) { 7371 for (f = 0; f < numFields; f++) { 7372 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7373 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7374 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7375 } 7376 } else { 7377 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7378 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7379 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7380 } 7381 PetscCall(ISRestoreIndices(aIS, &anchors)); 7382 7383 /* output */ 7384 if (outPoints) { 7385 *outPoints = newPoints; 7386 } else { 7387 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7388 } 7389 if (outValues) *outValues = newValues; 7390 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7391 PetscFunctionReturn(0); 7392 } 7393 7394 /*@C 7395 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7396 7397 Not collective 7398 7399 Input Parameters: 7400 + dm - The `DM` 7401 . section - The `PetscSection` describing the points (a local section) 7402 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7403 . point - The point defining the closure 7404 - useClPerm - Use the closure point permutation if available 7405 7406 Output Parameters: 7407 + numIndices - The number of dof indices in the closure of point with the input sections 7408 . indices - The dof indices 7409 . outOffsets - Array to write the field offsets into, or NULL 7410 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7411 7412 Level: advanced 7413 7414 Notes: 7415 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7416 7417 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7418 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7419 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7420 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7421 indices (with the above semantics) are implied. 7422 7423 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7424 `PetscSection`, `DMGetGlobalSection()` 7425 @*/ 7426 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7427 { 7428 /* Closure ordering */ 7429 PetscSection clSection; 7430 IS clPoints; 7431 const PetscInt *clp; 7432 PetscInt *points; 7433 const PetscInt *clperm = NULL; 7434 /* Dof permutation and sign flips */ 7435 const PetscInt **perms[32] = {NULL}; 7436 const PetscScalar **flips[32] = {NULL}; 7437 PetscScalar *valCopy = NULL; 7438 /* Hanging node constraints */ 7439 PetscInt *pointsC = NULL; 7440 PetscScalar *valuesC = NULL; 7441 PetscInt NclC, NiC; 7442 7443 PetscInt *idx; 7444 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7445 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7446 7447 PetscFunctionBeginHot; 7448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7449 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7450 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7451 if (numIndices) PetscValidIntPointer(numIndices, 6); 7452 if (indices) PetscValidPointer(indices, 7); 7453 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7454 if (values) PetscValidPointer(values, 9); 7455 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7456 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7457 PetscCall(PetscArrayzero(offsets, 32)); 7458 /* 1) Get points in closure */ 7459 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7460 if (useClPerm) { 7461 PetscInt depth, clsize; 7462 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7463 for (clsize = 0, p = 0; p < Ncl; p++) { 7464 PetscInt dof; 7465 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7466 clsize += dof; 7467 } 7468 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7469 } 7470 /* 2) Get number of indices on these points and field offsets from section */ 7471 for (p = 0; p < Ncl * 2; p += 2) { 7472 PetscInt dof, fdof; 7473 7474 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7475 for (f = 0; f < Nf; ++f) { 7476 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7477 offsets[f + 1] += fdof; 7478 } 7479 Ni += dof; 7480 } 7481 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7482 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7483 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7484 for (f = 0; f < PetscMax(1, Nf); ++f) { 7485 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7486 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7487 /* may need to apply sign changes to the element matrix */ 7488 if (values && flips[f]) { 7489 PetscInt foffset = offsets[f]; 7490 7491 for (p = 0; p < Ncl; ++p) { 7492 PetscInt pnt = points[2 * p], fdof; 7493 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7494 7495 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7496 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7497 if (flip) { 7498 PetscInt i, j, k; 7499 7500 if (!valCopy) { 7501 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7502 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7503 *values = valCopy; 7504 } 7505 for (i = 0; i < fdof; ++i) { 7506 PetscScalar fval = flip[i]; 7507 7508 for (k = 0; k < Ni; ++k) { 7509 valCopy[Ni * (foffset + i) + k] *= fval; 7510 valCopy[Ni * k + (foffset + i)] *= fval; 7511 } 7512 } 7513 } 7514 foffset += fdof; 7515 } 7516 } 7517 } 7518 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7519 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7520 if (NclC) { 7521 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7522 for (f = 0; f < PetscMax(1, Nf); ++f) { 7523 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7524 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7525 } 7526 for (f = 0; f < PetscMax(1, Nf); ++f) { 7527 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7528 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7529 } 7530 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7531 Ncl = NclC; 7532 Ni = NiC; 7533 points = pointsC; 7534 if (values) *values = valuesC; 7535 } 7536 /* 5) Calculate indices */ 7537 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7538 if (Nf) { 7539 PetscInt idxOff; 7540 PetscBool useFieldOffsets; 7541 7542 if (outOffsets) { 7543 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7544 } 7545 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7546 if (useFieldOffsets) { 7547 for (p = 0; p < Ncl; ++p) { 7548 const PetscInt pnt = points[p * 2]; 7549 7550 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7551 } 7552 } else { 7553 for (p = 0; p < Ncl; ++p) { 7554 const PetscInt pnt = points[p * 2]; 7555 7556 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7557 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7558 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7559 * global section. */ 7560 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7561 } 7562 } 7563 } else { 7564 PetscInt off = 0, idxOff; 7565 7566 for (p = 0; p < Ncl; ++p) { 7567 const PetscInt pnt = points[p * 2]; 7568 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7569 7570 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7571 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7572 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7573 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7574 } 7575 } 7576 /* 6) Cleanup */ 7577 for (f = 0; f < PetscMax(1, Nf); ++f) { 7578 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7579 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7580 } 7581 if (NclC) { 7582 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7583 } else { 7584 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7585 } 7586 7587 if (numIndices) *numIndices = Ni; 7588 if (indices) *indices = idx; 7589 PetscFunctionReturn(0); 7590 } 7591 7592 /*@C 7593 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7594 7595 Not collective 7596 7597 Input Parameters: 7598 + dm - The `DM` 7599 . section - The `PetscSection` describing the points (a local section) 7600 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7601 . point - The point defining the closure 7602 - useClPerm - Use the closure point permutation if available 7603 7604 Output Parameters: 7605 + numIndices - The number of dof indices in the closure of point with the input sections 7606 . indices - The dof indices 7607 . outOffsets - Array to write the field offsets into, or NULL 7608 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7609 7610 Level: advanced 7611 7612 Notes: 7613 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7614 7615 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7616 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7617 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7618 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7619 indices (with the above semantics) are implied. 7620 7621 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7622 @*/ 7623 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7624 { 7625 PetscFunctionBegin; 7626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7627 PetscValidPointer(indices, 7); 7628 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7629 PetscFunctionReturn(0); 7630 } 7631 7632 /*@C 7633 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7634 7635 Not collective 7636 7637 Input Parameters: 7638 + dm - The `DM` 7639 . section - The section describing the layout in v, or NULL to use the default section 7640 . globalSection - The section describing the layout in v, or NULL to use the default global section 7641 . A - The matrix 7642 . point - The point in the `DM` 7643 . values - The array of values 7644 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7645 7646 Level: intermediate 7647 7648 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7649 @*/ 7650 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7651 { 7652 DM_Plex *mesh = (DM_Plex *)dm->data; 7653 PetscInt *indices; 7654 PetscInt numIndices; 7655 const PetscScalar *valuesOrig = values; 7656 PetscErrorCode ierr; 7657 7658 PetscFunctionBegin; 7659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7660 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7661 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7662 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7663 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7664 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7665 7666 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7667 7668 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7669 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7670 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7671 if (ierr) { 7672 PetscMPIInt rank; 7673 7674 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7675 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7676 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7677 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7678 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7679 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7680 } 7681 if (mesh->printFEM > 1) { 7682 PetscInt i; 7683 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7684 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7685 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7686 } 7687 7688 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7689 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7690 PetscFunctionReturn(0); 7691 } 7692 7693 /*@C 7694 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7695 7696 Not collective 7697 7698 Input Parameters: 7699 + dmRow - The `DM` for the row fields 7700 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7701 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7702 . dmCol - The `DM` for the column fields 7703 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7704 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7705 . A - The matrix 7706 . point - The point in the `DM` 7707 . values - The array of values 7708 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7709 7710 Level: intermediate 7711 7712 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7713 @*/ 7714 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7715 { 7716 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7717 PetscInt *indicesRow, *indicesCol; 7718 PetscInt numIndicesRow, numIndicesCol; 7719 const PetscScalar *valuesOrig = values; 7720 PetscErrorCode ierr; 7721 7722 PetscFunctionBegin; 7723 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7724 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7725 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7726 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7727 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7728 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7729 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7730 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7731 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7732 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7733 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7734 7735 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7736 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7737 7738 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7739 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7740 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7741 if (ierr) { 7742 PetscMPIInt rank; 7743 7744 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7745 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7746 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7747 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7748 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7749 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7750 } 7751 7752 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7753 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7754 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7755 PetscFunctionReturn(0); 7756 } 7757 7758 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7759 { 7760 DM_Plex *mesh = (DM_Plex *)dmf->data; 7761 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7762 PetscInt *cpoints = NULL; 7763 PetscInt *findices, *cindices; 7764 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7765 PetscInt foffsets[32], coffsets[32]; 7766 DMPolytopeType ct; 7767 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7768 PetscErrorCode ierr; 7769 7770 PetscFunctionBegin; 7771 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7772 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7773 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7774 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7775 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7776 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7777 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7778 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7779 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7780 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7781 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7782 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7783 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7784 PetscCall(PetscArrayzero(foffsets, 32)); 7785 PetscCall(PetscArrayzero(coffsets, 32)); 7786 /* Column indices */ 7787 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7788 maxFPoints = numCPoints; 7789 /* Compress out points not in the section */ 7790 /* TODO: Squeeze out points with 0 dof as well */ 7791 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7792 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7793 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7794 cpoints[q * 2] = cpoints[p]; 7795 cpoints[q * 2 + 1] = cpoints[p + 1]; 7796 ++q; 7797 } 7798 } 7799 numCPoints = q; 7800 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7801 PetscInt fdof; 7802 7803 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7804 if (!dof) continue; 7805 for (f = 0; f < numFields; ++f) { 7806 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7807 coffsets[f + 1] += fdof; 7808 } 7809 numCIndices += dof; 7810 } 7811 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7812 /* Row indices */ 7813 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7814 { 7815 DMPlexTransform tr; 7816 DMPolytopeType *rct; 7817 PetscInt *rsize, *rcone, *rornt, Nt; 7818 7819 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7820 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7821 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7822 numSubcells = rsize[Nt - 1]; 7823 PetscCall(DMPlexTransformDestroy(&tr)); 7824 } 7825 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7826 for (r = 0, q = 0; r < numSubcells; ++r) { 7827 /* TODO Map from coarse to fine cells */ 7828 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7829 /* Compress out points not in the section */ 7830 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7831 for (p = 0; p < numFPoints * 2; p += 2) { 7832 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7833 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7834 if (!dof) continue; 7835 for (s = 0; s < q; ++s) 7836 if (fpoints[p] == ftotpoints[s * 2]) break; 7837 if (s < q) continue; 7838 ftotpoints[q * 2] = fpoints[p]; 7839 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7840 ++q; 7841 } 7842 } 7843 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7844 } 7845 numFPoints = q; 7846 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7847 PetscInt fdof; 7848 7849 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7850 if (!dof) continue; 7851 for (f = 0; f < numFields; ++f) { 7852 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7853 foffsets[f + 1] += fdof; 7854 } 7855 numFIndices += dof; 7856 } 7857 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7858 7859 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7860 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7861 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7862 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7863 if (numFields) { 7864 const PetscInt **permsF[32] = {NULL}; 7865 const PetscInt **permsC[32] = {NULL}; 7866 7867 for (f = 0; f < numFields; f++) { 7868 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7869 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7870 } 7871 for (p = 0; p < numFPoints; p++) { 7872 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7873 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7874 } 7875 for (p = 0; p < numCPoints; p++) { 7876 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7877 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7878 } 7879 for (f = 0; f < numFields; f++) { 7880 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7881 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7882 } 7883 } else { 7884 const PetscInt **permsF = NULL; 7885 const PetscInt **permsC = NULL; 7886 7887 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7888 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7889 for (p = 0, off = 0; p < numFPoints; p++) { 7890 const PetscInt *perm = permsF ? permsF[p] : NULL; 7891 7892 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7893 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7894 } 7895 for (p = 0, off = 0; p < numCPoints; p++) { 7896 const PetscInt *perm = permsC ? permsC[p] : NULL; 7897 7898 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7899 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7900 } 7901 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7902 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7903 } 7904 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7905 /* TODO: flips */ 7906 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7907 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7908 if (ierr) { 7909 PetscMPIInt rank; 7910 7911 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7912 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7913 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7914 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7915 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7916 } 7917 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7918 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7919 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7920 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7921 PetscFunctionReturn(0); 7922 } 7923 7924 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7925 { 7926 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7927 PetscInt *cpoints = NULL; 7928 PetscInt foffsets[32], coffsets[32]; 7929 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7930 DMPolytopeType ct; 7931 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7932 7933 PetscFunctionBegin; 7934 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7935 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7936 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7937 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7938 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7939 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7940 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7941 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7942 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7943 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7944 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7945 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7946 PetscCall(PetscArrayzero(foffsets, 32)); 7947 PetscCall(PetscArrayzero(coffsets, 32)); 7948 /* Column indices */ 7949 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7950 maxFPoints = numCPoints; 7951 /* Compress out points not in the section */ 7952 /* TODO: Squeeze out points with 0 dof as well */ 7953 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7954 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7955 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7956 cpoints[q * 2] = cpoints[p]; 7957 cpoints[q * 2 + 1] = cpoints[p + 1]; 7958 ++q; 7959 } 7960 } 7961 numCPoints = q; 7962 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7963 PetscInt fdof; 7964 7965 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7966 if (!dof) continue; 7967 for (f = 0; f < numFields; ++f) { 7968 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7969 coffsets[f + 1] += fdof; 7970 } 7971 numCIndices += dof; 7972 } 7973 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7974 /* Row indices */ 7975 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7976 { 7977 DMPlexTransform tr; 7978 DMPolytopeType *rct; 7979 PetscInt *rsize, *rcone, *rornt, Nt; 7980 7981 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7982 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7983 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7984 numSubcells = rsize[Nt - 1]; 7985 PetscCall(DMPlexTransformDestroy(&tr)); 7986 } 7987 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7988 for (r = 0, q = 0; r < numSubcells; ++r) { 7989 /* TODO Map from coarse to fine cells */ 7990 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7991 /* Compress out points not in the section */ 7992 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7993 for (p = 0; p < numFPoints * 2; p += 2) { 7994 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7995 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7996 if (!dof) continue; 7997 for (s = 0; s < q; ++s) 7998 if (fpoints[p] == ftotpoints[s * 2]) break; 7999 if (s < q) continue; 8000 ftotpoints[q * 2] = fpoints[p]; 8001 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8002 ++q; 8003 } 8004 } 8005 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8006 } 8007 numFPoints = q; 8008 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8009 PetscInt fdof; 8010 8011 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8012 if (!dof) continue; 8013 for (f = 0; f < numFields; ++f) { 8014 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8015 foffsets[f + 1] += fdof; 8016 } 8017 numFIndices += dof; 8018 } 8019 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8020 8021 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8022 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8023 if (numFields) { 8024 const PetscInt **permsF[32] = {NULL}; 8025 const PetscInt **permsC[32] = {NULL}; 8026 8027 for (f = 0; f < numFields; f++) { 8028 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8029 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8030 } 8031 for (p = 0; p < numFPoints; p++) { 8032 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8033 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8034 } 8035 for (p = 0; p < numCPoints; p++) { 8036 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8037 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8038 } 8039 for (f = 0; f < numFields; f++) { 8040 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8041 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8042 } 8043 } else { 8044 const PetscInt **permsF = NULL; 8045 const PetscInt **permsC = NULL; 8046 8047 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8048 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8049 for (p = 0, off = 0; p < numFPoints; p++) { 8050 const PetscInt *perm = permsF ? permsF[p] : NULL; 8051 8052 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8053 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8054 } 8055 for (p = 0, off = 0; p < numCPoints; p++) { 8056 const PetscInt *perm = permsC ? permsC[p] : NULL; 8057 8058 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8059 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8060 } 8061 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8062 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8063 } 8064 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8065 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8066 PetscFunctionReturn(0); 8067 } 8068 8069 /*@C 8070 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8071 8072 Input Parameter: 8073 . dm - The `DMPLEX` object 8074 8075 Output Parameter: 8076 . cellHeight - The height of a cell 8077 8078 Level: developer 8079 8080 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8081 @*/ 8082 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8083 { 8084 DM_Plex *mesh = (DM_Plex *)dm->data; 8085 8086 PetscFunctionBegin; 8087 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8088 PetscValidIntPointer(cellHeight, 2); 8089 *cellHeight = mesh->vtkCellHeight; 8090 PetscFunctionReturn(0); 8091 } 8092 8093 /*@C 8094 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8095 8096 Input Parameters: 8097 + dm - The `DMPLEX` object 8098 - cellHeight - The height of a cell 8099 8100 Level: developer 8101 8102 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8103 @*/ 8104 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8105 { 8106 DM_Plex *mesh = (DM_Plex *)dm->data; 8107 8108 PetscFunctionBegin; 8109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8110 mesh->vtkCellHeight = cellHeight; 8111 PetscFunctionReturn(0); 8112 } 8113 8114 /*@ 8115 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8116 8117 Input Parameter: 8118 . dm - The `DMPLEX` object 8119 8120 Output Parameters: 8121 + gcStart - The first ghost cell, or NULL 8122 - gcEnd - The upper bound on ghost cells, or NULL 8123 8124 Level: advanced 8125 8126 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8127 @*/ 8128 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8129 { 8130 DMLabel ctLabel; 8131 8132 PetscFunctionBegin; 8133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8134 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8135 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8136 // Reset label for fast lookup 8137 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8138 PetscFunctionReturn(0); 8139 } 8140 8141 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8142 { 8143 PetscSection section, globalSection; 8144 PetscInt *numbers, p; 8145 8146 PetscFunctionBegin; 8147 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8148 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8149 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8150 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8151 PetscCall(PetscSectionSetUp(section)); 8152 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8153 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8154 for (p = pStart; p < pEnd; ++p) { 8155 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8156 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8157 else numbers[p - pStart] += shift; 8158 } 8159 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8160 if (globalSize) { 8161 PetscLayout layout; 8162 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8163 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8164 PetscCall(PetscLayoutDestroy(&layout)); 8165 } 8166 PetscCall(PetscSectionDestroy(§ion)); 8167 PetscCall(PetscSectionDestroy(&globalSection)); 8168 PetscFunctionReturn(0); 8169 } 8170 8171 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8172 { 8173 PetscInt cellHeight, cStart, cEnd; 8174 8175 PetscFunctionBegin; 8176 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8177 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8178 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8179 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8180 PetscFunctionReturn(0); 8181 } 8182 8183 /*@ 8184 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8185 8186 Input Parameter: 8187 . dm - The `DMPLEX` object 8188 8189 Output Parameter: 8190 . globalCellNumbers - Global cell numbers for all cells on this process 8191 8192 Level: developer 8193 8194 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8195 @*/ 8196 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8197 { 8198 DM_Plex *mesh = (DM_Plex *)dm->data; 8199 8200 PetscFunctionBegin; 8201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8202 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8203 *globalCellNumbers = mesh->globalCellNumbers; 8204 PetscFunctionReturn(0); 8205 } 8206 8207 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8208 { 8209 PetscInt vStart, vEnd; 8210 8211 PetscFunctionBegin; 8212 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8213 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8214 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8215 PetscFunctionReturn(0); 8216 } 8217 8218 /*@ 8219 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8220 8221 Input Parameter: 8222 . dm - The `DMPLEX` object 8223 8224 Output Parameter: 8225 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8226 8227 Level: developer 8228 8229 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8230 @*/ 8231 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8232 { 8233 DM_Plex *mesh = (DM_Plex *)dm->data; 8234 8235 PetscFunctionBegin; 8236 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8237 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8238 *globalVertexNumbers = mesh->globalVertexNumbers; 8239 PetscFunctionReturn(0); 8240 } 8241 8242 /*@ 8243 DMPlexCreatePointNumbering - Create a global numbering for all points. 8244 8245 Collective on dm 8246 8247 Input Parameter: 8248 . dm - The `DMPLEX` object 8249 8250 Output Parameter: 8251 . globalPointNumbers - Global numbers for all points on this process 8252 8253 Level: developer 8254 8255 Notes: 8256 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8257 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8258 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8259 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8260 8261 The partitioned mesh is 8262 ``` 8263 (2)--0--(3)--1--(4) (1)--0--(2) 8264 ``` 8265 and its global numbering is 8266 ``` 8267 (3)--0--(4)--1--(5)--2--(6) 8268 ``` 8269 Then the global numbering is provided as 8270 ``` 8271 [0] Number of indices in set 5 8272 [0] 0 0 8273 [0] 1 1 8274 [0] 2 3 8275 [0] 3 4 8276 [0] 4 -6 8277 [1] Number of indices in set 3 8278 [1] 0 2 8279 [1] 1 5 8280 [1] 2 6 8281 ``` 8282 8283 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8284 @*/ 8285 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8286 { 8287 IS nums[4]; 8288 PetscInt depths[4], gdepths[4], starts[4]; 8289 PetscInt depth, d, shift = 0; 8290 PetscBool empty = PETSC_FALSE; 8291 8292 PetscFunctionBegin; 8293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8294 PetscCall(DMPlexGetDepth(dm, &depth)); 8295 // For unstratified meshes use dim instead of depth 8296 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8297 // If any stratum is empty, we must mark all empty 8298 for (d = 0; d <= depth; ++d) { 8299 PetscInt end; 8300 8301 depths[d] = depth - d; 8302 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8303 if (!(starts[d] - end)) empty = PETSC_TRUE; 8304 } 8305 if (empty) 8306 for (d = 0; d <= depth; ++d) { 8307 depths[d] = -1; 8308 starts[d] = -1; 8309 } 8310 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8311 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8312 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]); 8313 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8314 for (d = 0; d <= depth; ++d) { 8315 PetscInt pStart, pEnd, gsize; 8316 8317 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8318 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8319 shift += gsize; 8320 } 8321 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8322 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8323 PetscFunctionReturn(0); 8324 } 8325 8326 /*@ 8327 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8328 8329 Input Parameter: 8330 . dm - The `DMPLEX` object 8331 8332 Output Parameter: 8333 . ranks - The rank field 8334 8335 Options Database Key: 8336 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8337 8338 Level: intermediate 8339 8340 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8341 @*/ 8342 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8343 { 8344 DM rdm; 8345 PetscFE fe; 8346 PetscScalar *r; 8347 PetscMPIInt rank; 8348 DMPolytopeType ct; 8349 PetscInt dim, cStart, cEnd, c; 8350 PetscBool simplex; 8351 8352 PetscFunctionBeginUser; 8353 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8354 PetscValidPointer(ranks, 2); 8355 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8356 PetscCall(DMClone(dm, &rdm)); 8357 PetscCall(DMGetDimension(rdm, &dim)); 8358 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8359 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8360 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8361 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8362 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8363 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8364 PetscCall(PetscFEDestroy(&fe)); 8365 PetscCall(DMCreateDS(rdm)); 8366 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8367 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8368 PetscCall(VecGetArray(*ranks, &r)); 8369 for (c = cStart; c < cEnd; ++c) { 8370 PetscScalar *lr; 8371 8372 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8373 if (lr) *lr = rank; 8374 } 8375 PetscCall(VecRestoreArray(*ranks, &r)); 8376 PetscCall(DMDestroy(&rdm)); 8377 PetscFunctionReturn(0); 8378 } 8379 8380 /*@ 8381 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8382 8383 Input Parameters: 8384 + dm - The DMPlex 8385 - label - The DMLabel 8386 8387 Output Parameter: 8388 . val - The label value field 8389 8390 Options Database Keys: 8391 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8392 8393 Level: intermediate 8394 8395 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8396 @*/ 8397 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8398 { 8399 DM rdm; 8400 PetscFE fe; 8401 PetscScalar *v; 8402 PetscInt dim, cStart, cEnd, c; 8403 8404 PetscFunctionBeginUser; 8405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8406 PetscValidPointer(label, 2); 8407 PetscValidPointer(val, 3); 8408 PetscCall(DMClone(dm, &rdm)); 8409 PetscCall(DMGetDimension(rdm, &dim)); 8410 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8411 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8412 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8413 PetscCall(PetscFEDestroy(&fe)); 8414 PetscCall(DMCreateDS(rdm)); 8415 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8416 PetscCall(DMCreateGlobalVector(rdm, val)); 8417 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8418 PetscCall(VecGetArray(*val, &v)); 8419 for (c = cStart; c < cEnd; ++c) { 8420 PetscScalar *lv; 8421 PetscInt cval; 8422 8423 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8424 PetscCall(DMLabelGetValue(label, c, &cval)); 8425 *lv = cval; 8426 } 8427 PetscCall(VecRestoreArray(*val, &v)); 8428 PetscCall(DMDestroy(&rdm)); 8429 PetscFunctionReturn(0); 8430 } 8431 8432 /*@ 8433 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8434 8435 Input Parameter: 8436 . dm - The `DMPLEX` object 8437 8438 Level: developer 8439 8440 Notes: 8441 This is a useful diagnostic when creating meshes programmatically. 8442 8443 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8444 8445 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8446 @*/ 8447 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8448 { 8449 PetscSection coneSection, supportSection; 8450 const PetscInt *cone, *support; 8451 PetscInt coneSize, c, supportSize, s; 8452 PetscInt pStart, pEnd, p, pp, csize, ssize; 8453 PetscBool storagecheck = PETSC_TRUE; 8454 8455 PetscFunctionBegin; 8456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8457 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8458 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8459 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8460 /* Check that point p is found in the support of its cone points, and vice versa */ 8461 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8462 for (p = pStart; p < pEnd; ++p) { 8463 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8464 PetscCall(DMPlexGetCone(dm, p, &cone)); 8465 for (c = 0; c < coneSize; ++c) { 8466 PetscBool dup = PETSC_FALSE; 8467 PetscInt d; 8468 for (d = c - 1; d >= 0; --d) { 8469 if (cone[c] == cone[d]) { 8470 dup = PETSC_TRUE; 8471 break; 8472 } 8473 } 8474 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8475 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8476 for (s = 0; s < supportSize; ++s) { 8477 if (support[s] == p) break; 8478 } 8479 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8480 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8481 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8482 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8483 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8484 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8485 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8486 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]); 8487 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8488 } 8489 } 8490 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8491 if (p != pp) { 8492 storagecheck = PETSC_FALSE; 8493 continue; 8494 } 8495 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8496 PetscCall(DMPlexGetSupport(dm, p, &support)); 8497 for (s = 0; s < supportSize; ++s) { 8498 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8499 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8500 for (c = 0; c < coneSize; ++c) { 8501 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8502 if (cone[c] != pp) { 8503 c = 0; 8504 break; 8505 } 8506 if (cone[c] == p) break; 8507 } 8508 if (c >= coneSize) { 8509 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8510 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8511 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8512 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8513 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8514 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8515 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8516 } 8517 } 8518 } 8519 if (storagecheck) { 8520 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8521 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8522 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8523 } 8524 PetscFunctionReturn(0); 8525 } 8526 8527 /* 8528 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. 8529 */ 8530 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8531 { 8532 DMPolytopeType cct; 8533 PetscInt ptpoints[4]; 8534 const PetscInt *cone, *ccone, *ptcone; 8535 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8536 8537 PetscFunctionBegin; 8538 *unsplit = 0; 8539 switch (ct) { 8540 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8541 ptpoints[npt++] = c; 8542 break; 8543 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8544 PetscCall(DMPlexGetCone(dm, c, &cone)); 8545 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8546 for (cp = 0; cp < coneSize; ++cp) { 8547 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8548 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8549 } 8550 break; 8551 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8552 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8553 PetscCall(DMPlexGetCone(dm, c, &cone)); 8554 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8555 for (cp = 0; cp < coneSize; ++cp) { 8556 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8557 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8558 for (ccp = 0; ccp < cconeSize; ++ccp) { 8559 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8560 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8561 PetscInt p; 8562 for (p = 0; p < npt; ++p) 8563 if (ptpoints[p] == ccone[ccp]) break; 8564 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8565 } 8566 } 8567 } 8568 break; 8569 default: 8570 break; 8571 } 8572 for (pt = 0; pt < npt; ++pt) { 8573 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8574 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8575 } 8576 PetscFunctionReturn(0); 8577 } 8578 8579 /*@ 8580 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8581 8582 Input Parameters: 8583 + dm - The `DMPLEX` object 8584 - cellHeight - Normally 0 8585 8586 Level: developer 8587 8588 Notes: 8589 This is a useful diagnostic when creating meshes programmatically. 8590 Currently applicable only to homogeneous simplex or tensor meshes. 8591 8592 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8593 8594 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8595 @*/ 8596 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8597 { 8598 DMPlexInterpolatedFlag interp; 8599 DMPolytopeType ct; 8600 PetscInt vStart, vEnd, cStart, cEnd, c; 8601 8602 PetscFunctionBegin; 8603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8604 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8605 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8606 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8607 for (c = cStart; c < cEnd; ++c) { 8608 PetscInt *closure = NULL; 8609 PetscInt coneSize, closureSize, cl, Nv = 0; 8610 8611 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8612 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8613 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8614 if (interp == DMPLEX_INTERPOLATED_FULL) { 8615 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8616 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)); 8617 } 8618 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8619 for (cl = 0; cl < closureSize * 2; cl += 2) { 8620 const PetscInt p = closure[cl]; 8621 if ((p >= vStart) && (p < vEnd)) ++Nv; 8622 } 8623 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8624 /* Special Case: Tensor faces with identified vertices */ 8625 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8626 PetscInt unsplit; 8627 8628 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8629 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8630 } 8631 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)); 8632 } 8633 PetscFunctionReturn(0); 8634 } 8635 8636 /*@ 8637 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8638 8639 Collective on dm 8640 8641 Input Parameters: 8642 + dm - The `DMPLEX` object 8643 - cellHeight - Normally 0 8644 8645 Level: developer 8646 8647 Notes: 8648 This is a useful diagnostic when creating meshes programmatically. 8649 This routine is only relevant for meshes that are fully interpolated across all ranks. 8650 It will error out if a partially interpolated mesh is given on some rank. 8651 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8652 8653 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8654 8655 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8656 @*/ 8657 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8658 { 8659 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8660 DMPlexInterpolatedFlag interpEnum; 8661 8662 PetscFunctionBegin; 8663 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8664 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8665 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8666 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8667 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8668 PetscFunctionReturn(0); 8669 } 8670 8671 PetscCall(DMGetDimension(dm, &dim)); 8672 PetscCall(DMPlexGetDepth(dm, &depth)); 8673 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8674 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8675 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8676 for (c = cStart; c < cEnd; ++c) { 8677 const PetscInt *cone, *ornt, *faceSizes, *faces; 8678 const DMPolytopeType *faceTypes; 8679 DMPolytopeType ct; 8680 PetscInt numFaces, coneSize, f; 8681 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8682 8683 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8684 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8685 if (unsplit) continue; 8686 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8687 PetscCall(DMPlexGetCone(dm, c, &cone)); 8688 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8689 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8690 for (cl = 0; cl < closureSize * 2; cl += 2) { 8691 const PetscInt p = closure[cl]; 8692 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8693 } 8694 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8695 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); 8696 for (f = 0; f < numFaces; ++f) { 8697 DMPolytopeType fct; 8698 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8699 8700 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8701 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8702 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8703 const PetscInt p = fclosure[cl]; 8704 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8705 } 8706 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]); 8707 for (v = 0; v < fnumCorners; ++v) { 8708 if (fclosure[v] != faces[fOff + v]) { 8709 PetscInt v1; 8710 8711 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8712 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8713 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8714 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8715 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8716 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]); 8717 } 8718 } 8719 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8720 fOff += faceSizes[f]; 8721 } 8722 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8723 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8724 } 8725 } 8726 PetscFunctionReturn(0); 8727 } 8728 8729 /*@ 8730 DMPlexCheckGeometry - Check the geometry of mesh cells 8731 8732 Input Parameter: 8733 . dm - The `DMPLEX` object 8734 8735 Level: developer 8736 8737 Notes: 8738 This is a useful diagnostic when creating meshes programmatically. 8739 8740 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8741 8742 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8743 @*/ 8744 PetscErrorCode DMPlexCheckGeometry(DM dm) 8745 { 8746 Vec coordinates; 8747 PetscReal detJ, J[9], refVol = 1.0; 8748 PetscReal vol; 8749 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8750 8751 PetscFunctionBegin; 8752 PetscCall(DMGetDimension(dm, &dim)); 8753 PetscCall(DMGetCoordinateDim(dm, &dE)); 8754 if (dim != dE) PetscFunctionReturn(0); 8755 PetscCall(DMPlexGetDepth(dm, &depth)); 8756 for (d = 0; d < dim; ++d) refVol *= 2.0; 8757 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8758 /* Make sure local coordinates are created, because that step is collective */ 8759 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8760 for (c = cStart; c < cEnd; ++c) { 8761 DMPolytopeType ct; 8762 PetscInt unsplit; 8763 PetscBool ignoreZeroVol = PETSC_FALSE; 8764 8765 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8766 switch (ct) { 8767 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8768 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8769 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8770 ignoreZeroVol = PETSC_TRUE; 8771 break; 8772 default: 8773 break; 8774 } 8775 switch (ct) { 8776 case DM_POLYTOPE_TRI_PRISM: 8777 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8778 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8779 case DM_POLYTOPE_PYRAMID: 8780 continue; 8781 default: 8782 break; 8783 } 8784 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8785 if (unsplit) continue; 8786 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8787 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); 8788 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8789 /* This should work with periodicity since DG coordinates should be used */ 8790 if (depth > 1) { 8791 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8792 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); 8793 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8794 } 8795 } 8796 PetscFunctionReturn(0); 8797 } 8798 8799 /*@ 8800 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8801 8802 Collective on dm 8803 8804 Input Parameters: 8805 + dm - The `DMPLEX` object 8806 . pointSF - The `PetscSF`, or NULL for `PointSF` attached to `DM` 8807 - allowExtraRoots - Flag to allow extra points not present in the `DM` 8808 8809 Level: developer 8810 8811 Notes: 8812 This is mainly intended for debugging/testing purposes. 8813 8814 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8815 8816 Extra roots can come from priodic cuts, where additional points appear on the boundary 8817 8818 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 8819 @*/ 8820 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 8821 { 8822 PetscInt l, nleaves, nroots, overlap; 8823 const PetscInt *locals; 8824 const PetscSFNode *remotes; 8825 PetscBool distributed; 8826 MPI_Comm comm; 8827 PetscMPIInt rank; 8828 8829 PetscFunctionBegin; 8830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8831 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8832 else pointSF = dm->sf; 8833 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8834 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8835 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8836 { 8837 PetscMPIInt mpiFlag; 8838 8839 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8840 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8841 } 8842 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8843 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8844 if (!distributed) { 8845 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); 8846 PetscFunctionReturn(0); 8847 } 8848 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); 8849 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8850 8851 /* Check SF graph is compatible with DMPlex chart */ 8852 { 8853 PetscInt pStart, pEnd, maxLeaf; 8854 8855 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8856 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8857 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8858 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8859 } 8860 8861 /* Check Point SF has no local points referenced */ 8862 for (l = 0; l < nleaves; l++) { 8863 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); 8864 } 8865 8866 /* Check there are no cells in interface */ 8867 if (!overlap) { 8868 PetscInt cellHeight, cStart, cEnd; 8869 8870 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8871 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8872 for (l = 0; l < nleaves; ++l) { 8873 const PetscInt point = locals ? locals[l] : l; 8874 8875 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8876 } 8877 } 8878 8879 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8880 { 8881 const PetscInt *rootdegree; 8882 8883 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8884 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8885 for (l = 0; l < nleaves; ++l) { 8886 const PetscInt point = locals ? locals[l] : l; 8887 const PetscInt *cone; 8888 PetscInt coneSize, c, idx; 8889 8890 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8891 PetscCall(DMPlexGetCone(dm, point, &cone)); 8892 for (c = 0; c < coneSize; ++c) { 8893 if (!rootdegree[cone[c]]) { 8894 if (locals) { 8895 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8896 } else { 8897 idx = (cone[c] < nleaves) ? cone[c] : -1; 8898 } 8899 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8900 } 8901 } 8902 } 8903 } 8904 PetscFunctionReturn(0); 8905 } 8906 8907 /*@ 8908 DMPlexCheck - Perform various checks of Plex sanity 8909 8910 Input Parameter: 8911 . dm - The `DMPLEX` object 8912 8913 Level: developer 8914 8915 Notes: 8916 This is a useful diagnostic when creating meshes programmatically. 8917 8918 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8919 8920 Currently does not include DMPlexCheckCellShape(). 8921 8922 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, DMCreate(), DMSetFromOptions() 8923 @*/ 8924 PetscErrorCode DMPlexCheck(DM dm) 8925 { 8926 PetscInt cellHeight; 8927 8928 PetscFunctionBegin; 8929 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8930 PetscCall(DMPlexCheckSymmetry(dm)); 8931 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8932 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8933 PetscCall(DMPlexCheckGeometry(dm)); 8934 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 8935 PetscCall(DMPlexCheckInterfaceCones(dm)); 8936 PetscFunctionReturn(0); 8937 } 8938 8939 typedef struct cell_stats { 8940 PetscReal min, max, sum, squaresum; 8941 PetscInt count; 8942 } cell_stats_t; 8943 8944 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 8945 { 8946 PetscInt i, N = *len; 8947 8948 for (i = 0; i < N; i++) { 8949 cell_stats_t *A = (cell_stats_t *)a; 8950 cell_stats_t *B = (cell_stats_t *)b; 8951 8952 B->min = PetscMin(A->min, B->min); 8953 B->max = PetscMax(A->max, B->max); 8954 B->sum += A->sum; 8955 B->squaresum += A->squaresum; 8956 B->count += A->count; 8957 } 8958 } 8959 8960 /*@ 8961 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8962 8963 Collective on dm 8964 8965 Input Parameters: 8966 + dm - The `DMPLEX` object 8967 . output - If true, statistics will be displayed on stdout 8968 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 8969 8970 Level: developer 8971 8972 Notes: 8973 This is mainly intended for debugging/testing purposes. 8974 8975 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8976 8977 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8978 @*/ 8979 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8980 { 8981 DM dmCoarse; 8982 cell_stats_t stats, globalStats; 8983 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8984 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8985 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8986 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8987 PetscMPIInt rank, size; 8988 8989 PetscFunctionBegin; 8990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8991 stats.min = PETSC_MAX_REAL; 8992 stats.max = PETSC_MIN_REAL; 8993 stats.sum = stats.squaresum = 0.; 8994 stats.count = 0; 8995 8996 PetscCallMPI(MPI_Comm_size(comm, &size)); 8997 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8998 PetscCall(DMGetCoordinateDim(dm, &cdim)); 8999 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9000 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9001 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9002 for (c = cStart; c < cEnd; c++) { 9003 PetscInt i; 9004 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9005 9006 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9007 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9008 for (i = 0; i < PetscSqr(cdim); ++i) { 9009 frobJ += J[i] * J[i]; 9010 frobInvJ += invJ[i] * invJ[i]; 9011 } 9012 cond2 = frobJ * frobInvJ; 9013 cond = PetscSqrtReal(cond2); 9014 9015 stats.min = PetscMin(stats.min, cond); 9016 stats.max = PetscMax(stats.max, cond); 9017 stats.sum += cond; 9018 stats.squaresum += cond2; 9019 stats.count++; 9020 if (output && cond > limit) { 9021 PetscSection coordSection; 9022 Vec coordsLocal; 9023 PetscScalar *coords = NULL; 9024 PetscInt Nv, d, clSize, cl, *closure = NULL; 9025 9026 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9027 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9028 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9029 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9030 for (i = 0; i < Nv / cdim; ++i) { 9031 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9032 for (d = 0; d < cdim; ++d) { 9033 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9034 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9035 } 9036 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9037 } 9038 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9039 for (cl = 0; cl < clSize * 2; cl += 2) { 9040 const PetscInt edge = closure[cl]; 9041 9042 if ((edge >= eStart) && (edge < eEnd)) { 9043 PetscReal len; 9044 9045 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9046 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9047 } 9048 } 9049 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9050 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9051 } 9052 } 9053 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9054 9055 if (size > 1) { 9056 PetscMPIInt blockLengths[2] = {4, 1}; 9057 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9058 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9059 MPI_Op statReduce; 9060 9061 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9062 PetscCallMPI(MPI_Type_commit(&statType)); 9063 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9064 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9065 PetscCallMPI(MPI_Op_free(&statReduce)); 9066 PetscCallMPI(MPI_Type_free(&statType)); 9067 } else { 9068 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9069 } 9070 if (rank == 0) { 9071 count = globalStats.count; 9072 min = globalStats.min; 9073 max = globalStats.max; 9074 mean = globalStats.sum / globalStats.count; 9075 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9076 } 9077 9078 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)); 9079 PetscCall(PetscFree2(J, invJ)); 9080 9081 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9082 if (dmCoarse) { 9083 PetscBool isplex; 9084 9085 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9086 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9087 } 9088 PetscFunctionReturn(0); 9089 } 9090 9091 /*@ 9092 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9093 orthogonal quality below given tolerance. 9094 9095 Collective on dm 9096 9097 Input Parameters: 9098 + dm - The `DMPLEX` object 9099 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9100 - atol - [0, 1] Absolute tolerance for tagging cells. 9101 9102 Output Parameters: 9103 + OrthQual - Vec containing orthogonal quality per cell 9104 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9105 9106 Options Database Keys: 9107 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9108 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9109 9110 Level: intermediate 9111 9112 Notes: 9113 Orthogonal quality is given by the following formula: 9114 9115 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9116 9117 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 9118 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9119 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9120 calculating the cosine of the angle between these vectors. 9121 9122 Orthogonal quality ranges from 1 (best) to 0 (worst). 9123 9124 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9125 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9126 9127 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9128 9129 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9130 @*/ 9131 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9132 { 9133 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9134 PetscInt *idx; 9135 PetscScalar *oqVals; 9136 const PetscScalar *cellGeomArr, *faceGeomArr; 9137 PetscReal *ci, *fi, *Ai; 9138 MPI_Comm comm; 9139 Vec cellgeom, facegeom; 9140 DM dmFace, dmCell; 9141 IS glob; 9142 ISLocalToGlobalMapping ltog; 9143 PetscViewer vwr; 9144 9145 PetscFunctionBegin; 9146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9147 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9148 PetscValidPointer(OrthQual, 4); 9149 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9150 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9151 PetscCall(DMGetDimension(dm, &nc)); 9152 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9153 { 9154 DMPlexInterpolatedFlag interpFlag; 9155 9156 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9157 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9158 PetscMPIInt rank; 9159 9160 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9161 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9162 } 9163 } 9164 if (OrthQualLabel) { 9165 PetscValidPointer(OrthQualLabel, 5); 9166 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9167 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9168 } else { 9169 *OrthQualLabel = NULL; 9170 } 9171 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9172 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9173 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9174 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9175 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9176 PetscCall(VecCreate(comm, OrthQual)); 9177 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9178 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9179 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9180 PetscCall(VecSetUp(*OrthQual)); 9181 PetscCall(ISDestroy(&glob)); 9182 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9183 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9184 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9185 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9186 PetscCall(VecGetDM(cellgeom, &dmCell)); 9187 PetscCall(VecGetDM(facegeom, &dmFace)); 9188 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9189 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9190 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9191 PetscInt cellarr[2], *adj = NULL; 9192 PetscScalar *cArr, *fArr; 9193 PetscReal minvalc = 1.0, minvalf = 1.0; 9194 PetscFVCellGeom *cg; 9195 9196 idx[cellIter] = cell - cStart; 9197 cellarr[0] = cell; 9198 /* Make indexing into cellGeom easier */ 9199 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9200 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9201 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9202 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9203 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9204 PetscInt i; 9205 const PetscInt neigh = adj[cellneigh]; 9206 PetscReal normci = 0, normfi = 0, normai = 0; 9207 PetscFVCellGeom *cgneigh; 9208 PetscFVFaceGeom *fg; 9209 9210 /* Don't count ourselves in the neighbor list */ 9211 if (neigh == cell) continue; 9212 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9213 cellarr[1] = neigh; 9214 { 9215 PetscInt numcovpts; 9216 const PetscInt *covpts; 9217 9218 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9219 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9220 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9221 } 9222 9223 /* Compute c_i, f_i and their norms */ 9224 for (i = 0; i < nc; i++) { 9225 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9226 fi[i] = fg->centroid[i] - cg->centroid[i]; 9227 Ai[i] = fg->normal[i]; 9228 normci += PetscPowReal(ci[i], 2); 9229 normfi += PetscPowReal(fi[i], 2); 9230 normai += PetscPowReal(Ai[i], 2); 9231 } 9232 normci = PetscSqrtReal(normci); 9233 normfi = PetscSqrtReal(normfi); 9234 normai = PetscSqrtReal(normai); 9235 9236 /* Normalize and compute for each face-cell-normal pair */ 9237 for (i = 0; i < nc; i++) { 9238 ci[i] = ci[i] / normci; 9239 fi[i] = fi[i] / normfi; 9240 Ai[i] = Ai[i] / normai; 9241 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9242 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9243 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9244 } 9245 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9246 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9247 } 9248 PetscCall(PetscFree(adj)); 9249 PetscCall(PetscFree2(cArr, fArr)); 9250 /* Defer to cell if they're equal */ 9251 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9252 if (OrthQualLabel) { 9253 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9254 } 9255 } 9256 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9257 PetscCall(VecAssemblyBegin(*OrthQual)); 9258 PetscCall(VecAssemblyEnd(*OrthQual)); 9259 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9260 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9261 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9262 if (OrthQualLabel) { 9263 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9264 } 9265 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9266 PetscCall(PetscViewerDestroy(&vwr)); 9267 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9268 PetscFunctionReturn(0); 9269 } 9270 9271 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9272 * interpolator construction */ 9273 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9274 { 9275 PetscSection section, newSection, gsection; 9276 PetscSF sf; 9277 PetscBool hasConstraints, ghasConstraints; 9278 9279 PetscFunctionBegin; 9280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9281 PetscValidPointer(odm, 2); 9282 PetscCall(DMGetLocalSection(dm, §ion)); 9283 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9284 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9285 if (!ghasConstraints) { 9286 PetscCall(PetscObjectReference((PetscObject)dm)); 9287 *odm = dm; 9288 PetscFunctionReturn(0); 9289 } 9290 PetscCall(DMClone(dm, odm)); 9291 PetscCall(DMCopyFields(dm, *odm)); 9292 PetscCall(DMGetLocalSection(*odm, &newSection)); 9293 PetscCall(DMGetPointSF(*odm, &sf)); 9294 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9295 PetscCall(DMSetGlobalSection(*odm, gsection)); 9296 PetscCall(PetscSectionDestroy(&gsection)); 9297 PetscFunctionReturn(0); 9298 } 9299 9300 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9301 { 9302 DM dmco, dmfo; 9303 Mat interpo; 9304 Vec rscale; 9305 Vec cglobalo, clocal; 9306 Vec fglobal, fglobalo, flocal; 9307 PetscBool regular; 9308 9309 PetscFunctionBegin; 9310 PetscCall(DMGetFullDM(dmc, &dmco)); 9311 PetscCall(DMGetFullDM(dmf, &dmfo)); 9312 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9313 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9314 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9315 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9316 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9317 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9318 PetscCall(VecSet(cglobalo, 0.)); 9319 PetscCall(VecSet(clocal, 0.)); 9320 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9321 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9322 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9323 PetscCall(VecSet(fglobal, 0.)); 9324 PetscCall(VecSet(fglobalo, 0.)); 9325 PetscCall(VecSet(flocal, 0.)); 9326 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9327 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9328 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9329 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9330 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9331 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9332 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9333 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9334 *shift = fglobal; 9335 PetscCall(VecDestroy(&flocal)); 9336 PetscCall(VecDestroy(&fglobalo)); 9337 PetscCall(VecDestroy(&clocal)); 9338 PetscCall(VecDestroy(&cglobalo)); 9339 PetscCall(VecDestroy(&rscale)); 9340 PetscCall(MatDestroy(&interpo)); 9341 PetscCall(DMDestroy(&dmfo)); 9342 PetscCall(DMDestroy(&dmco)); 9343 PetscFunctionReturn(0); 9344 } 9345 9346 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9347 { 9348 PetscObject shifto; 9349 Vec shift; 9350 9351 PetscFunctionBegin; 9352 if (!interp) { 9353 Vec rscale; 9354 9355 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9356 PetscCall(VecDestroy(&rscale)); 9357 } else { 9358 PetscCall(PetscObjectReference((PetscObject)interp)); 9359 } 9360 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9361 if (!shifto) { 9362 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9363 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9364 shifto = (PetscObject)shift; 9365 PetscCall(VecDestroy(&shift)); 9366 } 9367 shift = (Vec)shifto; 9368 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9369 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9370 PetscCall(MatDestroy(&interp)); 9371 PetscFunctionReturn(0); 9372 } 9373 9374 /* Pointwise interpolation 9375 Just code FEM for now 9376 u^f = I u^c 9377 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9378 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9379 I_{ij} = psi^f_i phi^c_j 9380 */ 9381 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9382 { 9383 PetscSection gsc, gsf; 9384 PetscInt m, n; 9385 void *ctx; 9386 DM cdm; 9387 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9388 9389 PetscFunctionBegin; 9390 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9391 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9392 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9393 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9394 9395 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9396 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9397 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9398 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9399 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9400 9401 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9402 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9403 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9404 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9405 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9406 if (scaling) { 9407 /* Use naive scaling */ 9408 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9409 } 9410 PetscFunctionReturn(0); 9411 } 9412 9413 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9414 { 9415 VecScatter ctx; 9416 9417 PetscFunctionBegin; 9418 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9419 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9420 PetscCall(VecScatterDestroy(&ctx)); 9421 PetscFunctionReturn(0); 9422 } 9423 9424 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[]) 9425 { 9426 const PetscInt Nc = uOff[1] - uOff[0]; 9427 PetscInt c; 9428 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9429 } 9430 9431 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9432 { 9433 DM dmc; 9434 PetscDS ds; 9435 Vec ones, locmass; 9436 IS cellIS; 9437 PetscFormKey key; 9438 PetscInt depth; 9439 9440 PetscFunctionBegin; 9441 PetscCall(DMClone(dm, &dmc)); 9442 PetscCall(DMCopyDisc(dm, dmc)); 9443 PetscCall(DMGetDS(dmc, &ds)); 9444 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9445 PetscCall(DMCreateGlobalVector(dmc, mass)); 9446 PetscCall(DMGetLocalVector(dmc, &ones)); 9447 PetscCall(DMGetLocalVector(dmc, &locmass)); 9448 PetscCall(DMPlexGetDepth(dmc, &depth)); 9449 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9450 PetscCall(VecSet(locmass, 0.0)); 9451 PetscCall(VecSet(ones, 1.0)); 9452 key.label = NULL; 9453 key.value = 0; 9454 key.field = 0; 9455 key.part = 0; 9456 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9457 PetscCall(ISDestroy(&cellIS)); 9458 PetscCall(VecSet(*mass, 0.0)); 9459 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9460 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9461 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9462 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9463 PetscCall(DMDestroy(&dmc)); 9464 PetscFunctionReturn(0); 9465 } 9466 9467 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9468 { 9469 PetscSection gsc, gsf; 9470 PetscInt m, n; 9471 void *ctx; 9472 DM cdm; 9473 PetscBool regular; 9474 9475 PetscFunctionBegin; 9476 if (dmFine == dmCoarse) { 9477 DM dmc; 9478 PetscDS ds; 9479 PetscWeakForm wf; 9480 Vec u; 9481 IS cellIS; 9482 PetscFormKey key; 9483 PetscInt depth; 9484 9485 PetscCall(DMClone(dmFine, &dmc)); 9486 PetscCall(DMCopyDisc(dmFine, dmc)); 9487 PetscCall(DMGetDS(dmc, &ds)); 9488 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9489 PetscCall(PetscWeakFormClear(wf)); 9490 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9491 PetscCall(DMCreateMatrix(dmc, mass)); 9492 PetscCall(DMGetLocalVector(dmc, &u)); 9493 PetscCall(DMPlexGetDepth(dmc, &depth)); 9494 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9495 PetscCall(MatZeroEntries(*mass)); 9496 key.label = NULL; 9497 key.value = 0; 9498 key.field = 0; 9499 key.part = 0; 9500 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9501 PetscCall(ISDestroy(&cellIS)); 9502 PetscCall(DMRestoreLocalVector(dmc, &u)); 9503 PetscCall(DMDestroy(&dmc)); 9504 } else { 9505 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9506 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9507 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9508 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9509 9510 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9511 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9512 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9513 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9514 9515 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9516 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9517 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9518 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9519 } 9520 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9521 PetscFunctionReturn(0); 9522 } 9523 9524 /*@ 9525 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9526 9527 Input Parameter: 9528 . dm - The `DMPLEX` object 9529 9530 Output Parameter: 9531 . regular - The flag 9532 9533 Level: intermediate 9534 9535 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9536 @*/ 9537 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9538 { 9539 PetscFunctionBegin; 9540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9541 PetscValidBoolPointer(regular, 2); 9542 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9543 PetscFunctionReturn(0); 9544 } 9545 9546 /*@ 9547 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9548 9549 Input Parameters: 9550 + dm - The `DMPLEX` object 9551 - regular - The flag 9552 9553 Level: intermediate 9554 9555 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9556 @*/ 9557 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9558 { 9559 PetscFunctionBegin; 9560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9561 ((DM_Plex *)dm->data)->regularRefinement = regular; 9562 PetscFunctionReturn(0); 9563 } 9564 9565 /*@ 9566 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9567 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9568 9569 Not Collective 9570 9571 Input Parameter: 9572 . dm - The `DMPLEX` object 9573 9574 Output Parameters: 9575 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9576 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9577 9578 Level: intermediate 9579 9580 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9581 @*/ 9582 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9583 { 9584 DM_Plex *plex = (DM_Plex *)dm->data; 9585 9586 PetscFunctionBegin; 9587 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9588 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9589 if (anchorSection) *anchorSection = plex->anchorSection; 9590 if (anchorIS) *anchorIS = plex->anchorIS; 9591 PetscFunctionReturn(0); 9592 } 9593 9594 /*@ 9595 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9596 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9597 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9598 9599 Collective on dm 9600 9601 Input Parameters: 9602 + dm - The `DMPLEX` object 9603 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9604 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9605 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9606 9607 Level: intermediate 9608 9609 Notes: 9610 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9611 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9612 9613 The reference counts of anchorSection and anchorIS are incremented. 9614 9615 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9616 @*/ 9617 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9618 { 9619 DM_Plex *plex = (DM_Plex *)dm->data; 9620 PetscMPIInt result; 9621 9622 PetscFunctionBegin; 9623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9624 if (anchorSection) { 9625 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9626 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9627 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9628 } 9629 if (anchorIS) { 9630 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9631 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9632 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9633 } 9634 9635 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9636 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9637 plex->anchorSection = anchorSection; 9638 9639 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9640 PetscCall(ISDestroy(&plex->anchorIS)); 9641 plex->anchorIS = anchorIS; 9642 9643 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9644 PetscInt size, a, pStart, pEnd; 9645 const PetscInt *anchors; 9646 9647 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9648 PetscCall(ISGetLocalSize(anchorIS, &size)); 9649 PetscCall(ISGetIndices(anchorIS, &anchors)); 9650 for (a = 0; a < size; a++) { 9651 PetscInt p; 9652 9653 p = anchors[a]; 9654 if (p >= pStart && p < pEnd) { 9655 PetscInt dof; 9656 9657 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9658 if (dof) { 9659 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9660 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9661 } 9662 } 9663 } 9664 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9665 } 9666 /* reset the generic constraints */ 9667 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9668 PetscFunctionReturn(0); 9669 } 9670 9671 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9672 { 9673 PetscSection anchorSection; 9674 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9675 9676 PetscFunctionBegin; 9677 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9678 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9679 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9680 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9681 if (numFields) { 9682 PetscInt f; 9683 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9684 9685 for (f = 0; f < numFields; f++) { 9686 PetscInt numComp; 9687 9688 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9689 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9690 } 9691 } 9692 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9693 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9694 pStart = PetscMax(pStart, sStart); 9695 pEnd = PetscMin(pEnd, sEnd); 9696 pEnd = PetscMax(pStart, pEnd); 9697 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9698 for (p = pStart; p < pEnd; p++) { 9699 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9700 if (dof) { 9701 PetscCall(PetscSectionGetDof(section, p, &dof)); 9702 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9703 for (f = 0; f < numFields; f++) { 9704 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9705 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9706 } 9707 } 9708 } 9709 PetscCall(PetscSectionSetUp(*cSec)); 9710 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9711 PetscFunctionReturn(0); 9712 } 9713 9714 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9715 { 9716 PetscSection aSec; 9717 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9718 const PetscInt *anchors; 9719 PetscInt numFields, f; 9720 IS aIS; 9721 MatType mtype; 9722 PetscBool iscuda, iskokkos; 9723 9724 PetscFunctionBegin; 9725 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9726 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9727 PetscCall(PetscSectionGetStorageSize(section, &n)); 9728 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9729 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9730 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9731 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9732 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9733 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9734 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9735 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9736 else mtype = MATSEQAIJ; 9737 PetscCall(MatSetType(*cMat, mtype)); 9738 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9739 PetscCall(ISGetIndices(aIS, &anchors)); 9740 /* cSec will be a subset of aSec and section */ 9741 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9742 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9743 PetscCall(PetscMalloc1(m + 1, &i)); 9744 i[0] = 0; 9745 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9746 for (p = pStart; p < pEnd; p++) { 9747 PetscInt rDof, rOff, r; 9748 9749 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9750 if (!rDof) continue; 9751 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9752 if (numFields) { 9753 for (f = 0; f < numFields; f++) { 9754 annz = 0; 9755 for (r = 0; r < rDof; r++) { 9756 a = anchors[rOff + r]; 9757 if (a < sStart || a >= sEnd) continue; 9758 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9759 annz += aDof; 9760 } 9761 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9762 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9763 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9764 } 9765 } else { 9766 annz = 0; 9767 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9768 for (q = 0; q < dof; q++) { 9769 a = anchors[rOff + q]; 9770 if (a < sStart || a >= sEnd) continue; 9771 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9772 annz += aDof; 9773 } 9774 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9775 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9776 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9777 } 9778 } 9779 nnz = i[m]; 9780 PetscCall(PetscMalloc1(nnz, &j)); 9781 offset = 0; 9782 for (p = pStart; p < pEnd; p++) { 9783 if (numFields) { 9784 for (f = 0; f < numFields; f++) { 9785 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9786 for (q = 0; q < dof; q++) { 9787 PetscInt rDof, rOff, r; 9788 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9789 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9790 for (r = 0; r < rDof; r++) { 9791 PetscInt s; 9792 9793 a = anchors[rOff + r]; 9794 if (a < sStart || a >= sEnd) continue; 9795 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9796 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9797 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9798 } 9799 } 9800 } 9801 } else { 9802 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9803 for (q = 0; q < dof; q++) { 9804 PetscInt rDof, rOff, r; 9805 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9806 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9807 for (r = 0; r < rDof; r++) { 9808 PetscInt s; 9809 9810 a = anchors[rOff + r]; 9811 if (a < sStart || a >= sEnd) continue; 9812 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9813 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9814 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9815 } 9816 } 9817 } 9818 } 9819 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9820 PetscCall(PetscFree(i)); 9821 PetscCall(PetscFree(j)); 9822 PetscCall(ISRestoreIndices(aIS, &anchors)); 9823 PetscFunctionReturn(0); 9824 } 9825 9826 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9827 { 9828 DM_Plex *plex = (DM_Plex *)dm->data; 9829 PetscSection anchorSection, section, cSec; 9830 Mat cMat; 9831 9832 PetscFunctionBegin; 9833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9834 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9835 if (anchorSection) { 9836 PetscInt Nf; 9837 9838 PetscCall(DMGetLocalSection(dm, §ion)); 9839 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9840 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9841 PetscCall(DMGetNumFields(dm, &Nf)); 9842 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9843 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9844 PetscCall(PetscSectionDestroy(&cSec)); 9845 PetscCall(MatDestroy(&cMat)); 9846 } 9847 PetscFunctionReturn(0); 9848 } 9849 9850 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9851 { 9852 IS subis; 9853 PetscSection section, subsection; 9854 9855 PetscFunctionBegin; 9856 PetscCall(DMGetLocalSection(dm, §ion)); 9857 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9858 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9859 /* Create subdomain */ 9860 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9861 /* Create submodel */ 9862 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9863 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9864 PetscCall(DMSetLocalSection(*subdm, subsection)); 9865 PetscCall(PetscSectionDestroy(&subsection)); 9866 PetscCall(DMCopyDisc(dm, *subdm)); 9867 /* Create map from submodel to global model */ 9868 if (is) { 9869 PetscSection sectionGlobal, subsectionGlobal; 9870 IS spIS; 9871 const PetscInt *spmap; 9872 PetscInt *subIndices; 9873 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9874 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9875 9876 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9877 PetscCall(ISGetIndices(spIS, &spmap)); 9878 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9879 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9880 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9881 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9882 for (p = pStart; p < pEnd; ++p) { 9883 PetscInt gdof, pSubSize = 0; 9884 9885 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9886 if (gdof > 0) { 9887 for (f = 0; f < Nf; ++f) { 9888 PetscInt fdof, fcdof; 9889 9890 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9891 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9892 pSubSize += fdof - fcdof; 9893 } 9894 subSize += pSubSize; 9895 if (pSubSize) { 9896 if (bs < 0) { 9897 bs = pSubSize; 9898 } else if (bs != pSubSize) { 9899 /* Layout does not admit a pointwise block size */ 9900 bs = 1; 9901 } 9902 } 9903 } 9904 } 9905 /* Must have same blocksize on all procs (some might have no points) */ 9906 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9907 bsLocal[1] = bs; 9908 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9909 if (bsMinMax[0] != bsMinMax[1]) { 9910 bs = 1; 9911 } else { 9912 bs = bsMinMax[0]; 9913 } 9914 PetscCall(PetscMalloc1(subSize, &subIndices)); 9915 for (p = pStart; p < pEnd; ++p) { 9916 PetscInt gdof, goff; 9917 9918 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9919 if (gdof > 0) { 9920 const PetscInt point = spmap[p]; 9921 9922 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9923 for (f = 0; f < Nf; ++f) { 9924 PetscInt fdof, fcdof, fc, f2, poff = 0; 9925 9926 /* Can get rid of this loop by storing field information in the global section */ 9927 for (f2 = 0; f2 < f; ++f2) { 9928 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9929 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9930 poff += fdof - fcdof; 9931 } 9932 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9933 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9934 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 9935 } 9936 } 9937 } 9938 PetscCall(ISRestoreIndices(spIS, &spmap)); 9939 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9940 if (bs > 1) { 9941 /* We need to check that the block size does not come from non-contiguous fields */ 9942 PetscInt i, j, set = 1; 9943 for (i = 0; i < subSize; i += bs) { 9944 for (j = 0; j < bs; ++j) { 9945 if (subIndices[i + j] != subIndices[i] + j) { 9946 set = 0; 9947 break; 9948 } 9949 } 9950 } 9951 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9952 } 9953 /* Attach nullspace */ 9954 for (f = 0; f < Nf; ++f) { 9955 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9956 if ((*subdm)->nullspaceConstructors[f]) break; 9957 } 9958 if (f < Nf) { 9959 MatNullSpace nullSpace; 9960 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9961 9962 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9963 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9964 } 9965 } 9966 PetscFunctionReturn(0); 9967 } 9968 9969 /*@ 9970 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9971 9972 Input Parameters: 9973 + dm - The `DM` 9974 - dummy - unused argument 9975 9976 Options Database Key: 9977 . -dm_plex_monitor_throughput - Activate the monitor 9978 9979 Level: developer 9980 9981 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 9982 @*/ 9983 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9984 { 9985 #if defined(PETSC_USE_LOG) 9986 PetscStageLog stageLog; 9987 PetscLogEvent event; 9988 PetscLogStage stage; 9989 PetscEventPerfInfo eventInfo; 9990 PetscReal cellRate, flopRate; 9991 PetscInt cStart, cEnd, Nf, N; 9992 const char *name; 9993 #endif 9994 9995 PetscFunctionBegin; 9996 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9997 #if defined(PETSC_USE_LOG) 9998 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 9999 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10000 PetscCall(DMGetNumFields(dm, &Nf)); 10001 PetscCall(PetscLogGetStageLog(&stageLog)); 10002 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10003 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10004 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10005 N = (cEnd - cStart) * Nf * eventInfo.count; 10006 flopRate = eventInfo.flops / eventInfo.time; 10007 cellRate = N / eventInfo.time; 10008 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))); 10009 #else 10010 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10011 #endif 10012 PetscFunctionReturn(0); 10013 } 10014