1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The `DMPLEX` object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Level: intermediate 28 29 Note: 30 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 31 If the mesh has no cells, this returns `PETSC_FALSE`. 32 33 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 34 @*/ 35 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 36 { 37 DMPolytopeType ct; 38 PetscInt cStart, cEnd; 39 40 PetscFunctionBegin; 41 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 42 if (cEnd <= cStart) { 43 *simplex = PETSC_FALSE; 44 PetscFunctionReturn(PETSC_SUCCESS); 45 } 46 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 47 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 48 PetscFunctionReturn(PETSC_SUCCESS); 49 } 50 51 /*@ 52 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 53 54 Input Parameters: 55 + dm - The `DMPLEX` object 56 - height - The cell height in the Plex, 0 is the default 57 58 Output Parameters: 59 + cStart - The first "normal" cell 60 - cEnd - The upper bound on "normal"" cells 61 62 Level: developer 63 64 Note: 65 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 66 67 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 68 @*/ 69 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 70 { 71 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 72 PetscInt cS, cE, c; 73 74 PetscFunctionBegin; 75 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 76 for (c = cS; c < cE; ++c) { 77 DMPolytopeType cct; 78 79 PetscCall(DMPlexGetCellType(dm, c, &cct)); 80 if ((PetscInt)cct < 0) break; 81 switch (cct) { 82 case DM_POLYTOPE_POINT: 83 case DM_POLYTOPE_SEGMENT: 84 case DM_POLYTOPE_TRIANGLE: 85 case DM_POLYTOPE_QUADRILATERAL: 86 case DM_POLYTOPE_TETRAHEDRON: 87 case DM_POLYTOPE_HEXAHEDRON: 88 ct = cct; 89 break; 90 default: 91 break; 92 } 93 if (ct != DM_POLYTOPE_UNKNOWN) break; 94 } 95 if (ct != DM_POLYTOPE_UNKNOWN) { 96 DMLabel ctLabel; 97 98 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 99 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 100 // Reset label for fast lookup 101 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 102 } 103 if (cStart) *cStart = cS; 104 if (cEnd) *cEnd = cE; 105 PetscFunctionReturn(PETSC_SUCCESS); 106 } 107 108 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 109 { 110 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 111 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 112 113 PetscFunctionBegin; 114 *ft = PETSC_VTK_INVALID; 115 PetscCall(DMGetCoordinateDim(dm, &cdim)); 116 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 117 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 118 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 119 if (field >= 0) { 120 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 121 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 122 } else { 123 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 124 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 125 } 126 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 127 if (globalvcdof[0]) { 128 *sStart = vStart; 129 *sEnd = vEnd; 130 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 131 else *ft = PETSC_VTK_POINT_FIELD; 132 } else if (globalvcdof[1]) { 133 *sStart = cStart; 134 *sEnd = cEnd; 135 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 136 else *ft = PETSC_VTK_CELL_FIELD; 137 } else { 138 if (field >= 0) { 139 const char *fieldname; 140 141 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 143 } else { 144 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 145 } 146 } 147 PetscFunctionReturn(PETSC_SUCCESS); 148 } 149 150 /*@ 151 DMPlexVecView1D - Plot many 1D solutions on the same line graph 152 153 Collective on dm 154 155 Input Parameters: 156 + dm - The `DMPLEX` object 157 . n - The number of vectors 158 . u - The array of local vectors 159 - viewer - The `PetscViewer` 160 161 Level: advanced 162 163 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 164 @*/ 165 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 166 { 167 PetscDS ds; 168 PetscDraw draw = NULL; 169 PetscDrawLG lg; 170 Vec coordinates; 171 const PetscScalar *coords, **sol; 172 PetscReal *vals; 173 PetscInt *Nc; 174 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 175 char **names; 176 177 PetscFunctionBegin; 178 PetscCall(DMGetDS(dm, &ds)); 179 PetscCall(PetscDSGetNumFields(ds, &Nf)); 180 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 181 PetscCall(PetscDSGetComponents(ds, &Nc)); 182 183 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 184 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 185 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 186 187 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 188 for (i = 0, l = 0; i < n; ++i) { 189 const char *vname; 190 191 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 192 for (f = 0; f < Nf; ++f) { 193 PetscObject disc; 194 const char *fname; 195 char tmpname[PETSC_MAX_PATH_LEN]; 196 197 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 198 /* TODO Create names for components */ 199 for (c = 0; c < Nc[f]; ++c, ++l) { 200 PetscCall(PetscObjectGetName(disc, &fname)); 201 PetscCall(PetscStrcpy(tmpname, vname)); 202 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 203 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 204 PetscCall(PetscStrallocpy(tmpname, &names[l])); 205 } 206 } 207 } 208 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 209 /* Just add P_1 support for now */ 210 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 211 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 212 PetscCall(VecGetArrayRead(coordinates, &coords)); 213 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 214 for (v = vStart; v < vEnd; ++v) { 215 PetscScalar *x, *svals; 216 217 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 218 for (i = 0; i < n; ++i) { 219 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 220 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 221 } 222 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 223 } 224 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 225 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 226 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 227 PetscCall(PetscFree3(sol, names, vals)); 228 229 PetscCall(PetscDrawLGDraw(lg)); 230 PetscCall(PetscDrawLGDestroy(&lg)); 231 PetscFunctionReturn(PETSC_SUCCESS); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 235 { 236 DM dm; 237 238 PetscFunctionBegin; 239 PetscCall(VecGetDM(u, &dm)); 240 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 241 PetscFunctionReturn(PETSC_SUCCESS); 242 } 243 244 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 245 { 246 DM dm; 247 PetscSection s; 248 PetscDraw draw, popup; 249 DM cdm; 250 PetscSection coordSection; 251 Vec coordinates; 252 const PetscScalar *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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(DMPlexCreateNaturalVector(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(VecDestroy(&v)); 626 PetscFunctionReturn(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(DMPlexCreateNaturalVector(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(VecDestroy(&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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PetscViewerGetFormat(viewer, &format)); 829 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 830 const char *name; 831 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 832 PetscInt pStart, pEnd, p, numLabels, l; 833 PetscMPIInt rank, size; 834 835 PetscCall(DMGetCoordinateDM(dm, &cdm)); 836 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 837 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 838 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 839 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 840 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 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 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 945 PetscCall(PetscViewerFlush(viewer)); 946 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 947 const char *name, *color; 948 const char *defcolors[3] = {"gray", "orange", "green"}; 949 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 950 char lname[PETSC_MAX_PATH_LEN]; 951 PetscReal scale = 2.0; 952 PetscReal tikzscale = 1.0; 953 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 954 double tcoords[3]; 955 PetscScalar *coords; 956 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 957 PetscMPIInt rank, size; 958 char **names, **colors, **lcolors; 959 PetscBool flg, lflg; 960 PetscBT wp = NULL; 961 PetscInt pEnd, pStart; 962 963 PetscCall(DMGetCoordinateDM(dm, &cdm)); 964 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 965 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 966 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 967 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 968 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 969 PetscCall(DMGetDimension(dm, &dim)); 970 PetscCall(DMPlexGetDepth(dm, &depth)); 971 PetscCall(DMGetNumLabels(dm, &numLabels)); 972 numLabels = PetscMax(numLabels, 10); 973 numColors = 10; 974 numLColors = 10; 975 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 976 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 977 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 978 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 979 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 980 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 981 n = 4; 982 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 983 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 984 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 985 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 986 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 987 if (!useLabels) numLabels = 0; 988 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 989 if (!useColors) { 990 numColors = 3; 991 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 992 } 993 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 994 if (!useColors) { 995 numLColors = 4; 996 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 997 } 998 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 999 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1000 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1001 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1002 if (depth < dim) plotEdges = PETSC_FALSE; 1003 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1004 1005 /* filter points with labelvalue != labeldefaultvalue */ 1006 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1007 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1008 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1009 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1010 if (lflg) { 1011 DMLabel lbl; 1012 1013 PetscCall(DMGetLabel(dm, lname, &lbl)); 1014 if (lbl) { 1015 PetscInt val, defval; 1016 1017 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1018 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1019 for (c = pStart; c < pEnd; c++) { 1020 PetscInt *closure = NULL; 1021 PetscInt closureSize; 1022 1023 PetscCall(DMLabelGetValue(lbl, c, &val)); 1024 if (val == defval) continue; 1025 1026 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1027 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1028 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1029 } 1030 } 1031 } 1032 1033 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1034 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1035 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1036 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1037 \\documentclass[tikz]{standalone}\n\n\ 1038 \\usepackage{pgflibraryshapes}\n\ 1039 \\usetikzlibrary{backgrounds}\n\ 1040 \\usetikzlibrary{arrows}\n\ 1041 \\begin{document}\n")); 1042 if (size > 1) { 1043 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1044 for (p = 0; p < size; ++p) { 1045 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1046 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1047 } 1048 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1049 } 1050 if (drawHasse) { 1051 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1052 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1058 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1060 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1062 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1063 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1064 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1065 } 1066 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1067 1068 /* Plot vertices */ 1069 PetscCall(VecGetArray(coordinates, &coords)); 1070 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1071 for (v = vStart; v < vEnd; ++v) { 1072 PetscInt off, dof, d; 1073 PetscBool isLabeled = PETSC_FALSE; 1074 1075 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1076 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1077 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1079 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1080 for (d = 0; d < dof; ++d) { 1081 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1082 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1083 } 1084 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1085 if (dim == 3) { 1086 PetscReal tmp = tcoords[1]; 1087 tcoords[1] = tcoords[2]; 1088 tcoords[2] = -tmp; 1089 } 1090 for (d = 0; d < dof; ++d) { 1091 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1093 } 1094 if (drawHasse) color = colors[0 % numColors]; 1095 else color = colors[rank % numColors]; 1096 for (l = 0; l < numLabels; ++l) { 1097 PetscInt val; 1098 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1099 if (val >= 0) { 1100 color = lcolors[l % numLColors]; 1101 isLabeled = PETSC_TRUE; 1102 break; 1103 } 1104 } 1105 if (drawNumbers[0]) { 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1107 } else if (drawColors[0]) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1109 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1110 } 1111 PetscCall(VecRestoreArray(coordinates, &coords)); 1112 PetscCall(PetscViewerFlush(viewer)); 1113 /* Plot edges */ 1114 if (plotEdges) { 1115 PetscCall(VecGetArray(coordinates, &coords)); 1116 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1117 for (e = eStart; e < eEnd; ++e) { 1118 const PetscInt *cone; 1119 PetscInt coneSize, offA, offB, dof, d; 1120 1121 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1122 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1123 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1124 PetscCall(DMPlexGetCone(dm, e, &cone)); 1125 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1126 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1127 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1128 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1129 for (d = 0; d < dof; ++d) { 1130 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1131 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1132 } 1133 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1134 if (dim == 3) { 1135 PetscReal tmp = tcoords[1]; 1136 tcoords[1] = tcoords[2]; 1137 tcoords[2] = -tmp; 1138 } 1139 for (d = 0; d < dof; ++d) { 1140 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1141 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1142 } 1143 if (drawHasse) color = colors[1 % numColors]; 1144 else color = colors[rank % numColors]; 1145 for (l = 0; l < numLabels; ++l) { 1146 PetscInt val; 1147 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1148 if (val >= 0) { 1149 color = lcolors[l % numLColors]; 1150 break; 1151 } 1152 } 1153 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1154 } 1155 PetscCall(VecRestoreArray(coordinates, &coords)); 1156 PetscCall(PetscViewerFlush(viewer)); 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1158 } 1159 /* Plot cells */ 1160 if (dim == 3 || !drawNumbers[1]) { 1161 for (e = eStart; e < eEnd; ++e) { 1162 const PetscInt *cone; 1163 1164 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1165 color = colors[rank % numColors]; 1166 for (l = 0; l < numLabels; ++l) { 1167 PetscInt val; 1168 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1169 if (val >= 0) { 1170 color = lcolors[l % numLColors]; 1171 break; 1172 } 1173 } 1174 PetscCall(DMPlexGetCone(dm, e, &cone)); 1175 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1176 } 1177 } else { 1178 DMPolytopeType ct; 1179 1180 /* Drawing a 2D polygon */ 1181 for (c = cStart; c < cEnd; ++c) { 1182 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1183 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1184 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1185 const PetscInt *cone; 1186 PetscInt coneSize, e; 1187 1188 PetscCall(DMPlexGetCone(dm, c, &cone)); 1189 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1190 for (e = 0; e < coneSize; ++e) { 1191 const PetscInt *econe; 1192 1193 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1194 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)); 1195 } 1196 } else { 1197 PetscInt *closure = NULL; 1198 PetscInt closureSize, Nv = 0, v; 1199 1200 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1201 for (p = 0; p < closureSize * 2; p += 2) { 1202 const PetscInt point = closure[p]; 1203 1204 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1205 } 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1207 for (v = 0; v <= Nv; ++v) { 1208 const PetscInt vertex = closure[v % Nv]; 1209 1210 if (v > 0) { 1211 if (plotEdges) { 1212 const PetscInt *edge; 1213 PetscInt endpoints[2], ne; 1214 1215 endpoints[0] = closure[v - 1]; 1216 endpoints[1] = vertex; 1217 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1218 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1219 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1220 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1221 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1222 } 1223 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1224 } 1225 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1226 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1227 } 1228 } 1229 } 1230 for (c = cStart; c < cEnd; ++c) { 1231 double ccoords[3] = {0.0, 0.0, 0.0}; 1232 PetscBool isLabeled = PETSC_FALSE; 1233 PetscScalar *cellCoords = NULL; 1234 const PetscScalar *array; 1235 PetscInt numCoords, cdim, d; 1236 PetscBool isDG; 1237 1238 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1239 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1240 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1241 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1242 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1243 for (p = 0; p < numCoords / cdim; ++p) { 1244 for (d = 0; d < cdim; ++d) { 1245 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1246 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1247 } 1248 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1249 if (cdim == 3) { 1250 PetscReal tmp = tcoords[1]; 1251 tcoords[1] = tcoords[2]; 1252 tcoords[2] = -tmp; 1253 } 1254 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1255 } 1256 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1257 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1258 for (d = 0; d < cdim; ++d) { 1259 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1260 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1261 } 1262 if (drawHasse) color = colors[depth % numColors]; 1263 else color = colors[rank % numColors]; 1264 for (l = 0; l < numLabels; ++l) { 1265 PetscInt val; 1266 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1267 if (val >= 0) { 1268 color = lcolors[l % numLColors]; 1269 isLabeled = PETSC_TRUE; 1270 break; 1271 } 1272 } 1273 if (drawNumbers[dim]) { 1274 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1275 } else if (drawColors[dim]) { 1276 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1277 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1278 } 1279 if (drawHasse) { 1280 color = colors[depth % numColors]; 1281 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1282 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1283 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1284 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1286 1287 color = colors[1 % numColors]; 1288 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1289 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1291 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1293 1294 color = colors[0 % numColors]; 1295 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1296 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1297 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1298 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1299 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1300 1301 for (p = pStart; p < pEnd; ++p) { 1302 const PetscInt *cone; 1303 PetscInt coneSize, cp; 1304 1305 PetscCall(DMPlexGetCone(dm, p, &cone)); 1306 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1307 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1308 } 1309 } 1310 PetscCall(PetscViewerFlush(viewer)); 1311 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1312 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1313 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1314 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1315 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1316 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1317 PetscCall(PetscFree3(names, colors, lcolors)); 1318 PetscCall(PetscBTDestroy(&wp)); 1319 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1320 Vec cown, acown; 1321 VecScatter sct; 1322 ISLocalToGlobalMapping g2l; 1323 IS gid, acis; 1324 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1325 MPI_Group ggroup, ngroup; 1326 PetscScalar *array, nid; 1327 const PetscInt *idxs; 1328 PetscInt *idxs2, *start, *adjacency, *work; 1329 PetscInt64 lm[3], gm[3]; 1330 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1331 PetscMPIInt d1, d2, rank; 1332 1333 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1334 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1335 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1336 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1337 #endif 1338 if (ncomm != MPI_COMM_NULL) { 1339 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1340 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1341 d1 = 0; 1342 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1343 nid = d2; 1344 PetscCallMPI(MPI_Group_free(&ggroup)); 1345 PetscCallMPI(MPI_Group_free(&ngroup)); 1346 PetscCallMPI(MPI_Comm_free(&ncomm)); 1347 } else nid = 0.0; 1348 1349 /* Get connectivity */ 1350 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1351 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1352 1353 /* filter overlapped local cells */ 1354 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1355 PetscCall(ISGetIndices(gid, &idxs)); 1356 PetscCall(ISGetLocalSize(gid, &cum)); 1357 PetscCall(PetscMalloc1(cum, &idxs2)); 1358 for (c = cStart, cum = 0; c < cEnd; c++) { 1359 if (idxs[c - cStart] < 0) continue; 1360 idxs2[cum++] = idxs[c - cStart]; 1361 } 1362 PetscCall(ISRestoreIndices(gid, &idxs)); 1363 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1364 PetscCall(ISDestroy(&gid)); 1365 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1366 1367 /* support for node-aware cell locality */ 1368 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1369 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1370 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1371 PetscCall(VecGetArray(cown, &array)); 1372 for (c = 0; c < numVertices; c++) array[c] = nid; 1373 PetscCall(VecRestoreArray(cown, &array)); 1374 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1375 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1376 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1377 PetscCall(ISDestroy(&acis)); 1378 PetscCall(VecScatterDestroy(&sct)); 1379 PetscCall(VecDestroy(&cown)); 1380 1381 /* compute edgeCut */ 1382 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1383 PetscCall(PetscMalloc1(cum, &work)); 1384 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1385 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1386 PetscCall(ISDestroy(&gid)); 1387 PetscCall(VecGetArray(acown, &array)); 1388 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1389 PetscInt totl; 1390 1391 totl = start[c + 1] - start[c]; 1392 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1393 for (i = 0; i < totl; i++) { 1394 if (work[i] < 0) { 1395 ect += 1; 1396 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1397 } 1398 } 1399 } 1400 PetscCall(PetscFree(work)); 1401 PetscCall(VecRestoreArray(acown, &array)); 1402 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1403 lm[1] = -numVertices; 1404 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1406 lm[0] = ect; /* edgeCut */ 1407 lm[1] = ectn; /* node-aware edgeCut */ 1408 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1409 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1410 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1411 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1412 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1413 #else 1414 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1415 #endif 1416 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1417 PetscCall(PetscFree(start)); 1418 PetscCall(PetscFree(adjacency)); 1419 PetscCall(VecDestroy(&acown)); 1420 } else { 1421 const char *name; 1422 PetscInt *sizes, *hybsizes, *ghostsizes; 1423 PetscInt locDepth, depth, cellHeight, dim, d; 1424 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1425 PetscInt numLabels, l, maxSize = 17; 1426 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1427 MPI_Comm comm; 1428 PetscMPIInt size, rank; 1429 1430 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1431 PetscCallMPI(MPI_Comm_size(comm, &size)); 1432 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1433 PetscCall(DMGetDimension(dm, &dim)); 1434 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1435 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1436 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1437 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1438 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1439 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1440 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1441 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1442 gcNum = gcEnd - gcStart; 1443 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1444 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1445 for (d = 0; d <= depth; d++) { 1446 PetscInt Nc[2] = {0, 0}, ict; 1447 1448 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1449 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1450 ict = ct0; 1451 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1452 ct0 = (DMPolytopeType)ict; 1453 for (p = pStart; p < pEnd; ++p) { 1454 DMPolytopeType ct; 1455 1456 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1457 if (ct == ct0) ++Nc[0]; 1458 else ++Nc[1]; 1459 } 1460 if (size < maxSize) { 1461 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1462 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1463 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1464 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1465 for (p = 0; p < size; ++p) { 1466 if (rank == 0) { 1467 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1468 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1469 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1470 } 1471 } 1472 } else { 1473 PetscInt locMinMax[2]; 1474 1475 locMinMax[0] = Nc[0] + Nc[1]; 1476 locMinMax[1] = Nc[0] + Nc[1]; 1477 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1478 locMinMax[0] = Nc[1]; 1479 locMinMax[1] = Nc[1]; 1480 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1481 if (d == depth) { 1482 locMinMax[0] = gcNum; 1483 locMinMax[1] = gcNum; 1484 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1485 } 1486 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1488 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1489 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1490 } 1491 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1492 } 1493 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1494 { 1495 const PetscReal *maxCell; 1496 const PetscReal *L; 1497 PetscBool localized; 1498 1499 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1500 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1501 if (L || localized) { 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1503 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1504 if (L) { 1505 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1506 for (d = 0; d < dim; ++d) { 1507 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1509 } 1510 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1511 } 1512 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1513 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1514 } 1515 } 1516 PetscCall(DMGetNumLabels(dm, &numLabels)); 1517 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1518 for (l = 0; l < numLabels; ++l) { 1519 DMLabel label; 1520 const char *name; 1521 IS valueIS; 1522 const PetscInt *values; 1523 PetscInt numValues, v; 1524 1525 PetscCall(DMGetLabelName(dm, l, &name)); 1526 PetscCall(DMGetLabel(dm, name, &label)); 1527 PetscCall(DMLabelGetNumValues(label, &numValues)); 1528 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1529 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1530 PetscCall(ISGetIndices(valueIS, &values)); 1531 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1532 for (v = 0; v < numValues; ++v) { 1533 PetscInt size; 1534 1535 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1536 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1537 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1538 } 1539 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1540 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1541 PetscCall(ISRestoreIndices(valueIS, &values)); 1542 PetscCall(ISDestroy(&valueIS)); 1543 } 1544 { 1545 char **labelNames; 1546 PetscInt Nl = numLabels; 1547 PetscBool flg; 1548 1549 PetscCall(PetscMalloc1(Nl, &labelNames)); 1550 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1551 for (l = 0; l < Nl; ++l) { 1552 DMLabel label; 1553 1554 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1555 if (flg) { 1556 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1557 PetscCall(DMLabelView(label, viewer)); 1558 } 1559 PetscCall(PetscFree(labelNames[l])); 1560 } 1561 PetscCall(PetscFree(labelNames)); 1562 } 1563 /* If no fields are specified, people do not want to see adjacency */ 1564 if (dm->Nf) { 1565 PetscInt f; 1566 1567 for (f = 0; f < dm->Nf; ++f) { 1568 const char *name; 1569 1570 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1571 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1572 PetscCall(PetscViewerASCIIPushTab(viewer)); 1573 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1574 if (dm->fields[f].adjacency[0]) { 1575 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1576 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1577 } else { 1578 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1579 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1580 } 1581 PetscCall(PetscViewerASCIIPopTab(viewer)); 1582 } 1583 } 1584 PetscCall(DMGetCoarseDM(dm, &cdm)); 1585 if (cdm) { 1586 PetscCall(PetscViewerASCIIPushTab(viewer)); 1587 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1588 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1589 PetscCall(PetscViewerASCIIPopTab(viewer)); 1590 } 1591 } 1592 PetscFunctionReturn(PETSC_SUCCESS); 1593 } 1594 1595 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1596 { 1597 DMPolytopeType ct; 1598 PetscMPIInt rank; 1599 PetscInt cdim; 1600 1601 PetscFunctionBegin; 1602 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1603 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1604 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1605 switch (ct) { 1606 case DM_POLYTOPE_SEGMENT: 1607 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1608 switch (cdim) { 1609 case 1: { 1610 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1611 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1612 1613 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1614 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1615 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1616 } break; 1617 case 2: { 1618 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1619 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1620 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1621 1622 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1623 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)); 1624 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)); 1625 } break; 1626 default: 1627 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1628 } 1629 break; 1630 case DM_POLYTOPE_TRIANGLE: 1631 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)); 1632 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1633 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1634 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1635 break; 1636 case DM_POLYTOPE_QUADRILATERAL: 1637 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)); 1638 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)); 1639 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1640 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1641 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1642 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1643 break; 1644 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1645 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)); 1646 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1647 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1648 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1649 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1650 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1651 break; 1652 case DM_POLYTOPE_FV_GHOST: 1653 break; 1654 default: 1655 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1656 } 1657 PetscFunctionReturn(PETSC_SUCCESS); 1658 } 1659 1660 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1661 { 1662 DMPolytopeType ct; 1663 PetscReal centroid[2] = {0., 0.}; 1664 PetscMPIInt rank; 1665 PetscInt fillColor, v, e, d; 1666 1667 PetscFunctionBegin; 1668 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1669 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1670 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1671 switch (ct) { 1672 case DM_POLYTOPE_TRIANGLE: { 1673 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1674 1675 for (v = 0; v < 3; ++v) { 1676 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1677 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1678 } 1679 for (e = 0; e < 3; ++e) { 1680 refCoords[0] = refVertices[e * 2 + 0]; 1681 refCoords[1] = refVertices[e * 2 + 1]; 1682 for (d = 1; d <= edgeDiv; ++d) { 1683 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1684 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1685 } 1686 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1687 for (d = 0; d < edgeDiv; ++d) { 1688 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)); 1689 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1690 } 1691 } 1692 } break; 1693 default: 1694 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1700 { 1701 PetscDraw draw; 1702 DM cdm; 1703 PetscSection coordSection; 1704 Vec coordinates; 1705 const PetscScalar *coords; 1706 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1707 PetscReal *refCoords, *edgeCoords; 1708 PetscBool isnull, drawAffine = PETSC_TRUE; 1709 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1710 1711 PetscFunctionBegin; 1712 PetscCall(DMGetCoordinateDim(dm, &dim)); 1713 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1714 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1715 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1716 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1717 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1718 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1719 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1720 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1721 1722 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1723 PetscCall(PetscDrawIsNull(draw, &isnull)); 1724 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1725 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1726 1727 PetscCall(VecGetLocalSize(coordinates, &N)); 1728 PetscCall(VecGetArrayRead(coordinates, &coords)); 1729 for (c = 0; c < N; c += dim) { 1730 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1731 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1732 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1733 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1734 } 1735 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1736 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1737 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1738 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1739 PetscCall(PetscDrawClear(draw)); 1740 1741 for (c = cStart; c < cEnd; ++c) { 1742 PetscScalar *coords = NULL; 1743 PetscInt numCoords; 1744 1745 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1746 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1747 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1748 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1749 } 1750 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1751 PetscCall(PetscDrawFlush(draw)); 1752 PetscCall(PetscDrawPause(draw)); 1753 PetscCall(PetscDrawSave(draw)); 1754 PetscFunctionReturn(PETSC_SUCCESS); 1755 } 1756 1757 #if defined(PETSC_HAVE_EXODUSII) 1758 #include <exodusII.h> 1759 #include <petscviewerexodusii.h> 1760 #endif 1761 1762 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1763 { 1764 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1765 char name[PETSC_MAX_PATH_LEN]; 1766 1767 PetscFunctionBegin; 1768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1769 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1770 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1771 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1776 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1777 if (iascii) { 1778 PetscViewerFormat format; 1779 PetscCall(PetscViewerGetFormat(viewer, &format)); 1780 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1781 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1782 } else if (ishdf5) { 1783 #if defined(PETSC_HAVE_HDF5) 1784 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1785 #else 1786 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1787 #endif 1788 } else if (isvtk) { 1789 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1790 } else if (isdraw) { 1791 PetscCall(DMPlexView_Draw(dm, viewer)); 1792 } else if (isglvis) { 1793 PetscCall(DMPlexView_GLVis(dm, viewer)); 1794 #if defined(PETSC_HAVE_EXODUSII) 1795 } else if (isexodus) { 1796 /* 1797 exodusII requires that all sets be part of exactly one cell set. 1798 If the dm does not have a "Cell Sets" label defined, we create one 1799 with ID 1, containing all cells. 1800 Note that if the Cell Sets label is defined but does not cover all cells, 1801 we may still have a problem. This should probably be checked here or in the viewer; 1802 */ 1803 PetscInt numCS; 1804 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1805 if (!numCS) { 1806 PetscInt cStart, cEnd, c; 1807 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1808 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1809 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1810 } 1811 PetscCall(DMView_PlexExodusII(dm, viewer)); 1812 #endif 1813 #if defined(PETSC_HAVE_CGNS) 1814 } else if (iscgns) { 1815 PetscCall(DMView_PlexCGNS(dm, viewer)); 1816 #endif 1817 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1818 /* Optionally view the partition */ 1819 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1820 if (flg) { 1821 Vec ranks; 1822 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1823 PetscCall(VecView(ranks, viewer)); 1824 PetscCall(VecDestroy(&ranks)); 1825 } 1826 /* Optionally view a label */ 1827 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1828 if (flg) { 1829 DMLabel label; 1830 Vec val; 1831 1832 PetscCall(DMGetLabel(dm, name, &label)); 1833 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1834 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1835 PetscCall(VecView(val, viewer)); 1836 PetscCall(VecDestroy(&val)); 1837 } 1838 PetscFunctionReturn(PETSC_SUCCESS); 1839 } 1840 1841 /*@ 1842 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1843 1844 Collective on dm 1845 1846 Input Parameters: 1847 + dm - The `DM` whose topology is to be saved 1848 - viewer - The `PetscViewer` to save it in 1849 1850 Level: advanced 1851 1852 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1853 @*/ 1854 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1855 { 1856 PetscBool ishdf5; 1857 1858 PetscFunctionBegin; 1859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1860 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1861 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1862 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1863 if (ishdf5) { 1864 #if defined(PETSC_HAVE_HDF5) 1865 PetscViewerFormat format; 1866 PetscCall(PetscViewerGetFormat(viewer, &format)); 1867 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1868 IS globalPointNumbering; 1869 1870 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1871 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1872 PetscCall(ISDestroy(&globalPointNumbering)); 1873 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1874 #else 1875 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1876 #endif 1877 } 1878 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1879 PetscFunctionReturn(PETSC_SUCCESS); 1880 } 1881 1882 /*@ 1883 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1884 1885 Collective on dm 1886 1887 Input Parameters: 1888 + dm - The `DM` whose coordinates are to be saved 1889 - viewer - The `PetscViewer` for saving 1890 1891 Level: advanced 1892 1893 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1894 @*/ 1895 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1896 { 1897 PetscBool ishdf5; 1898 1899 PetscFunctionBegin; 1900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1901 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1902 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1903 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1904 if (ishdf5) { 1905 #if defined(PETSC_HAVE_HDF5) 1906 PetscViewerFormat format; 1907 PetscCall(PetscViewerGetFormat(viewer, &format)); 1908 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1909 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1910 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1911 #else 1912 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1913 #endif 1914 } 1915 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1916 PetscFunctionReturn(PETSC_SUCCESS); 1917 } 1918 1919 /*@ 1920 DMPlexLabelsView - Saves `DMPLEX` labels into a file 1921 1922 Collective on dm 1923 1924 Input Parameters: 1925 + dm - The `DM` whose labels are to be saved 1926 - viewer - The `PetscViewer` for saving 1927 1928 Level: advanced 1929 1930 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 1931 @*/ 1932 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1933 { 1934 PetscBool ishdf5; 1935 1936 PetscFunctionBegin; 1937 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1938 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1939 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1940 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1941 if (ishdf5) { 1942 #if defined(PETSC_HAVE_HDF5) 1943 IS globalPointNumbering; 1944 PetscViewerFormat format; 1945 1946 PetscCall(PetscViewerGetFormat(viewer, &format)); 1947 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1948 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1949 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1950 PetscCall(ISDestroy(&globalPointNumbering)); 1951 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1952 #else 1953 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1954 #endif 1955 } 1956 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1957 PetscFunctionReturn(PETSC_SUCCESS); 1958 } 1959 1960 /*@ 1961 DMPlexSectionView - Saves a section associated with a `DMPLEX` 1962 1963 Collective on dm 1964 1965 Input Parameters: 1966 + dm - The `DM` that contains the topology on which the section to be saved is defined 1967 . viewer - The `PetscViewer` for saving 1968 - sectiondm - The `DM` that contains the section to be saved 1969 1970 Level: advanced 1971 1972 Notes: 1973 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. 1974 1975 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. 1976 1977 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 1978 @*/ 1979 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1980 { 1981 PetscBool ishdf5; 1982 1983 PetscFunctionBegin; 1984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1985 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1986 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1987 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1988 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1989 if (ishdf5) { 1990 #if defined(PETSC_HAVE_HDF5) 1991 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1992 #else 1993 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1994 #endif 1995 } 1996 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1997 PetscFunctionReturn(PETSC_SUCCESS); 1998 } 1999 2000 /*@ 2001 DMPlexGlobalVectorView - Saves a global vector 2002 2003 Collective on dm 2004 2005 Input Parameters: 2006 + dm - The `DM` that represents the topology 2007 . viewer - The `PetscViewer` to save data with 2008 . sectiondm - The `DM` that contains the global section on which vec is defined 2009 - vec - The global vector to be saved 2010 2011 Level: advanced 2012 2013 Notes: 2014 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. 2015 2016 Typical calling sequence: 2017 .vb 2018 DMCreate(PETSC_COMM_WORLD, &dm); 2019 DMSetType(dm, DMPLEX); 2020 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2021 DMClone(dm, §iondm); 2022 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2023 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2024 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2025 PetscSectionSetChart(section, pStart, pEnd); 2026 PetscSectionSetUp(section); 2027 DMSetLocalSection(sectiondm, section); 2028 PetscSectionDestroy(§ion); 2029 DMGetGlobalVector(sectiondm, &vec); 2030 PetscObjectSetName((PetscObject)vec, "vec_name"); 2031 DMPlexTopologyView(dm, viewer); 2032 DMPlexSectionView(dm, viewer, sectiondm); 2033 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2034 DMRestoreGlobalVector(sectiondm, &vec); 2035 DMDestroy(§iondm); 2036 DMDestroy(&dm); 2037 .ve 2038 2039 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2040 @*/ 2041 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2042 { 2043 PetscBool ishdf5; 2044 2045 PetscFunctionBegin; 2046 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2047 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2048 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2049 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2050 /* Check consistency */ 2051 { 2052 PetscSection section; 2053 PetscBool includesConstraints; 2054 PetscInt m, m1; 2055 2056 PetscCall(VecGetLocalSize(vec, &m1)); 2057 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2058 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2059 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2060 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2061 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2062 } 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2064 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2065 if (ishdf5) { 2066 #if defined(PETSC_HAVE_HDF5) 2067 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2068 #else 2069 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2070 #endif 2071 } 2072 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2073 PetscFunctionReturn(PETSC_SUCCESS); 2074 } 2075 2076 /*@ 2077 DMPlexLocalVectorView - Saves a local vector 2078 2079 Collective on dm 2080 2081 Input Parameters: 2082 + dm - The `DM` that represents the topology 2083 . viewer - The `PetscViewer` to save data with 2084 . sectiondm - The `DM` that contains the local section on which vec is defined; may be the same as dm 2085 - vec - The local vector to be saved 2086 2087 Level: advanced 2088 2089 Note: 2090 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. 2091 2092 Typical calling sequence: 2093 .vb 2094 DMCreate(PETSC_COMM_WORLD, &dm); 2095 DMSetType(dm, DMPLEX); 2096 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2097 DMClone(dm, §iondm); 2098 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2099 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2100 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2101 PetscSectionSetChart(section, pStart, pEnd); 2102 PetscSectionSetUp(section); 2103 DMSetLocalSection(sectiondm, section); 2104 DMGetLocalVector(sectiondm, &vec); 2105 PetscObjectSetName((PetscObject)vec, "vec_name"); 2106 DMPlexTopologyView(dm, viewer); 2107 DMPlexSectionView(dm, viewer, sectiondm); 2108 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2109 DMRestoreLocalVector(sectiondm, &vec); 2110 DMDestroy(§iondm); 2111 DMDestroy(&dm); 2112 .ve 2113 2114 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2115 @*/ 2116 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2117 { 2118 PetscBool ishdf5; 2119 2120 PetscFunctionBegin; 2121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2122 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2123 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2124 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2125 /* Check consistency */ 2126 { 2127 PetscSection section; 2128 PetscBool includesConstraints; 2129 PetscInt m, m1; 2130 2131 PetscCall(VecGetLocalSize(vec, &m1)); 2132 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2133 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2134 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2135 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2136 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2137 } 2138 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2139 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2140 if (ishdf5) { 2141 #if defined(PETSC_HAVE_HDF5) 2142 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2143 #else 2144 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2145 #endif 2146 } 2147 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2148 PetscFunctionReturn(PETSC_SUCCESS); 2149 } 2150 2151 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2152 { 2153 PetscBool ishdf5; 2154 2155 PetscFunctionBegin; 2156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2157 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2158 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2159 if (ishdf5) { 2160 #if defined(PETSC_HAVE_HDF5) 2161 PetscViewerFormat format; 2162 PetscCall(PetscViewerGetFormat(viewer, &format)); 2163 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2164 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2165 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2166 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2167 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2168 PetscFunctionReturn(PETSC_SUCCESS); 2169 #else 2170 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2171 #endif 2172 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2173 } 2174 2175 /*@ 2176 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2177 2178 Collective on dm 2179 2180 Input Parameters: 2181 + dm - The `DM` into which the topology is loaded 2182 - viewer - The `PetscViewer` for the saved topology 2183 2184 Output Parameters: 2185 . 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 2186 2187 Level: advanced 2188 2189 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2190 `PetscViewer`, `PetscSF` 2191 @*/ 2192 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2193 { 2194 PetscBool ishdf5; 2195 2196 PetscFunctionBegin; 2197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2198 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2199 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2200 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2201 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2202 if (ishdf5) { 2203 #if defined(PETSC_HAVE_HDF5) 2204 PetscViewerFormat format; 2205 PetscCall(PetscViewerGetFormat(viewer, &format)); 2206 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2207 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2208 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2209 #else 2210 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2211 #endif 2212 } 2213 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2214 PetscFunctionReturn(PETSC_SUCCESS); 2215 } 2216 2217 /*@ 2218 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2219 2220 Collective on dm 2221 2222 Input Parameters: 2223 + dm - The `DM` into which the coordinates are loaded 2224 . viewer - The `PetscViewer` for the saved coordinates 2225 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2226 2227 Level: advanced 2228 2229 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2230 `PetscSF`, `PetscViewer` 2231 @*/ 2232 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2233 { 2234 PetscBool ishdf5; 2235 2236 PetscFunctionBegin; 2237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2238 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2239 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2240 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2241 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2242 if (ishdf5) { 2243 #if defined(PETSC_HAVE_HDF5) 2244 PetscViewerFormat format; 2245 PetscCall(PetscViewerGetFormat(viewer, &format)); 2246 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2247 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2248 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2249 #else 2250 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2251 #endif 2252 } 2253 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2254 PetscFunctionReturn(PETSC_SUCCESS); 2255 } 2256 2257 /*@ 2258 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2259 2260 Collective on dm 2261 2262 Input Parameters: 2263 + dm - The `DM` into which the labels are loaded 2264 . viewer - The `PetscViewer` for the saved labels 2265 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2266 2267 Level: advanced 2268 2269 Note: 2270 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2271 2272 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2273 `PetscSF`, `PetscViewer` 2274 @*/ 2275 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2276 { 2277 PetscBool ishdf5; 2278 2279 PetscFunctionBegin; 2280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2281 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2282 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2284 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2285 if (ishdf5) { 2286 #if defined(PETSC_HAVE_HDF5) 2287 PetscViewerFormat format; 2288 2289 PetscCall(PetscViewerGetFormat(viewer, &format)); 2290 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2291 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2292 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2293 #else 2294 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2295 #endif 2296 } 2297 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2298 PetscFunctionReturn(PETSC_SUCCESS); 2299 } 2300 2301 /*@ 2302 DMPlexSectionLoad - Loads section into a `DMPLEX` 2303 2304 Collective on dm 2305 2306 Input Parameters: 2307 + dm - The `DM` that represents the topology 2308 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2309 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2310 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2311 2312 Output Parameters 2313 + 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) 2314 - 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) 2315 2316 Level: advanced 2317 2318 Notes: 2319 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. 2320 2321 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. 2322 2323 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. 2324 2325 Example using 2 processes: 2326 .vb 2327 NX (number of points on dm): 4 2328 sectionA : the on-disk section 2329 vecA : a vector associated with sectionA 2330 sectionB : sectiondm's local section constructed in this function 2331 vecB (local) : a vector associated with sectiondm's local section 2332 vecB (global) : a vector associated with sectiondm's global section 2333 2334 rank 0 rank 1 2335 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2336 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2337 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2338 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2339 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2340 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2341 sectionB->atlasDof : 1 0 1 | 1 3 2342 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2343 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2344 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2345 .ve 2346 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2347 2348 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2349 @*/ 2350 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2351 { 2352 PetscBool ishdf5; 2353 2354 PetscFunctionBegin; 2355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2356 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2357 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2358 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2359 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2360 if (localDofSF) PetscValidPointer(localDofSF, 6); 2361 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2362 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2363 if (ishdf5) { 2364 #if defined(PETSC_HAVE_HDF5) 2365 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2366 #else 2367 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2368 #endif 2369 } 2370 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2371 PetscFunctionReturn(PETSC_SUCCESS); 2372 } 2373 2374 /*@ 2375 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2376 2377 Collective on dm 2378 2379 Input Parameters: 2380 + dm - The `DM` that represents the topology 2381 . viewer - The `PetscViewer` that represents the on-disk vector data 2382 . sectiondm - The `DM` that contains the global section on which vec is defined 2383 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2384 - vec - The global vector to set values of 2385 2386 Level: advanced 2387 2388 Notes: 2389 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. 2390 2391 Typical calling sequence: 2392 .vb 2393 DMCreate(PETSC_COMM_WORLD, &dm); 2394 DMSetType(dm, DMPLEX); 2395 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2396 DMPlexTopologyLoad(dm, viewer, &sfX); 2397 DMClone(dm, §iondm); 2398 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2399 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2400 DMGetGlobalVector(sectiondm, &vec); 2401 PetscObjectSetName((PetscObject)vec, "vec_name"); 2402 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2403 DMRestoreGlobalVector(sectiondm, &vec); 2404 PetscSFDestroy(&gsf); 2405 PetscSFDestroy(&sfX); 2406 DMDestroy(§iondm); 2407 DMDestroy(&dm); 2408 .ve 2409 2410 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2411 `PetscSF`, `PetscViewer` 2412 @*/ 2413 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2414 { 2415 PetscBool ishdf5; 2416 2417 PetscFunctionBegin; 2418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2419 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2420 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2421 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2422 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2423 /* Check consistency */ 2424 { 2425 PetscSection section; 2426 PetscBool includesConstraints; 2427 PetscInt m, m1; 2428 2429 PetscCall(VecGetLocalSize(vec, &m1)); 2430 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2431 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2432 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2433 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2434 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2435 } 2436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2437 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2438 if (ishdf5) { 2439 #if defined(PETSC_HAVE_HDF5) 2440 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2441 #else 2442 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2443 #endif 2444 } 2445 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2446 PetscFunctionReturn(PETSC_SUCCESS); 2447 } 2448 2449 /*@ 2450 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2451 2452 Collective on dm 2453 2454 Input Parameters: 2455 + dm - The `DM` that represents the topology 2456 . viewer - The `PetscViewer` that represents the on-disk vector data 2457 . sectiondm - The `DM` that contains the local section on which vec is defined 2458 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2459 - vec - The local vector to set values of 2460 2461 Level: advanced 2462 2463 Notes: 2464 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. 2465 2466 Typical calling sequence: 2467 .vb 2468 DMCreate(PETSC_COMM_WORLD, &dm); 2469 DMSetType(dm, DMPLEX); 2470 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2471 DMPlexTopologyLoad(dm, viewer, &sfX); 2472 DMClone(dm, §iondm); 2473 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2474 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2475 DMGetLocalVector(sectiondm, &vec); 2476 PetscObjectSetName((PetscObject)vec, "vec_name"); 2477 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2478 DMRestoreLocalVector(sectiondm, &vec); 2479 PetscSFDestroy(&lsf); 2480 PetscSFDestroy(&sfX); 2481 DMDestroy(§iondm); 2482 DMDestroy(&dm); 2483 .ve 2484 2485 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2486 `PetscSF`, `PetscViewer` 2487 @*/ 2488 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2489 { 2490 PetscBool ishdf5; 2491 2492 PetscFunctionBegin; 2493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2494 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2495 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2496 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2497 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2498 /* Check consistency */ 2499 { 2500 PetscSection section; 2501 PetscBool includesConstraints; 2502 PetscInt m, m1; 2503 2504 PetscCall(VecGetLocalSize(vec, &m1)); 2505 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2506 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2507 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2508 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2509 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2510 } 2511 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2512 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2513 if (ishdf5) { 2514 #if defined(PETSC_HAVE_HDF5) 2515 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2516 #else 2517 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2518 #endif 2519 } 2520 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2521 PetscFunctionReturn(PETSC_SUCCESS); 2522 } 2523 2524 PetscErrorCode DMDestroy_Plex(DM dm) 2525 { 2526 DM_Plex *mesh = (DM_Plex *)dm->data; 2527 2528 PetscFunctionBegin; 2529 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2530 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2531 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2532 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2533 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2534 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2535 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2536 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2537 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2538 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2539 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2540 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2541 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2542 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2543 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2544 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2545 PetscCall(PetscFree(mesh->cones)); 2546 PetscCall(PetscFree(mesh->coneOrientations)); 2547 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2548 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2549 PetscCall(PetscFree(mesh->supports)); 2550 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2551 PetscCall(PetscFree(mesh->facesTmp)); 2552 PetscCall(PetscFree(mesh->tetgenOpts)); 2553 PetscCall(PetscFree(mesh->triangleOpts)); 2554 PetscCall(PetscFree(mesh->transformType)); 2555 PetscCall(PetscFree(mesh->distributionName)); 2556 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2557 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2558 PetscCall(ISDestroy(&mesh->subpointIS)); 2559 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2560 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2561 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2562 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2563 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2564 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2565 PetscCall(ISDestroy(&mesh->anchorIS)); 2566 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2567 PetscCall(PetscFree(mesh->parents)); 2568 PetscCall(PetscFree(mesh->childIDs)); 2569 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2570 PetscCall(PetscFree(mesh->children)); 2571 PetscCall(DMDestroy(&mesh->referenceTree)); 2572 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2573 PetscCall(PetscFree(mesh->neighbors)); 2574 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2575 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2576 PetscCall(PetscFree(mesh)); 2577 PetscFunctionReturn(PETSC_SUCCESS); 2578 } 2579 2580 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2581 { 2582 PetscSection sectionGlobal; 2583 PetscInt bs = -1, mbs; 2584 PetscInt localSize, localStart = 0; 2585 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2586 MatType mtype; 2587 ISLocalToGlobalMapping ltog; 2588 2589 PetscFunctionBegin; 2590 PetscCall(MatInitializePackage()); 2591 mtype = dm->mattype; 2592 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2593 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2594 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2595 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2596 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2597 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2598 PetscCall(MatSetType(*J, mtype)); 2599 PetscCall(MatSetFromOptions(*J)); 2600 PetscCall(MatGetBlockSize(*J, &mbs)); 2601 if (mbs > 1) bs = mbs; 2602 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2603 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2604 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2605 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2606 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2607 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2608 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2609 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2610 if (!isShell) { 2611 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2612 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2613 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2614 2615 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2616 2617 PetscCall(PetscCalloc1(localSize, &pblocks)); 2618 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2619 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2620 for (p = pStart; p < pEnd; ++p) { 2621 switch (dm->blocking_type) { 2622 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2623 PetscInt bdof, offset; 2624 2625 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2626 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2627 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2628 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2629 dof = dof < 0 ? -(dof + 1) : dof; 2630 bdof = cdof && (dof - cdof) ? 1 : dof; 2631 if (dof) { 2632 if (bs < 0) { 2633 bs = bdof; 2634 } else if (bs != bdof) { 2635 bs = 1; 2636 } 2637 } 2638 } break; 2639 case DM_BLOCKING_FIELD_NODE: { 2640 for (PetscInt field = 0; field < num_fields; field++) { 2641 PetscInt num_comp, bdof, offset; 2642 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2643 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2644 if (dof < 0) continue; 2645 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2646 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2647 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2648 PetscInt num_nodes = dof / num_comp; 2649 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2650 // Handle possibly constant block size (unlikely) 2651 bdof = cdof && (dof - cdof) ? 1 : dof; 2652 if (dof) { 2653 if (bs < 0) { 2654 bs = bdof; 2655 } else if (bs != bdof) { 2656 bs = 1; 2657 } 2658 } 2659 } 2660 } break; 2661 } 2662 } 2663 /* Must have same blocksize on all procs (some might have no points) */ 2664 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2665 bsLocal[1] = bs; 2666 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2667 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2668 else bs = bsMinMax[0]; 2669 bs = PetscMax(1, bs); 2670 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2671 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2672 PetscCall(MatSetBlockSize(*J, bs)); 2673 PetscCall(MatSetUp(*J)); 2674 } else { 2675 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2676 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2677 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2678 } 2679 { // Consolidate blocks 2680 PetscInt nblocks = 0; 2681 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2682 if (pblocks[i] == 0) continue; 2683 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2684 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]); 2685 } 2686 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2687 } 2688 PetscCall(PetscFree(pblocks)); 2689 } 2690 PetscCall(MatSetDM(*J, dm)); 2691 PetscFunctionReturn(PETSC_SUCCESS); 2692 } 2693 2694 /*@ 2695 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2696 2697 Not Collective 2698 2699 Input Parameter: 2700 . mesh - The `DMPLEX` 2701 2702 Output Parameters: 2703 . subsection - The subdomain section 2704 2705 Level: developer 2706 2707 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSection` 2708 @*/ 2709 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2710 { 2711 DM_Plex *mesh = (DM_Plex *)dm->data; 2712 2713 PetscFunctionBegin; 2714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2715 if (!mesh->subdomainSection) { 2716 PetscSection section; 2717 PetscSF sf; 2718 2719 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2720 PetscCall(DMGetLocalSection(dm, §ion)); 2721 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2722 PetscCall(PetscSFDestroy(&sf)); 2723 } 2724 *subsection = mesh->subdomainSection; 2725 PetscFunctionReturn(PETSC_SUCCESS); 2726 } 2727 2728 /*@ 2729 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2730 2731 Not Collective 2732 2733 Input Parameter: 2734 . mesh - The `DMPLEX` 2735 2736 Output Parameters: 2737 + pStart - The first mesh point 2738 - pEnd - The upper bound for mesh points 2739 2740 Level: beginner 2741 2742 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2743 @*/ 2744 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2745 { 2746 DM_Plex *mesh = (DM_Plex *)dm->data; 2747 2748 PetscFunctionBegin; 2749 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2750 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2751 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2752 PetscFunctionReturn(PETSC_SUCCESS); 2753 } 2754 2755 /*@ 2756 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2757 2758 Not Collective 2759 2760 Input Parameters: 2761 + mesh - The `DMPLEX` 2762 . pStart - The first mesh point 2763 - pEnd - The upper bound for mesh points 2764 2765 Level: beginner 2766 2767 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2768 @*/ 2769 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2770 { 2771 DM_Plex *mesh = (DM_Plex *)dm->data; 2772 2773 PetscFunctionBegin; 2774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2775 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2776 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2777 PetscFunctionReturn(PETSC_SUCCESS); 2778 } 2779 2780 /*@ 2781 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2782 2783 Not Collective 2784 2785 Input Parameters: 2786 + mesh - The `DMPLEX` 2787 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2788 2789 Output Parameter: 2790 . size - The cone size for point p 2791 2792 Level: beginner 2793 2794 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2795 @*/ 2796 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2797 { 2798 DM_Plex *mesh = (DM_Plex *)dm->data; 2799 2800 PetscFunctionBegin; 2801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2802 PetscValidIntPointer(size, 3); 2803 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2804 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2805 PetscFunctionReturn(PETSC_SUCCESS); 2806 } 2807 2808 /*@ 2809 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2810 2811 Not Collective 2812 2813 Input Parameters: 2814 + mesh - The `DMPLEX` 2815 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2816 - size - The cone size for point p 2817 2818 Level: beginner 2819 2820 Note: 2821 This should be called after `DMPlexSetChart()`. 2822 2823 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2824 @*/ 2825 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2826 { 2827 DM_Plex *mesh = (DM_Plex *)dm->data; 2828 2829 PetscFunctionBegin; 2830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2831 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2832 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2833 PetscFunctionReturn(PETSC_SUCCESS); 2834 } 2835 2836 /*@C 2837 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2838 2839 Not Collective 2840 2841 Input Parameters: 2842 + dm - The `DMPLEX` 2843 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2844 2845 Output Parameter: 2846 . cone - An array of points which are on the in-edges for point p 2847 2848 Level: beginner 2849 2850 Fortran Note: 2851 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2852 `DMPlexRestoreCone()` is not needed/available in C. 2853 2854 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2855 @*/ 2856 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2857 { 2858 DM_Plex *mesh = (DM_Plex *)dm->data; 2859 PetscInt off; 2860 2861 PetscFunctionBegin; 2862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2863 PetscValidPointer(cone, 3); 2864 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2865 *cone = &mesh->cones[off]; 2866 PetscFunctionReturn(PETSC_SUCCESS); 2867 } 2868 2869 /*@C 2870 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2871 2872 Not Collective 2873 2874 Input Parameters: 2875 + dm - The `DMPLEX` 2876 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2877 2878 Output Parameters: 2879 + pConesSection - `PetscSection` describing the layout of pCones 2880 - pCones - An array of points which are on the in-edges for the point set p 2881 2882 Level: intermediate 2883 2884 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2885 @*/ 2886 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2887 { 2888 PetscSection cs, newcs; 2889 PetscInt *cones; 2890 PetscInt *newarr = NULL; 2891 PetscInt n; 2892 2893 PetscFunctionBegin; 2894 PetscCall(DMPlexGetCones(dm, &cones)); 2895 PetscCall(DMPlexGetConeSection(dm, &cs)); 2896 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2897 if (pConesSection) *pConesSection = newcs; 2898 if (pCones) { 2899 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2900 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2901 } 2902 PetscFunctionReturn(PETSC_SUCCESS); 2903 } 2904 2905 /*@ 2906 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2907 2908 Not Collective 2909 2910 Input Parameters: 2911 + dm - The `DMPLEX` 2912 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2913 2914 Output Parameter: 2915 . expandedPoints - An array of vertices recursively expanded from input points 2916 2917 Level: advanced 2918 2919 Notes: 2920 Like `DMPlexGetConeRecursive()` but returns only the 0-depth IS (i.e. vertices only) and no sections. 2921 2922 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 2923 2924 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 2925 `DMPlexGetDepth()`, `IS` 2926 @*/ 2927 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2928 { 2929 IS *expandedPointsAll; 2930 PetscInt depth; 2931 2932 PetscFunctionBegin; 2933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2934 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2935 PetscValidPointer(expandedPoints, 3); 2936 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2937 *expandedPoints = expandedPointsAll[0]; 2938 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2939 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2940 PetscFunctionReturn(PETSC_SUCCESS); 2941 } 2942 2943 /*@ 2944 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). 2945 2946 Not Collective 2947 2948 Input Parameters: 2949 + dm - The `DMPLEX` 2950 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2951 2952 Output Parameters: 2953 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 2954 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2955 - sections - (optional) An array of sections which describe mappings from points to their cone points 2956 2957 Level: advanced 2958 2959 Notes: 2960 Like `DMPlexGetConeTuple()` but recursive. 2961 2962 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. 2963 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2964 2965 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: 2966 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2967 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2968 2969 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 2970 `DMPlexGetDepth()`, `PetscSection`, `IS` 2971 @*/ 2972 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2973 { 2974 const PetscInt *arr0 = NULL, *cone = NULL; 2975 PetscInt *arr = NULL, *newarr = NULL; 2976 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2977 IS *expandedPoints_; 2978 PetscSection *sections_; 2979 2980 PetscFunctionBegin; 2981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2982 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2983 if (depth) PetscValidIntPointer(depth, 3); 2984 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2985 if (sections) PetscValidPointer(sections, 5); 2986 PetscCall(ISGetLocalSize(points, &n)); 2987 PetscCall(ISGetIndices(points, &arr0)); 2988 PetscCall(DMPlexGetDepth(dm, &depth_)); 2989 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2990 PetscCall(PetscCalloc1(depth_, §ions_)); 2991 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2992 for (d = depth_ - 1; d >= 0; d--) { 2993 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2994 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2995 for (i = 0; i < n; i++) { 2996 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2997 if (arr[i] >= start && arr[i] < end) { 2998 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2999 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 3000 } else { 3001 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 3002 } 3003 } 3004 PetscCall(PetscSectionSetUp(sections_[d])); 3005 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 3006 PetscCall(PetscMalloc1(newn, &newarr)); 3007 for (i = 0; i < n; i++) { 3008 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 3009 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 3010 if (cn > 1) { 3011 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3012 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3013 } else { 3014 newarr[co] = arr[i]; 3015 } 3016 } 3017 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3018 arr = newarr; 3019 n = newn; 3020 } 3021 PetscCall(ISRestoreIndices(points, &arr0)); 3022 *depth = depth_; 3023 if (expandedPoints) *expandedPoints = expandedPoints_; 3024 else { 3025 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3026 PetscCall(PetscFree(expandedPoints_)); 3027 } 3028 if (sections) *sections = sections_; 3029 else { 3030 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3031 PetscCall(PetscFree(sections_)); 3032 } 3033 PetscFunctionReturn(PETSC_SUCCESS); 3034 } 3035 3036 /*@ 3037 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3038 3039 Not Collective 3040 3041 Input Parameters: 3042 + dm - The `DMPLEX` 3043 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3044 3045 Output Parameters: 3046 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3047 . expandedPoints - (optional) An array of recursively expanded cones 3048 - sections - (optional) An array of sections which describe mappings from points to their cone points 3049 3050 Level: advanced 3051 3052 Note: 3053 See `DMPlexGetConeRecursive()` 3054 3055 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3056 `DMPlexGetDepth()`, `IS`, `PetscSection` 3057 @*/ 3058 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3059 { 3060 PetscInt d, depth_; 3061 3062 PetscFunctionBegin; 3063 PetscCall(DMPlexGetDepth(dm, &depth_)); 3064 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3065 if (depth) *depth = 0; 3066 if (expandedPoints) { 3067 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3068 PetscCall(PetscFree(*expandedPoints)); 3069 } 3070 if (sections) { 3071 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3072 PetscCall(PetscFree(*sections)); 3073 } 3074 PetscFunctionReturn(PETSC_SUCCESS); 3075 } 3076 3077 /*@ 3078 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 3079 3080 Not Collective 3081 3082 Input Parameters: 3083 + mesh - The `DMPLEX` 3084 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3085 - cone - An array of points which are on the in-edges for point p 3086 3087 Level: beginner 3088 3089 Note: 3090 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3091 3092 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3093 @*/ 3094 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3095 { 3096 DM_Plex *mesh = (DM_Plex *)dm->data; 3097 PetscInt pStart, pEnd; 3098 PetscInt dof, off, c; 3099 3100 PetscFunctionBegin; 3101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3102 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3103 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3104 if (dof) PetscValidIntPointer(cone, 3); 3105 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3106 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); 3107 for (c = 0; c < dof; ++c) { 3108 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); 3109 mesh->cones[off + c] = cone[c]; 3110 } 3111 PetscFunctionReturn(PETSC_SUCCESS); 3112 } 3113 3114 /*@C 3115 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3116 3117 Not Collective 3118 3119 Input Parameters: 3120 + mesh - The `DMPLEX` 3121 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3122 3123 Output Parameter: 3124 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3125 integer giving the prescription for cone traversal. 3126 3127 Level: beginner 3128 3129 Note: 3130 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3131 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3132 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3133 with the identity. 3134 3135 Fortran Note: 3136 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3137 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3138 3139 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3140 @*/ 3141 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3142 { 3143 DM_Plex *mesh = (DM_Plex *)dm->data; 3144 PetscInt off; 3145 3146 PetscFunctionBegin; 3147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3148 if (PetscDefined(USE_DEBUG)) { 3149 PetscInt dof; 3150 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3151 if (dof) PetscValidPointer(coneOrientation, 3); 3152 } 3153 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3154 3155 *coneOrientation = &mesh->coneOrientations[off]; 3156 PetscFunctionReturn(PETSC_SUCCESS); 3157 } 3158 3159 /*@ 3160 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3161 3162 Not Collective 3163 3164 Input Parameters: 3165 + mesh - The `DMPLEX` 3166 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3167 - coneOrientation - An array of orientations 3168 3169 Level: beginner 3170 3171 Notes: 3172 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3173 3174 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3175 3176 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3177 @*/ 3178 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3179 { 3180 DM_Plex *mesh = (DM_Plex *)dm->data; 3181 PetscInt pStart, pEnd; 3182 PetscInt dof, off, c; 3183 3184 PetscFunctionBegin; 3185 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3186 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3187 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3188 if (dof) PetscValidIntPointer(coneOrientation, 3); 3189 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3190 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); 3191 for (c = 0; c < dof; ++c) { 3192 PetscInt cdof, o = coneOrientation[c]; 3193 3194 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3195 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); 3196 mesh->coneOrientations[off + c] = o; 3197 } 3198 PetscFunctionReturn(PETSC_SUCCESS); 3199 } 3200 3201 /*@ 3202 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3203 3204 Not Collective 3205 3206 Input Parameters: 3207 + mesh - The `DMPLEX` 3208 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3209 . conePos - The local index in the cone where the point should be put 3210 - conePoint - The mesh point to insert 3211 3212 Level: beginner 3213 3214 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3215 @*/ 3216 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3217 { 3218 DM_Plex *mesh = (DM_Plex *)dm->data; 3219 PetscInt pStart, pEnd; 3220 PetscInt dof, off; 3221 3222 PetscFunctionBegin; 3223 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3224 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3225 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); 3226 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); 3227 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3228 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3229 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); 3230 mesh->cones[off + conePos] = conePoint; 3231 PetscFunctionReturn(PETSC_SUCCESS); 3232 } 3233 3234 /*@ 3235 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3236 3237 Not Collective 3238 3239 Input Parameters: 3240 + mesh - The `DMPLEX` 3241 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3242 . conePos - The local index in the cone where the point should be put 3243 - coneOrientation - The point orientation to insert 3244 3245 Level: beginner 3246 3247 Note: 3248 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3249 3250 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3251 @*/ 3252 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3253 { 3254 DM_Plex *mesh = (DM_Plex *)dm->data; 3255 PetscInt pStart, pEnd; 3256 PetscInt dof, off; 3257 3258 PetscFunctionBegin; 3259 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3260 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3261 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3262 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3263 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3264 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); 3265 mesh->coneOrientations[off + conePos] = coneOrientation; 3266 PetscFunctionReturn(PETSC_SUCCESS); 3267 } 3268 3269 /*@C 3270 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3271 3272 Not collective 3273 3274 Input Parameters: 3275 + dm - The DMPlex 3276 - p - The point, which must lie in the chart set with DMPlexSetChart() 3277 3278 Output Parameters: 3279 + cone - An array of points which are on the in-edges for point p 3280 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3281 integer giving the prescription for cone traversal. 3282 3283 Level: beginner 3284 3285 Notes: 3286 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3287 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3288 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3289 with the identity. 3290 3291 Fortran Notes: 3292 Since it returns an array, this routine is only available in Fortran 90, and you must 3293 include petsc.h90 in your code. 3294 You must also call DMPlexRestoreCone() after you finish using the returned array. 3295 DMPlexRestoreCone() is not needed/available in C. 3296 3297 .seealso: `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3298 @*/ 3299 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3300 { 3301 DM_Plex *mesh = (DM_Plex *)dm->data; 3302 3303 PetscFunctionBegin; 3304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3305 if (mesh->tr) { 3306 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3307 } else { 3308 PetscInt off; 3309 if (PetscDefined(USE_DEBUG)) { 3310 PetscInt dof; 3311 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3312 if (dof) { 3313 if (cone) PetscValidPointer(cone, 3); 3314 if (ornt) PetscValidPointer(ornt, 4); 3315 } 3316 } 3317 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3318 if (cone) *cone = &mesh->cones[off]; 3319 if (ornt) *ornt = &mesh->coneOrientations[off]; 3320 } 3321 PetscFunctionReturn(PETSC_SUCCESS); 3322 } 3323 3324 /*@C 3325 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3326 3327 Not collective 3328 3329 Input Parameters: 3330 + dm - The DMPlex 3331 . p - The point, which must lie in the chart set with DMPlexSetChart() 3332 . cone - An array of points which are on the in-edges for point p 3333 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3334 integer giving the prescription for cone traversal. 3335 3336 Level: beginner 3337 3338 Notes: 3339 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3340 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3341 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3342 with the identity. 3343 3344 Fortran Notes: 3345 Since it returns an array, this routine is only available in Fortran 90, and you must 3346 include petsc.h90 in your code. 3347 You must also call DMPlexRestoreCone() after you finish using the returned array. 3348 DMPlexRestoreCone() is not needed/available in C. 3349 3350 .seealso: `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3351 @*/ 3352 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3353 { 3354 DM_Plex *mesh = (DM_Plex *)dm->data; 3355 3356 PetscFunctionBegin; 3357 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3358 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3359 PetscFunctionReturn(PETSC_SUCCESS); 3360 } 3361 3362 /*@ 3363 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3364 3365 Not Collective 3366 3367 Input Parameters: 3368 + mesh - The `DMPLEX` 3369 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3370 3371 Output Parameter: 3372 . size - The support size for point p 3373 3374 Level: beginner 3375 3376 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3377 @*/ 3378 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3379 { 3380 DM_Plex *mesh = (DM_Plex *)dm->data; 3381 3382 PetscFunctionBegin; 3383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3384 PetscValidIntPointer(size, 3); 3385 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3386 PetscFunctionReturn(PETSC_SUCCESS); 3387 } 3388 3389 /*@ 3390 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3391 3392 Not Collective 3393 3394 Input Parameters: 3395 + mesh - The `DMPLEX` 3396 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3397 - size - The support size for point p 3398 3399 Level: beginner 3400 3401 Note: 3402 This should be called after DMPlexSetChart(). 3403 3404 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3405 @*/ 3406 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3407 { 3408 DM_Plex *mesh = (DM_Plex *)dm->data; 3409 3410 PetscFunctionBegin; 3411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3412 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3413 PetscFunctionReturn(PETSC_SUCCESS); 3414 } 3415 3416 /*@C 3417 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3418 3419 Not Collective 3420 3421 Input Parameters: 3422 + mesh - The `DMPLEX` 3423 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3424 3425 Output Parameter: 3426 . support - An array of points which are on the out-edges for point p 3427 3428 Level: beginner 3429 3430 Fortran Note: 3431 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3432 `DMPlexRestoreSupport()` is not needed/available in C. 3433 3434 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3435 @*/ 3436 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3437 { 3438 DM_Plex *mesh = (DM_Plex *)dm->data; 3439 PetscInt off; 3440 3441 PetscFunctionBegin; 3442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3443 PetscValidPointer(support, 3); 3444 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3445 *support = &mesh->supports[off]; 3446 PetscFunctionReturn(PETSC_SUCCESS); 3447 } 3448 3449 /*@ 3450 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3451 3452 Not Collective 3453 3454 Input Parameters: 3455 + mesh - The `DMPLEX` 3456 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3457 - support - An array of points which are on the out-edges for point p 3458 3459 Level: beginner 3460 3461 Note: 3462 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3463 3464 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3465 @*/ 3466 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3467 { 3468 DM_Plex *mesh = (DM_Plex *)dm->data; 3469 PetscInt pStart, pEnd; 3470 PetscInt dof, off, c; 3471 3472 PetscFunctionBegin; 3473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3474 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3475 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3476 if (dof) PetscValidIntPointer(support, 3); 3477 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3478 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); 3479 for (c = 0; c < dof; ++c) { 3480 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); 3481 mesh->supports[off + c] = support[c]; 3482 } 3483 PetscFunctionReturn(PETSC_SUCCESS); 3484 } 3485 3486 /*@ 3487 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3488 3489 Not Collective 3490 3491 Input Parameters: 3492 + mesh - The `DMPLEX` 3493 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3494 . supportPos - The local index in the cone where the point should be put 3495 - supportPoint - The mesh point to insert 3496 3497 Level: beginner 3498 3499 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3500 @*/ 3501 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3502 { 3503 DM_Plex *mesh = (DM_Plex *)dm->data; 3504 PetscInt pStart, pEnd; 3505 PetscInt dof, off; 3506 3507 PetscFunctionBegin; 3508 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3509 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3510 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3511 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3512 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); 3513 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); 3514 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); 3515 mesh->supports[off + supportPos] = supportPoint; 3516 PetscFunctionReturn(PETSC_SUCCESS); 3517 } 3518 3519 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3520 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3521 { 3522 switch (ct) { 3523 case DM_POLYTOPE_SEGMENT: 3524 if (o == -1) return -2; 3525 break; 3526 case DM_POLYTOPE_TRIANGLE: 3527 if (o == -3) return -1; 3528 if (o == -2) return -3; 3529 if (o == -1) return -2; 3530 break; 3531 case DM_POLYTOPE_QUADRILATERAL: 3532 if (o == -4) return -2; 3533 if (o == -3) return -1; 3534 if (o == -2) return -4; 3535 if (o == -1) return -3; 3536 break; 3537 default: 3538 return o; 3539 } 3540 return o; 3541 } 3542 3543 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3544 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3545 { 3546 switch (ct) { 3547 case DM_POLYTOPE_SEGMENT: 3548 if ((o == -2) || (o == 1)) return -1; 3549 if (o == -1) return 0; 3550 break; 3551 case DM_POLYTOPE_TRIANGLE: 3552 if (o == -3) return -2; 3553 if (o == -2) return -1; 3554 if (o == -1) return -3; 3555 break; 3556 case DM_POLYTOPE_QUADRILATERAL: 3557 if (o == -4) return -2; 3558 if (o == -3) return -1; 3559 if (o == -2) return -4; 3560 if (o == -1) return -3; 3561 break; 3562 default: 3563 return o; 3564 } 3565 return o; 3566 } 3567 3568 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3569 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3570 { 3571 PetscInt pStart, pEnd, p; 3572 3573 PetscFunctionBegin; 3574 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3575 for (p = pStart; p < pEnd; ++p) { 3576 const PetscInt *cone, *ornt; 3577 PetscInt coneSize, c; 3578 3579 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3580 PetscCall(DMPlexGetCone(dm, p, &cone)); 3581 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3582 for (c = 0; c < coneSize; ++c) { 3583 DMPolytopeType ct; 3584 const PetscInt o = ornt[c]; 3585 3586 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3587 switch (ct) { 3588 case DM_POLYTOPE_SEGMENT: 3589 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3590 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3591 break; 3592 case DM_POLYTOPE_TRIANGLE: 3593 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3594 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3595 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3596 break; 3597 case DM_POLYTOPE_QUADRILATERAL: 3598 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3599 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3600 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3601 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3602 break; 3603 default: 3604 break; 3605 } 3606 } 3607 } 3608 PetscFunctionReturn(PETSC_SUCCESS); 3609 } 3610 3611 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3612 { 3613 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3614 PetscInt *closure; 3615 const PetscInt *tmp = NULL, *tmpO = NULL; 3616 PetscInt off = 0, tmpSize, t; 3617 3618 PetscFunctionBeginHot; 3619 if (ornt) { 3620 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3621 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3622 } 3623 if (*points) { 3624 closure = *points; 3625 } else { 3626 PetscInt maxConeSize, maxSupportSize; 3627 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3628 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3629 } 3630 if (useCone) { 3631 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3632 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3633 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3634 } else { 3635 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3636 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3637 } 3638 if (ct == DM_POLYTOPE_UNKNOWN) { 3639 closure[off++] = p; 3640 closure[off++] = 0; 3641 for (t = 0; t < tmpSize; ++t) { 3642 closure[off++] = tmp[t]; 3643 closure[off++] = tmpO ? tmpO[t] : 0; 3644 } 3645 } else { 3646 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3647 3648 /* We assume that cells with a valid type have faces with a valid type */ 3649 closure[off++] = p; 3650 closure[off++] = ornt; 3651 for (t = 0; t < tmpSize; ++t) { 3652 DMPolytopeType ft; 3653 3654 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3655 closure[off++] = tmp[arr[t]]; 3656 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3657 } 3658 } 3659 if (numPoints) *numPoints = tmpSize + 1; 3660 if (points) *points = closure; 3661 PetscFunctionReturn(PETSC_SUCCESS); 3662 } 3663 3664 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3665 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3666 { 3667 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3668 const PetscInt *cone, *ornt; 3669 PetscInt *pts, *closure = NULL; 3670 DMPolytopeType ft; 3671 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3672 PetscInt dim, coneSize, c, d, clSize, cl; 3673 3674 PetscFunctionBeginHot; 3675 PetscCall(DMGetDimension(dm, &dim)); 3676 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3677 PetscCall(DMPlexGetCone(dm, point, &cone)); 3678 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3679 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3680 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3681 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3682 maxSize = PetscMax(coneSeries, supportSeries); 3683 if (*points) { 3684 pts = *points; 3685 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3686 c = 0; 3687 pts[c++] = point; 3688 pts[c++] = o; 3689 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3690 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3691 for (cl = 0; cl < clSize * 2; cl += 2) { 3692 pts[c++] = closure[cl]; 3693 pts[c++] = closure[cl + 1]; 3694 } 3695 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3696 for (cl = 0; cl < clSize * 2; cl += 2) { 3697 pts[c++] = closure[cl]; 3698 pts[c++] = closure[cl + 1]; 3699 } 3700 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3701 for (d = 2; d < coneSize; ++d) { 3702 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3703 pts[c++] = cone[arr[d * 2 + 0]]; 3704 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3705 } 3706 if (dim >= 3) { 3707 for (d = 2; d < coneSize; ++d) { 3708 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3709 const PetscInt *fcone, *fornt; 3710 PetscInt fconeSize, fc, i; 3711 3712 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3713 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3714 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3715 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3716 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3717 for (fc = 0; fc < fconeSize; ++fc) { 3718 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3719 const PetscInt co = farr[fc * 2 + 1]; 3720 3721 for (i = 0; i < c; i += 2) 3722 if (pts[i] == cp) break; 3723 if (i == c) { 3724 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3725 pts[c++] = cp; 3726 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3727 } 3728 } 3729 } 3730 } 3731 *numPoints = c / 2; 3732 *points = pts; 3733 PetscFunctionReturn(PETSC_SUCCESS); 3734 } 3735 3736 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3737 { 3738 DMPolytopeType ct; 3739 PetscInt *closure, *fifo; 3740 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3741 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3742 PetscInt depth, maxSize; 3743 3744 PetscFunctionBeginHot; 3745 PetscCall(DMPlexGetDepth(dm, &depth)); 3746 if (depth == 1) { 3747 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3748 PetscFunctionReturn(PETSC_SUCCESS); 3749 } 3750 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3751 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3752 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3753 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3754 PetscFunctionReturn(PETSC_SUCCESS); 3755 } 3756 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3757 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3758 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3759 maxSize = PetscMax(coneSeries, supportSeries); 3760 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3761 if (*points) { 3762 closure = *points; 3763 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3764 closure[closureSize++] = p; 3765 closure[closureSize++] = ornt; 3766 fifo[fifoSize++] = p; 3767 fifo[fifoSize++] = ornt; 3768 fifo[fifoSize++] = ct; 3769 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3770 while (fifoSize - fifoStart) { 3771 const PetscInt q = fifo[fifoStart++]; 3772 const PetscInt o = fifo[fifoStart++]; 3773 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3774 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3775 const PetscInt *tmp, *tmpO; 3776 PetscInt tmpSize, t; 3777 3778 if (PetscDefined(USE_DEBUG)) { 3779 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3780 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); 3781 } 3782 if (useCone) { 3783 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3784 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3785 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3786 } else { 3787 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3788 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3789 tmpO = NULL; 3790 } 3791 for (t = 0; t < tmpSize; ++t) { 3792 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3793 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3794 const PetscInt cp = tmp[ip]; 3795 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3796 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3797 PetscInt c; 3798 3799 /* Check for duplicate */ 3800 for (c = 0; c < closureSize; c += 2) { 3801 if (closure[c] == cp) break; 3802 } 3803 if (c == closureSize) { 3804 closure[closureSize++] = cp; 3805 closure[closureSize++] = co; 3806 fifo[fifoSize++] = cp; 3807 fifo[fifoSize++] = co; 3808 fifo[fifoSize++] = ct; 3809 } 3810 } 3811 } 3812 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3813 if (numPoints) *numPoints = closureSize / 2; 3814 if (points) *points = closure; 3815 PetscFunctionReturn(PETSC_SUCCESS); 3816 } 3817 3818 /*@C 3819 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3820 3821 Not Collective 3822 3823 Input Parameters: 3824 + dm - The `DMPLEX` 3825 . p - The mesh point 3826 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3827 3828 Input/Output Parameter: 3829 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3830 if NULL on input, internal storage will be returned, otherwise the provided array is used 3831 3832 Output Parameter: 3833 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3834 3835 Level: beginner 3836 3837 Note: 3838 If using internal storage (points is NULL on input), each call overwrites the last output. 3839 3840 Fortran Note: 3841 The numPoints argument is not present in the Fortran binding since it is internal to the array. 3842 3843 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3844 @*/ 3845 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3846 { 3847 PetscFunctionBeginHot; 3848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3849 if (numPoints) PetscValidIntPointer(numPoints, 4); 3850 if (points) PetscValidPointer(points, 5); 3851 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3852 PetscFunctionReturn(PETSC_SUCCESS); 3853 } 3854 3855 /*@C 3856 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3857 3858 Not Collective 3859 3860 Input Parameters: 3861 + dm - The `DMPLEX` 3862 . p - The mesh point 3863 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3864 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3865 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3866 3867 Level: beginner 3868 3869 Note: 3870 If not using internal storage (points is not NULL on input), this call is unnecessary 3871 3872 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3873 @*/ 3874 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3875 { 3876 PetscFunctionBeginHot; 3877 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3878 if (numPoints) *numPoints = 0; 3879 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3880 PetscFunctionReturn(PETSC_SUCCESS); 3881 } 3882 3883 /*@ 3884 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3885 3886 Not Collective 3887 3888 Input Parameter: 3889 . mesh - The `DMPLEX` 3890 3891 Output Parameters: 3892 + maxConeSize - The maximum number of in-edges 3893 - maxSupportSize - The maximum number of out-edges 3894 3895 Level: beginner 3896 3897 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3898 @*/ 3899 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3900 { 3901 DM_Plex *mesh = (DM_Plex *)dm->data; 3902 3903 PetscFunctionBegin; 3904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3905 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3906 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3907 PetscFunctionReturn(PETSC_SUCCESS); 3908 } 3909 3910 PetscErrorCode DMSetUp_Plex(DM dm) 3911 { 3912 DM_Plex *mesh = (DM_Plex *)dm->data; 3913 PetscInt size, maxSupportSize; 3914 3915 PetscFunctionBegin; 3916 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3917 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3918 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3919 PetscCall(PetscMalloc1(size, &mesh->cones)); 3920 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3921 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3922 if (maxSupportSize) { 3923 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3924 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3925 PetscCall(PetscMalloc1(size, &mesh->supports)); 3926 } 3927 PetscFunctionReturn(PETSC_SUCCESS); 3928 } 3929 3930 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3931 { 3932 PetscFunctionBegin; 3933 if (subdm) PetscCall(DMClone(dm, subdm)); 3934 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3935 if (subdm) (*subdm)->useNatural = dm->useNatural; 3936 if (dm->useNatural && dm->sfMigration) { 3937 PetscSF sfNatural; 3938 3939 (*subdm)->sfMigration = dm->sfMigration; 3940 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3941 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3942 (*subdm)->sfNatural = sfNatural; 3943 } 3944 PetscFunctionReturn(PETSC_SUCCESS); 3945 } 3946 3947 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3948 { 3949 PetscInt i = 0; 3950 3951 PetscFunctionBegin; 3952 PetscCall(DMClone(dms[0], superdm)); 3953 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3954 (*superdm)->useNatural = PETSC_FALSE; 3955 for (i = 0; i < len; i++) { 3956 if (dms[i]->useNatural && dms[i]->sfMigration) { 3957 PetscSF sfNatural; 3958 3959 (*superdm)->sfMigration = dms[i]->sfMigration; 3960 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3961 (*superdm)->useNatural = PETSC_TRUE; 3962 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3963 (*superdm)->sfNatural = sfNatural; 3964 break; 3965 } 3966 } 3967 PetscFunctionReturn(PETSC_SUCCESS); 3968 } 3969 3970 /*@ 3971 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3972 3973 Not Collective 3974 3975 Input Parameter: 3976 . mesh - The `DMPLEX` 3977 3978 Level: beginner 3979 3980 Note: 3981 This should be called after all calls to `DMPlexSetCone()` 3982 3983 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3984 @*/ 3985 PetscErrorCode DMPlexSymmetrize(DM dm) 3986 { 3987 DM_Plex *mesh = (DM_Plex *)dm->data; 3988 PetscInt *offsets; 3989 PetscInt supportSize; 3990 PetscInt pStart, pEnd, p; 3991 3992 PetscFunctionBegin; 3993 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3994 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3995 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3996 /* Calculate support sizes */ 3997 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3998 for (p = pStart; p < pEnd; ++p) { 3999 PetscInt dof, off, c; 4000 4001 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4002 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4003 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4004 } 4005 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4006 /* Calculate supports */ 4007 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4008 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4009 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4010 for (p = pStart; p < pEnd; ++p) { 4011 PetscInt dof, off, c; 4012 4013 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4014 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4015 for (c = off; c < off + dof; ++c) { 4016 const PetscInt q = mesh->cones[c]; 4017 PetscInt offS; 4018 4019 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4020 4021 mesh->supports[offS + offsets[q]] = p; 4022 ++offsets[q]; 4023 } 4024 } 4025 PetscCall(PetscFree(offsets)); 4026 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4027 PetscFunctionReturn(PETSC_SUCCESS); 4028 } 4029 4030 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4031 { 4032 IS stratumIS; 4033 4034 PetscFunctionBegin; 4035 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4036 if (PetscDefined(USE_DEBUG)) { 4037 PetscInt qStart, qEnd, numLevels, level; 4038 PetscBool overlap = PETSC_FALSE; 4039 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4040 for (level = 0; level < numLevels; level++) { 4041 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4042 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4043 overlap = PETSC_TRUE; 4044 break; 4045 } 4046 } 4047 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); 4048 } 4049 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4050 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4051 PetscCall(ISDestroy(&stratumIS)); 4052 PetscFunctionReturn(PETSC_SUCCESS); 4053 } 4054 4055 /*@ 4056 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4057 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 4058 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 4059 the DAG. 4060 4061 Collective on dm 4062 4063 Input Parameter: 4064 . mesh - The `DMPLEX` 4065 4066 Level: beginner 4067 4068 Notes: 4069 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4070 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4071 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4072 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4073 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4074 4075 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4076 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4077 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 4078 to interpolate only that one (e0), so that 4079 .vb 4080 cone(c0) = {e0, v2} 4081 cone(e0) = {v0, v1} 4082 .ve 4083 If `DMPlexStratify()` is run on this mesh, it will give depths 4084 .vb 4085 depth 0 = {v0, v1, v2} 4086 depth 1 = {e0, c0} 4087 .ve 4088 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4089 4090 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4091 4092 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4093 @*/ 4094 PetscErrorCode DMPlexStratify(DM dm) 4095 { 4096 DM_Plex *mesh = (DM_Plex *)dm->data; 4097 DMLabel label; 4098 PetscInt pStart, pEnd, p; 4099 PetscInt numRoots = 0, numLeaves = 0; 4100 4101 PetscFunctionBegin; 4102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4103 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4104 4105 /* Create depth label */ 4106 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4107 PetscCall(DMCreateLabel(dm, "depth")); 4108 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4109 4110 { 4111 /* Initialize roots and count leaves */ 4112 PetscInt sMin = PETSC_MAX_INT; 4113 PetscInt sMax = PETSC_MIN_INT; 4114 PetscInt coneSize, supportSize; 4115 4116 for (p = pStart; p < pEnd; ++p) { 4117 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4118 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4119 if (!coneSize && supportSize) { 4120 sMin = PetscMin(p, sMin); 4121 sMax = PetscMax(p, sMax); 4122 ++numRoots; 4123 } else if (!supportSize && coneSize) { 4124 ++numLeaves; 4125 } else if (!supportSize && !coneSize) { 4126 /* Isolated points */ 4127 sMin = PetscMin(p, sMin); 4128 sMax = PetscMax(p, sMax); 4129 } 4130 } 4131 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4132 } 4133 4134 if (numRoots + numLeaves == (pEnd - pStart)) { 4135 PetscInt sMin = PETSC_MAX_INT; 4136 PetscInt sMax = PETSC_MIN_INT; 4137 PetscInt coneSize, supportSize; 4138 4139 for (p = pStart; p < pEnd; ++p) { 4140 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4141 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4142 if (!supportSize && coneSize) { 4143 sMin = PetscMin(p, sMin); 4144 sMax = PetscMax(p, sMax); 4145 } 4146 } 4147 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4148 } else { 4149 PetscInt level = 0; 4150 PetscInt qStart, qEnd, q; 4151 4152 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4153 while (qEnd > qStart) { 4154 PetscInt sMin = PETSC_MAX_INT; 4155 PetscInt sMax = PETSC_MIN_INT; 4156 4157 for (q = qStart; q < qEnd; ++q) { 4158 const PetscInt *support; 4159 PetscInt supportSize, s; 4160 4161 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4162 PetscCall(DMPlexGetSupport(dm, q, &support)); 4163 for (s = 0; s < supportSize; ++s) { 4164 sMin = PetscMin(support[s], sMin); 4165 sMax = PetscMax(support[s], sMax); 4166 } 4167 } 4168 PetscCall(DMLabelGetNumValues(label, &level)); 4169 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4170 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4171 } 4172 } 4173 { /* just in case there is an empty process */ 4174 PetscInt numValues, maxValues = 0, v; 4175 4176 PetscCall(DMLabelGetNumValues(label, &numValues)); 4177 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4178 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4179 } 4180 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4181 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4182 PetscFunctionReturn(PETSC_SUCCESS); 4183 } 4184 4185 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4186 { 4187 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4188 PetscInt dim, depth, pheight, coneSize; 4189 4190 PetscFunctionBeginHot; 4191 PetscCall(DMGetDimension(dm, &dim)); 4192 PetscCall(DMPlexGetDepth(dm, &depth)); 4193 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4194 pheight = depth - pdepth; 4195 if (depth <= 1) { 4196 switch (pdepth) { 4197 case 0: 4198 ct = DM_POLYTOPE_POINT; 4199 break; 4200 case 1: 4201 switch (coneSize) { 4202 case 2: 4203 ct = DM_POLYTOPE_SEGMENT; 4204 break; 4205 case 3: 4206 ct = DM_POLYTOPE_TRIANGLE; 4207 break; 4208 case 4: 4209 switch (dim) { 4210 case 2: 4211 ct = DM_POLYTOPE_QUADRILATERAL; 4212 break; 4213 case 3: 4214 ct = DM_POLYTOPE_TETRAHEDRON; 4215 break; 4216 default: 4217 break; 4218 } 4219 break; 4220 case 5: 4221 ct = DM_POLYTOPE_PYRAMID; 4222 break; 4223 case 6: 4224 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4225 break; 4226 case 8: 4227 ct = DM_POLYTOPE_HEXAHEDRON; 4228 break; 4229 default: 4230 break; 4231 } 4232 } 4233 } else { 4234 if (pdepth == 0) { 4235 ct = DM_POLYTOPE_POINT; 4236 } else if (pheight == 0) { 4237 switch (dim) { 4238 case 1: 4239 switch (coneSize) { 4240 case 2: 4241 ct = DM_POLYTOPE_SEGMENT; 4242 break; 4243 default: 4244 break; 4245 } 4246 break; 4247 case 2: 4248 switch (coneSize) { 4249 case 3: 4250 ct = DM_POLYTOPE_TRIANGLE; 4251 break; 4252 case 4: 4253 ct = DM_POLYTOPE_QUADRILATERAL; 4254 break; 4255 default: 4256 break; 4257 } 4258 break; 4259 case 3: 4260 switch (coneSize) { 4261 case 4: 4262 ct = DM_POLYTOPE_TETRAHEDRON; 4263 break; 4264 case 5: { 4265 const PetscInt *cone; 4266 PetscInt faceConeSize; 4267 4268 PetscCall(DMPlexGetCone(dm, p, &cone)); 4269 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4270 switch (faceConeSize) { 4271 case 3: 4272 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4273 break; 4274 case 4: 4275 ct = DM_POLYTOPE_PYRAMID; 4276 break; 4277 } 4278 } break; 4279 case 6: 4280 ct = DM_POLYTOPE_HEXAHEDRON; 4281 break; 4282 default: 4283 break; 4284 } 4285 break; 4286 default: 4287 break; 4288 } 4289 } else if (pheight > 0) { 4290 switch (coneSize) { 4291 case 2: 4292 ct = DM_POLYTOPE_SEGMENT; 4293 break; 4294 case 3: 4295 ct = DM_POLYTOPE_TRIANGLE; 4296 break; 4297 case 4: 4298 ct = DM_POLYTOPE_QUADRILATERAL; 4299 break; 4300 default: 4301 break; 4302 } 4303 } 4304 } 4305 *pt = ct; 4306 PetscFunctionReturn(PETSC_SUCCESS); 4307 } 4308 4309 /*@ 4310 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4311 4312 Collective on dm 4313 4314 Input Parameter: 4315 . mesh - The `DMPLEX` 4316 4317 Level: developer 4318 4319 Note: 4320 This function is normally called automatically when a cell type is requested. It creates an 4321 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4322 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4323 4324 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4325 4326 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4327 @*/ 4328 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4329 { 4330 DM_Plex *mesh; 4331 DMLabel ctLabel; 4332 PetscInt pStart, pEnd, p; 4333 4334 PetscFunctionBegin; 4335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4336 mesh = (DM_Plex *)dm->data; 4337 PetscCall(DMCreateLabel(dm, "celltype")); 4338 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4339 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4340 for (p = pStart; p < pEnd; ++p) { 4341 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4342 PetscInt pdepth; 4343 4344 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4345 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4346 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4347 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4348 } 4349 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4350 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4351 PetscFunctionReturn(PETSC_SUCCESS); 4352 } 4353 4354 /*@C 4355 DMPlexGetJoin - Get an array for the join of the set of points 4356 4357 Not Collective 4358 4359 Input Parameters: 4360 + dm - The `DMPLEX` object 4361 . numPoints - The number of input points for the join 4362 - points - The input points 4363 4364 Output Parameters: 4365 + numCoveredPoints - The number of points in the join 4366 - coveredPoints - The points in the join 4367 4368 Level: intermediate 4369 4370 Note: 4371 Currently, this is restricted to a single level join 4372 4373 Fortran Note: 4374 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4375 4376 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4377 @*/ 4378 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4379 { 4380 DM_Plex *mesh = (DM_Plex *)dm->data; 4381 PetscInt *join[2]; 4382 PetscInt joinSize, i = 0; 4383 PetscInt dof, off, p, c, m; 4384 PetscInt maxSupportSize; 4385 4386 PetscFunctionBegin; 4387 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4388 PetscValidIntPointer(points, 3); 4389 PetscValidIntPointer(numCoveredPoints, 4); 4390 PetscValidPointer(coveredPoints, 5); 4391 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4392 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4393 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4394 /* Copy in support of first point */ 4395 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4396 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4397 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4398 /* Check each successive support */ 4399 for (p = 1; p < numPoints; ++p) { 4400 PetscInt newJoinSize = 0; 4401 4402 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4403 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4404 for (c = 0; c < dof; ++c) { 4405 const PetscInt point = mesh->supports[off + c]; 4406 4407 for (m = 0; m < joinSize; ++m) { 4408 if (point == join[i][m]) { 4409 join[1 - i][newJoinSize++] = point; 4410 break; 4411 } 4412 } 4413 } 4414 joinSize = newJoinSize; 4415 i = 1 - i; 4416 } 4417 *numCoveredPoints = joinSize; 4418 *coveredPoints = join[i]; 4419 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4420 PetscFunctionReturn(PETSC_SUCCESS); 4421 } 4422 4423 /*@C 4424 DMPlexRestoreJoin - Restore an array for the join of the set of points 4425 4426 Not Collective 4427 4428 Input Parameters: 4429 + dm - The `DMPLEX` object 4430 . numPoints - The number of input points for the join 4431 - points - The input points 4432 4433 Output Parameters: 4434 + numCoveredPoints - The number of points in the join 4435 - coveredPoints - The points in the join 4436 4437 Level: intermediate 4438 4439 Fortran Note: 4440 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4441 4442 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4443 @*/ 4444 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4445 { 4446 PetscFunctionBegin; 4447 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4448 if (points) PetscValidIntPointer(points, 3); 4449 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4450 PetscValidPointer(coveredPoints, 5); 4451 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4452 if (numCoveredPoints) *numCoveredPoints = 0; 4453 PetscFunctionReturn(PETSC_SUCCESS); 4454 } 4455 4456 /*@C 4457 DMPlexGetFullJoin - Get an array for the join of the set of points 4458 4459 Not Collective 4460 4461 Input Parameters: 4462 + dm - The `DMPLEX` object 4463 . numPoints - The number of input points for the join 4464 - points - The input points 4465 4466 Output Parameters: 4467 + numCoveredPoints - The number of points in the join 4468 - coveredPoints - The points in the join 4469 4470 Level: intermediate 4471 4472 Fortran Note: 4473 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4474 4475 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4476 @*/ 4477 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4478 { 4479 PetscInt *offsets, **closures; 4480 PetscInt *join[2]; 4481 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4482 PetscInt p, d, c, m, ms; 4483 4484 PetscFunctionBegin; 4485 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4486 PetscValidIntPointer(points, 3); 4487 PetscValidIntPointer(numCoveredPoints, 4); 4488 PetscValidPointer(coveredPoints, 5); 4489 4490 PetscCall(DMPlexGetDepth(dm, &depth)); 4491 PetscCall(PetscCalloc1(numPoints, &closures)); 4492 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4493 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4494 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4495 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4496 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4497 4498 for (p = 0; p < numPoints; ++p) { 4499 PetscInt closureSize; 4500 4501 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4502 4503 offsets[p * (depth + 2) + 0] = 0; 4504 for (d = 0; d < depth + 1; ++d) { 4505 PetscInt pStart, pEnd, i; 4506 4507 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4508 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4509 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4510 offsets[p * (depth + 2) + d + 1] = i; 4511 break; 4512 } 4513 } 4514 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4515 } 4516 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); 4517 } 4518 for (d = 0; d < depth + 1; ++d) { 4519 PetscInt dof; 4520 4521 /* Copy in support of first point */ 4522 dof = offsets[d + 1] - offsets[d]; 4523 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4524 /* Check each successive cone */ 4525 for (p = 1; p < numPoints && joinSize; ++p) { 4526 PetscInt newJoinSize = 0; 4527 4528 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4529 for (c = 0; c < dof; ++c) { 4530 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4531 4532 for (m = 0; m < joinSize; ++m) { 4533 if (point == join[i][m]) { 4534 join[1 - i][newJoinSize++] = point; 4535 break; 4536 } 4537 } 4538 } 4539 joinSize = newJoinSize; 4540 i = 1 - i; 4541 } 4542 if (joinSize) break; 4543 } 4544 *numCoveredPoints = joinSize; 4545 *coveredPoints = join[i]; 4546 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4547 PetscCall(PetscFree(closures)); 4548 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4549 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4550 PetscFunctionReturn(PETSC_SUCCESS); 4551 } 4552 4553 /*@C 4554 DMPlexGetMeet - Get an array for the meet of the set of points 4555 4556 Not Collective 4557 4558 Input Parameters: 4559 + dm - The `DMPLEX` object 4560 . numPoints - The number of input points for the meet 4561 - points - The input points 4562 4563 Output Parameters: 4564 + numCoveredPoints - The number of points in the meet 4565 - coveredPoints - The points in the meet 4566 4567 Level: intermediate 4568 4569 Note: 4570 Currently, this is restricted to a single level meet 4571 4572 Fortran Notes: 4573 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4574 4575 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4576 @*/ 4577 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4578 { 4579 DM_Plex *mesh = (DM_Plex *)dm->data; 4580 PetscInt *meet[2]; 4581 PetscInt meetSize, i = 0; 4582 PetscInt dof, off, p, c, m; 4583 PetscInt maxConeSize; 4584 4585 PetscFunctionBegin; 4586 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4587 PetscValidIntPointer(points, 3); 4588 PetscValidIntPointer(numCoveringPoints, 4); 4589 PetscValidPointer(coveringPoints, 5); 4590 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4591 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4592 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4593 /* Copy in cone of first point */ 4594 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4595 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4596 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4597 /* Check each successive cone */ 4598 for (p = 1; p < numPoints; ++p) { 4599 PetscInt newMeetSize = 0; 4600 4601 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4602 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4603 for (c = 0; c < dof; ++c) { 4604 const PetscInt point = mesh->cones[off + c]; 4605 4606 for (m = 0; m < meetSize; ++m) { 4607 if (point == meet[i][m]) { 4608 meet[1 - i][newMeetSize++] = point; 4609 break; 4610 } 4611 } 4612 } 4613 meetSize = newMeetSize; 4614 i = 1 - i; 4615 } 4616 *numCoveringPoints = meetSize; 4617 *coveringPoints = meet[i]; 4618 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4619 PetscFunctionReturn(PETSC_SUCCESS); 4620 } 4621 4622 /*@C 4623 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4624 4625 Not Collective 4626 4627 Input Parameters: 4628 + dm - The `DMPLEX` object 4629 . numPoints - The number of input points for the meet 4630 - points - The input points 4631 4632 Output Parameters: 4633 + numCoveredPoints - The number of points in the meet 4634 - coveredPoints - The points in the meet 4635 4636 Level: intermediate 4637 4638 Fortran Note: 4639 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4640 4641 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4642 @*/ 4643 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4644 { 4645 PetscFunctionBegin; 4646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4647 if (points) PetscValidIntPointer(points, 3); 4648 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4649 PetscValidPointer(coveredPoints, 5); 4650 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4651 if (numCoveredPoints) *numCoveredPoints = 0; 4652 PetscFunctionReturn(PETSC_SUCCESS); 4653 } 4654 4655 /*@C 4656 DMPlexGetFullMeet - Get an array for the meet of the set of points 4657 4658 Not Collective 4659 4660 Input Parameters: 4661 + dm - The `DMPLEX` object 4662 . numPoints - The number of input points for the meet 4663 - points - The input points 4664 4665 Output Parameters: 4666 + numCoveredPoints - The number of points in the meet 4667 - coveredPoints - The points in the meet 4668 4669 Level: intermediate 4670 4671 Fortran Note: 4672 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4673 4674 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4675 @*/ 4676 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4677 { 4678 PetscInt *offsets, **closures; 4679 PetscInt *meet[2]; 4680 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4681 PetscInt p, h, c, m, mc; 4682 4683 PetscFunctionBegin; 4684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4685 PetscValidIntPointer(points, 3); 4686 PetscValidIntPointer(numCoveredPoints, 4); 4687 PetscValidPointer(coveredPoints, 5); 4688 4689 PetscCall(DMPlexGetDepth(dm, &height)); 4690 PetscCall(PetscMalloc1(numPoints, &closures)); 4691 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4692 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4693 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4694 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4695 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4696 4697 for (p = 0; p < numPoints; ++p) { 4698 PetscInt closureSize; 4699 4700 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4701 4702 offsets[p * (height + 2) + 0] = 0; 4703 for (h = 0; h < height + 1; ++h) { 4704 PetscInt pStart, pEnd, i; 4705 4706 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4707 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4708 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4709 offsets[p * (height + 2) + h + 1] = i; 4710 break; 4711 } 4712 } 4713 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4714 } 4715 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); 4716 } 4717 for (h = 0; h < height + 1; ++h) { 4718 PetscInt dof; 4719 4720 /* Copy in cone of first point */ 4721 dof = offsets[h + 1] - offsets[h]; 4722 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4723 /* Check each successive cone */ 4724 for (p = 1; p < numPoints && meetSize; ++p) { 4725 PetscInt newMeetSize = 0; 4726 4727 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4728 for (c = 0; c < dof; ++c) { 4729 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4730 4731 for (m = 0; m < meetSize; ++m) { 4732 if (point == meet[i][m]) { 4733 meet[1 - i][newMeetSize++] = point; 4734 break; 4735 } 4736 } 4737 } 4738 meetSize = newMeetSize; 4739 i = 1 - i; 4740 } 4741 if (meetSize) break; 4742 } 4743 *numCoveredPoints = meetSize; 4744 *coveredPoints = meet[i]; 4745 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4746 PetscCall(PetscFree(closures)); 4747 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4748 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4749 PetscFunctionReturn(PETSC_SUCCESS); 4750 } 4751 4752 /*@C 4753 DMPlexEqual - Determine if two `DM` have the same topology 4754 4755 Not Collective 4756 4757 Input Parameters: 4758 + dmA - A `DMPLEX` object 4759 - dmB - A `DMPLEX` object 4760 4761 Output Parameters: 4762 . equal - `PETSC_TRUE` if the topologies are identical 4763 4764 Level: intermediate 4765 4766 Note: 4767 We are not solving graph isomorphism, so we do not permute. 4768 4769 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4770 @*/ 4771 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4772 { 4773 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4774 4775 PetscFunctionBegin; 4776 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4777 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4778 PetscValidBoolPointer(equal, 3); 4779 4780 *equal = PETSC_FALSE; 4781 PetscCall(DMPlexGetDepth(dmA, &depth)); 4782 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4783 if (depth != depthB) PetscFunctionReturn(PETSC_SUCCESS); 4784 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4785 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4786 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(PETSC_SUCCESS); 4787 for (p = pStart; p < pEnd; ++p) { 4788 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4789 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4790 4791 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4792 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4793 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4794 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4795 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4796 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4797 if (coneSize != coneSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4798 for (c = 0; c < coneSize; ++c) { 4799 if (cone[c] != coneB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4800 if (ornt[c] != orntB[c]) PetscFunctionReturn(PETSC_SUCCESS); 4801 } 4802 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4803 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4804 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4805 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4806 if (supportSize != supportSizeB) PetscFunctionReturn(PETSC_SUCCESS); 4807 for (s = 0; s < supportSize; ++s) { 4808 if (support[s] != supportB[s]) PetscFunctionReturn(PETSC_SUCCESS); 4809 } 4810 } 4811 *equal = PETSC_TRUE; 4812 PetscFunctionReturn(PETSC_SUCCESS); 4813 } 4814 4815 /*@C 4816 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4817 4818 Not Collective 4819 4820 Input Parameters: 4821 + dm - The `DMPLEX` 4822 . cellDim - The cell dimension 4823 - numCorners - The number of vertices on a cell 4824 4825 Output Parameters: 4826 . numFaceVertices - The number of vertices on a face 4827 4828 Level: developer 4829 4830 Note: 4831 Of course this can only work for a restricted set of symmetric shapes 4832 4833 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4834 @*/ 4835 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4836 { 4837 MPI_Comm comm; 4838 4839 PetscFunctionBegin; 4840 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4841 PetscValidIntPointer(numFaceVertices, 4); 4842 switch (cellDim) { 4843 case 0: 4844 *numFaceVertices = 0; 4845 break; 4846 case 1: 4847 *numFaceVertices = 1; 4848 break; 4849 case 2: 4850 switch (numCorners) { 4851 case 3: /* triangle */ 4852 *numFaceVertices = 2; /* Edge has 2 vertices */ 4853 break; 4854 case 4: /* quadrilateral */ 4855 *numFaceVertices = 2; /* Edge has 2 vertices */ 4856 break; 4857 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4858 *numFaceVertices = 3; /* Edge has 3 vertices */ 4859 break; 4860 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4861 *numFaceVertices = 3; /* Edge has 3 vertices */ 4862 break; 4863 default: 4864 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4865 } 4866 break; 4867 case 3: 4868 switch (numCorners) { 4869 case 4: /* tetradehdron */ 4870 *numFaceVertices = 3; /* Face has 3 vertices */ 4871 break; 4872 case 6: /* tet cohesive cells */ 4873 *numFaceVertices = 4; /* Face has 4 vertices */ 4874 break; 4875 case 8: /* hexahedron */ 4876 *numFaceVertices = 4; /* Face has 4 vertices */ 4877 break; 4878 case 9: /* tet cohesive Lagrange cells */ 4879 *numFaceVertices = 6; /* Face has 6 vertices */ 4880 break; 4881 case 10: /* quadratic tetrahedron */ 4882 *numFaceVertices = 6; /* Face has 6 vertices */ 4883 break; 4884 case 12: /* hex cohesive Lagrange cells */ 4885 *numFaceVertices = 6; /* Face has 6 vertices */ 4886 break; 4887 case 18: /* quadratic tet cohesive Lagrange cells */ 4888 *numFaceVertices = 6; /* Face has 6 vertices */ 4889 break; 4890 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4891 *numFaceVertices = 9; /* Face has 9 vertices */ 4892 break; 4893 default: 4894 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4895 } 4896 break; 4897 default: 4898 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4899 } 4900 PetscFunctionReturn(PETSC_SUCCESS); 4901 } 4902 4903 /*@ 4904 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 4905 4906 Not Collective 4907 4908 Input Parameter: 4909 . dm - The `DMPLEX` object 4910 4911 Output Parameter: 4912 . depthLabel - The `DMLabel` recording point depth 4913 4914 Level: developer 4915 4916 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4917 @*/ 4918 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4919 { 4920 PetscFunctionBegin; 4921 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4922 PetscValidPointer(depthLabel, 2); 4923 *depthLabel = dm->depthLabel; 4924 PetscFunctionReturn(PETSC_SUCCESS); 4925 } 4926 4927 /*@ 4928 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4929 4930 Not Collective 4931 4932 Input Parameter: 4933 . dm - The `DMPLEX` object 4934 4935 Output Parameter: 4936 . depth - The number of strata (breadth first levels) in the DAG 4937 4938 Level: developer 4939 4940 Notes: 4941 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 4942 4943 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 4944 4945 An empty mesh gives -1. 4946 4947 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4948 @*/ 4949 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4950 { 4951 DM_Plex *mesh = (DM_Plex *)dm->data; 4952 DMLabel label; 4953 PetscInt d = 0; 4954 4955 PetscFunctionBegin; 4956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4957 PetscValidIntPointer(depth, 2); 4958 if (mesh->tr) { 4959 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 4960 } else { 4961 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4962 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4963 *depth = d - 1; 4964 } 4965 PetscFunctionReturn(PETSC_SUCCESS); 4966 } 4967 4968 /*@ 4969 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4970 4971 Not Collective 4972 4973 Input Parameters: 4974 + dm - The `DMPLEX` object 4975 - depth - The requested depth 4976 4977 Output Parameters: 4978 + start - The first point at this depth 4979 - end - One beyond the last point at this depth 4980 4981 Level: developer 4982 4983 Notes: 4984 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4985 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 4986 higher dimension, e.g., "edges". 4987 4988 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4989 @*/ 4990 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4991 { 4992 DM_Plex *mesh = (DM_Plex *)dm->data; 4993 DMLabel label; 4994 PetscInt pStart, pEnd; 4995 4996 PetscFunctionBegin; 4997 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4998 if (start) { 4999 PetscValidIntPointer(start, 3); 5000 *start = 0; 5001 } 5002 if (end) { 5003 PetscValidIntPointer(end, 4); 5004 *end = 0; 5005 } 5006 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5007 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5008 if (depth < 0) { 5009 if (start) *start = pStart; 5010 if (end) *end = pEnd; 5011 PetscFunctionReturn(PETSC_SUCCESS); 5012 } 5013 if (mesh->tr) { 5014 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 5015 } else { 5016 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5017 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5018 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 5019 } 5020 PetscFunctionReturn(PETSC_SUCCESS); 5021 } 5022 5023 /*@ 5024 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 5025 5026 Not Collective 5027 5028 Input Parameters: 5029 + dm - The `DMPLEX` object 5030 - height - The requested height 5031 5032 Output Parameters: 5033 + start - The first point at this height 5034 - end - One beyond the last point at this height 5035 5036 Level: developer 5037 5038 Notes: 5039 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5040 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5041 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5042 5043 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5044 @*/ 5045 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5046 { 5047 DMLabel label; 5048 PetscInt depth, pStart, pEnd; 5049 5050 PetscFunctionBegin; 5051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5052 if (start) { 5053 PetscValidIntPointer(start, 3); 5054 *start = 0; 5055 } 5056 if (end) { 5057 PetscValidIntPointer(end, 4); 5058 *end = 0; 5059 } 5060 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5061 if (pStart == pEnd) PetscFunctionReturn(PETSC_SUCCESS); 5062 if (height < 0) { 5063 if (start) *start = pStart; 5064 if (end) *end = pEnd; 5065 PetscFunctionReturn(PETSC_SUCCESS); 5066 } 5067 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5068 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5069 PetscCall(DMLabelGetNumValues(label, &depth)); 5070 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 5071 PetscFunctionReturn(PETSC_SUCCESS); 5072 } 5073 5074 /*@ 5075 DMPlexGetPointDepth - Get the depth of a given point 5076 5077 Not Collective 5078 5079 Input Parameters: 5080 + dm - The `DMPLEX` object 5081 - point - The point 5082 5083 Output Parameter: 5084 . depth - The depth of the point 5085 5086 Level: intermediate 5087 5088 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5089 @*/ 5090 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5091 { 5092 PetscFunctionBegin; 5093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5094 PetscValidIntPointer(depth, 3); 5095 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5096 PetscFunctionReturn(PETSC_SUCCESS); 5097 } 5098 5099 /*@ 5100 DMPlexGetPointHeight - Get the height of a given point 5101 5102 Not Collective 5103 5104 Input Parameters: 5105 + dm - The `DMPLEX` object 5106 - point - The point 5107 5108 Output Parameter: 5109 . height - The height of the point 5110 5111 Level: intermediate 5112 5113 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5114 @*/ 5115 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5116 { 5117 PetscInt n, pDepth; 5118 5119 PetscFunctionBegin; 5120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5121 PetscValidIntPointer(height, 3); 5122 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5123 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5124 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5125 PetscFunctionReturn(PETSC_SUCCESS); 5126 } 5127 5128 /*@ 5129 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5130 5131 Not Collective 5132 5133 Input Parameter: 5134 . dm - The `DMPLEX` object 5135 5136 Output Parameter: 5137 . celltypeLabel - The `DMLabel` recording cell polytope type 5138 5139 Level: developer 5140 5141 Note: 5142 This function will trigger automatica computation of cell types. This can be disabled by calling 5143 `DMCreateLabel`(dm, "celltype") beforehand. 5144 5145 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5146 @*/ 5147 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5148 { 5149 PetscFunctionBegin; 5150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5151 PetscValidPointer(celltypeLabel, 2); 5152 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5153 *celltypeLabel = dm->celltypeLabel; 5154 PetscFunctionReturn(PETSC_SUCCESS); 5155 } 5156 5157 /*@ 5158 DMPlexGetCellType - Get the polytope type of a given cell 5159 5160 Not Collective 5161 5162 Input Parameters: 5163 + dm - The `DMPLEX` object 5164 - cell - The cell 5165 5166 Output Parameter: 5167 . celltype - The polytope type of the cell 5168 5169 Level: intermediate 5170 5171 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5172 @*/ 5173 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5174 { 5175 DM_Plex *mesh = (DM_Plex *)dm->data; 5176 DMLabel label; 5177 PetscInt ct; 5178 5179 PetscFunctionBegin; 5180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5181 PetscValidPointer(celltype, 3); 5182 if (mesh->tr) { 5183 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5184 } else { 5185 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5186 PetscCall(DMLabelGetValue(label, cell, &ct)); 5187 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5188 *celltype = (DMPolytopeType)ct; 5189 } 5190 PetscFunctionReturn(PETSC_SUCCESS); 5191 } 5192 5193 /*@ 5194 DMPlexSetCellType - Set the polytope type of a given cell 5195 5196 Not Collective 5197 5198 Input Parameters: 5199 + dm - The `DMPLEX` object 5200 . cell - The cell 5201 - celltype - The polytope type of the cell 5202 5203 Level: advanced 5204 5205 Note: 5206 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5207 is executed. This function will override the computed type. However, if automatic classification will not succeed 5208 and a user wants to manually specify all types, the classification must be disabled by calling 5209 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5210 5211 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5212 @*/ 5213 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5214 { 5215 DMLabel label; 5216 5217 PetscFunctionBegin; 5218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5219 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5220 PetscCall(DMLabelSetValue(label, cell, celltype)); 5221 PetscFunctionReturn(PETSC_SUCCESS); 5222 } 5223 5224 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5225 { 5226 PetscSection section, s; 5227 Mat m; 5228 PetscInt maxHeight; 5229 const char *prefix; 5230 5231 PetscFunctionBegin; 5232 PetscCall(DMClone(dm, cdm)); 5233 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5234 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5235 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5236 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5237 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5238 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5239 PetscCall(DMSetLocalSection(*cdm, section)); 5240 PetscCall(PetscSectionDestroy(§ion)); 5241 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5242 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5243 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5244 PetscCall(PetscSectionDestroy(&s)); 5245 PetscCall(MatDestroy(&m)); 5246 5247 PetscCall(DMSetNumFields(*cdm, 1)); 5248 PetscCall(DMCreateDS(*cdm)); 5249 (*cdm)->cloneOpts = PETSC_TRUE; 5250 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5251 PetscFunctionReturn(PETSC_SUCCESS); 5252 } 5253 5254 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5255 { 5256 Vec coordsLocal, cellCoordsLocal; 5257 DM coordsDM, cellCoordsDM; 5258 5259 PetscFunctionBegin; 5260 *field = NULL; 5261 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5262 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5263 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5264 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5265 if (coordsLocal && coordsDM) { 5266 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5267 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5268 } 5269 PetscFunctionReturn(PETSC_SUCCESS); 5270 } 5271 5272 /*@C 5273 DMPlexGetConeSection - Return a section which describes the layout of cone data 5274 5275 Not Collective 5276 5277 Input Parameters: 5278 . dm - The `DMPLEX` object 5279 5280 Output Parameter: 5281 . section - The `PetscSection` object 5282 5283 Level: developer 5284 5285 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5286 @*/ 5287 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5288 { 5289 DM_Plex *mesh = (DM_Plex *)dm->data; 5290 5291 PetscFunctionBegin; 5292 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5293 if (section) *section = mesh->coneSection; 5294 PetscFunctionReturn(PETSC_SUCCESS); 5295 } 5296 5297 /*@C 5298 DMPlexGetSupportSection - Return a section which describes the layout of support data 5299 5300 Not Collective 5301 5302 Input Parameters: 5303 . dm - The `DMPLEX` object 5304 5305 Output Parameter: 5306 . section - The `PetscSection` object 5307 5308 Level: developer 5309 5310 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5311 @*/ 5312 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5313 { 5314 DM_Plex *mesh = (DM_Plex *)dm->data; 5315 5316 PetscFunctionBegin; 5317 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5318 if (section) *section = mesh->supportSection; 5319 PetscFunctionReturn(PETSC_SUCCESS); 5320 } 5321 5322 /*@C 5323 DMPlexGetCones - Return cone data 5324 5325 Not Collective 5326 5327 Input Parameters: 5328 . dm - The `DMPLEX` object 5329 5330 Output Parameter: 5331 . cones - The cone for each point 5332 5333 Level: developer 5334 5335 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5336 @*/ 5337 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5338 { 5339 DM_Plex *mesh = (DM_Plex *)dm->data; 5340 5341 PetscFunctionBegin; 5342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5343 if (cones) *cones = mesh->cones; 5344 PetscFunctionReturn(PETSC_SUCCESS); 5345 } 5346 5347 /*@C 5348 DMPlexGetConeOrientations - Return cone orientation data 5349 5350 Not Collective 5351 5352 Input Parameters: 5353 . dm - The `DMPLEX` object 5354 5355 Output Parameter: 5356 . coneOrientations - The array of cone orientations for all points 5357 5358 Level: developer 5359 5360 Notes: 5361 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5362 5363 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5364 5365 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5366 @*/ 5367 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5368 { 5369 DM_Plex *mesh = (DM_Plex *)dm->data; 5370 5371 PetscFunctionBegin; 5372 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5373 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5374 PetscFunctionReturn(PETSC_SUCCESS); 5375 } 5376 5377 /******************************** FEM Support **********************************/ 5378 5379 /* 5380 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5381 representing a line in the section. 5382 */ 5383 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5384 { 5385 PetscFunctionBeginHot; 5386 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5387 if (line < 0) { 5388 *k = 0; 5389 *Nc = 0; 5390 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5391 *k = 1; 5392 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5393 /* An order k SEM disc has k-1 dofs on an edge */ 5394 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5395 *k = *k / *Nc + 1; 5396 } 5397 PetscFunctionReturn(PETSC_SUCCESS); 5398 } 5399 5400 /*@ 5401 5402 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5403 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5404 section provided (or the section of the DM). 5405 5406 Input Parameters: 5407 + dm - The DM 5408 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5409 - section - The PetscSection to reorder, or NULL for the default section 5410 5411 Example: 5412 A typical interpolated single-quad mesh might order points as 5413 .vb 5414 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5415 5416 v4 -- e6 -- v3 5417 | | 5418 e7 c0 e8 5419 | | 5420 v1 -- e5 -- v2 5421 .ve 5422 5423 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5424 dofs in the order of points, e.g., 5425 .vb 5426 c0 -> [0,1,2,3] 5427 v1 -> [4] 5428 ... 5429 e5 -> [8, 9] 5430 .ve 5431 5432 which corresponds to the dofs 5433 .vb 5434 6 10 11 7 5435 13 2 3 15 5436 12 0 1 14 5437 4 8 9 5 5438 .ve 5439 5440 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5441 .vb 5442 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5443 .ve 5444 5445 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5446 .vb 5447 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5448 .ve 5449 5450 Level: developer 5451 5452 Note: 5453 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5454 degree of the basis. 5455 5456 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5457 @*/ 5458 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5459 { 5460 DMLabel label; 5461 PetscInt dim, depth = -1, eStart = -1, Nf; 5462 PetscBool vertexchart; 5463 5464 PetscFunctionBegin; 5465 PetscCall(DMGetDimension(dm, &dim)); 5466 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5467 if (point < 0) { 5468 PetscInt sStart, sEnd; 5469 5470 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5471 point = sEnd - sStart ? sStart : point; 5472 } 5473 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5474 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5475 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5476 if (depth == 1) { 5477 eStart = point; 5478 } else if (depth == dim) { 5479 const PetscInt *cone; 5480 5481 PetscCall(DMPlexGetCone(dm, point, &cone)); 5482 if (dim == 2) eStart = cone[0]; 5483 else if (dim == 3) { 5484 const PetscInt *cone2; 5485 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5486 eStart = cone2[0]; 5487 } 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); 5488 } 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); 5489 { /* Determine whether the chart covers all points or just vertices. */ 5490 PetscInt pStart, pEnd, cStart, cEnd; 5491 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5492 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5493 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5494 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5495 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5496 } 5497 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5498 for (PetscInt d = 1; d <= dim; d++) { 5499 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5500 PetscInt *perm; 5501 5502 for (f = 0; f < Nf; ++f) { 5503 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5504 size += PetscPowInt(k + 1, d) * Nc; 5505 } 5506 PetscCall(PetscMalloc1(size, &perm)); 5507 for (f = 0; f < Nf; ++f) { 5508 switch (d) { 5509 case 1: 5510 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5511 /* 5512 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5513 We want [ vtx0; edge of length k-1; vtx1 ] 5514 */ 5515 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5516 for (i = 0; i < k - 1; i++) 5517 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5518 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5519 foffset = offset; 5520 break; 5521 case 2: 5522 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5523 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5524 /* The SEM order is 5525 5526 v_lb, {e_b}, v_rb, 5527 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5528 v_lt, reverse {e_t}, v_rt 5529 */ 5530 { 5531 const PetscInt of = 0; 5532 const PetscInt oeb = of + PetscSqr(k - 1); 5533 const PetscInt oer = oeb + (k - 1); 5534 const PetscInt oet = oer + (k - 1); 5535 const PetscInt oel = oet + (k - 1); 5536 const PetscInt ovlb = oel + (k - 1); 5537 const PetscInt ovrb = ovlb + 1; 5538 const PetscInt ovrt = ovrb + 1; 5539 const PetscInt ovlt = ovrt + 1; 5540 PetscInt o; 5541 5542 /* bottom */ 5543 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5544 for (o = oeb; o < oer; ++o) 5545 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5546 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5547 /* middle */ 5548 for (i = 0; i < k - 1; ++i) { 5549 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5550 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5551 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5552 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5553 } 5554 /* top */ 5555 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5556 for (o = oel - 1; o >= oet; --o) 5557 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5558 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5559 foffset = offset; 5560 } 5561 break; 5562 case 3: 5563 /* The original hex closure is 5564 5565 {c, 5566 f_b, f_t, f_f, f_b, f_r, f_l, 5567 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5568 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5569 */ 5570 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5571 /* The SEM order is 5572 Bottom Slice 5573 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5574 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5575 v_blb, {e_bb}, v_brb, 5576 5577 Middle Slice (j) 5578 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5579 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5580 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5581 5582 Top Slice 5583 v_tlf, {e_tf}, v_trf, 5584 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5585 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5586 */ 5587 { 5588 const PetscInt oc = 0; 5589 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5590 const PetscInt oft = ofb + PetscSqr(k - 1); 5591 const PetscInt off = oft + PetscSqr(k - 1); 5592 const PetscInt ofk = off + PetscSqr(k - 1); 5593 const PetscInt ofr = ofk + PetscSqr(k - 1); 5594 const PetscInt ofl = ofr + PetscSqr(k - 1); 5595 const PetscInt oebl = ofl + PetscSqr(k - 1); 5596 const PetscInt oebb = oebl + (k - 1); 5597 const PetscInt oebr = oebb + (k - 1); 5598 const PetscInt oebf = oebr + (k - 1); 5599 const PetscInt oetf = oebf + (k - 1); 5600 const PetscInt oetr = oetf + (k - 1); 5601 const PetscInt oetb = oetr + (k - 1); 5602 const PetscInt oetl = oetb + (k - 1); 5603 const PetscInt oerf = oetl + (k - 1); 5604 const PetscInt oelf = oerf + (k - 1); 5605 const PetscInt oelb = oelf + (k - 1); 5606 const PetscInt oerb = oelb + (k - 1); 5607 const PetscInt ovblf = oerb + (k - 1); 5608 const PetscInt ovblb = ovblf + 1; 5609 const PetscInt ovbrb = ovblb + 1; 5610 const PetscInt ovbrf = ovbrb + 1; 5611 const PetscInt ovtlf = ovbrf + 1; 5612 const PetscInt ovtrf = ovtlf + 1; 5613 const PetscInt ovtrb = ovtrf + 1; 5614 const PetscInt ovtlb = ovtrb + 1; 5615 PetscInt o, n; 5616 5617 /* Bottom Slice */ 5618 /* bottom */ 5619 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5620 for (o = oetf - 1; o >= oebf; --o) 5621 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5622 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5623 /* middle */ 5624 for (i = 0; i < k - 1; ++i) { 5625 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5626 for (n = 0; n < k - 1; ++n) { 5627 o = ofb + n * (k - 1) + i; 5628 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5629 } 5630 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5631 } 5632 /* top */ 5633 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5634 for (o = oebb; o < oebr; ++o) 5635 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5636 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5637 5638 /* Middle Slice */ 5639 for (j = 0; j < k - 1; ++j) { 5640 /* bottom */ 5641 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5642 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5643 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5644 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5645 /* middle */ 5646 for (i = 0; i < k - 1; ++i) { 5647 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5648 for (n = 0; n < k - 1; ++n) 5649 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5650 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5651 } 5652 /* top */ 5653 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5654 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5655 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5656 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5657 } 5658 5659 /* Top Slice */ 5660 /* bottom */ 5661 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5662 for (o = oetf; o < oetr; ++o) 5663 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5664 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5665 /* middle */ 5666 for (i = 0; i < k - 1; ++i) { 5667 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5668 for (n = 0; n < k - 1; ++n) 5669 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5670 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5671 } 5672 /* top */ 5673 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5674 for (o = oetl - 1; o >= oetb; --o) 5675 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5676 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5677 5678 foffset = offset; 5679 } 5680 break; 5681 default: 5682 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5683 } 5684 } 5685 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5686 /* Check permutation */ 5687 { 5688 PetscInt *check; 5689 5690 PetscCall(PetscMalloc1(size, &check)); 5691 for (i = 0; i < size; ++i) { 5692 check[i] = -1; 5693 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5694 } 5695 for (i = 0; i < size; ++i) check[perm[i]] = i; 5696 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5697 PetscCall(PetscFree(check)); 5698 } 5699 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5700 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5701 PetscInt *loc_perm; 5702 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5703 for (PetscInt i = 0; i < size; i++) { 5704 loc_perm[i] = perm[i]; 5705 loc_perm[size + i] = size + perm[i]; 5706 } 5707 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5708 } 5709 } 5710 PetscFunctionReturn(PETSC_SUCCESS); 5711 } 5712 5713 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5714 { 5715 PetscDS prob; 5716 PetscInt depth, Nf, h; 5717 DMLabel label; 5718 5719 PetscFunctionBeginHot; 5720 PetscCall(DMGetDS(dm, &prob)); 5721 Nf = prob->Nf; 5722 label = dm->depthLabel; 5723 *dspace = NULL; 5724 if (field < Nf) { 5725 PetscObject disc = prob->disc[field]; 5726 5727 if (disc->classid == PETSCFE_CLASSID) { 5728 PetscDualSpace dsp; 5729 5730 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5731 PetscCall(DMLabelGetNumValues(label, &depth)); 5732 PetscCall(DMLabelGetValue(label, point, &h)); 5733 h = depth - 1 - h; 5734 if (h) { 5735 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5736 } else { 5737 *dspace = dsp; 5738 } 5739 } 5740 } 5741 PetscFunctionReturn(PETSC_SUCCESS); 5742 } 5743 5744 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5745 { 5746 PetscScalar *array; 5747 const PetscScalar *vArray; 5748 const PetscInt *cone, *coneO; 5749 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5750 5751 PetscFunctionBeginHot; 5752 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5753 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5754 PetscCall(DMPlexGetCone(dm, point, &cone)); 5755 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5756 if (!values || !*values) { 5757 if ((point >= pStart) && (point < pEnd)) { 5758 PetscInt dof; 5759 5760 PetscCall(PetscSectionGetDof(section, point, &dof)); 5761 size += dof; 5762 } 5763 for (p = 0; p < numPoints; ++p) { 5764 const PetscInt cp = cone[p]; 5765 PetscInt dof; 5766 5767 if ((cp < pStart) || (cp >= pEnd)) continue; 5768 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5769 size += dof; 5770 } 5771 if (!values) { 5772 if (csize) *csize = size; 5773 PetscFunctionReturn(PETSC_SUCCESS); 5774 } 5775 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5776 } else { 5777 array = *values; 5778 } 5779 size = 0; 5780 PetscCall(VecGetArrayRead(v, &vArray)); 5781 if ((point >= pStart) && (point < pEnd)) { 5782 PetscInt dof, off, d; 5783 const PetscScalar *varr; 5784 5785 PetscCall(PetscSectionGetDof(section, point, &dof)); 5786 PetscCall(PetscSectionGetOffset(section, point, &off)); 5787 varr = &vArray[off]; 5788 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5789 size += dof; 5790 } 5791 for (p = 0; p < numPoints; ++p) { 5792 const PetscInt cp = cone[p]; 5793 PetscInt o = coneO[p]; 5794 PetscInt dof, off, d; 5795 const PetscScalar *varr; 5796 5797 if ((cp < pStart) || (cp >= pEnd)) continue; 5798 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5799 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5800 varr = &vArray[off]; 5801 if (o >= 0) { 5802 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5803 } else { 5804 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5805 } 5806 size += dof; 5807 } 5808 PetscCall(VecRestoreArrayRead(v, &vArray)); 5809 if (!*values) { 5810 if (csize) *csize = size; 5811 *values = array; 5812 } else { 5813 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5814 *csize = size; 5815 } 5816 PetscFunctionReturn(PETSC_SUCCESS); 5817 } 5818 5819 /* Compress out points not in the section */ 5820 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5821 { 5822 const PetscInt np = *numPoints; 5823 PetscInt pStart, pEnd, p, q; 5824 5825 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5826 for (p = 0, q = 0; p < np; ++p) { 5827 const PetscInt r = points[p * 2]; 5828 if ((r >= pStart) && (r < pEnd)) { 5829 points[q * 2] = r; 5830 points[q * 2 + 1] = points[p * 2 + 1]; 5831 ++q; 5832 } 5833 } 5834 *numPoints = q; 5835 return PETSC_SUCCESS; 5836 } 5837 5838 /* Compressed closure does not apply closure permutation */ 5839 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5840 { 5841 const PetscInt *cla = NULL; 5842 PetscInt np, *pts = NULL; 5843 5844 PetscFunctionBeginHot; 5845 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5846 if (*clPoints) { 5847 PetscInt dof, off; 5848 5849 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5850 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5851 PetscCall(ISGetIndices(*clPoints, &cla)); 5852 np = dof / 2; 5853 pts = (PetscInt *)&cla[off]; 5854 } else { 5855 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5856 PetscCall(CompressPoints_Private(section, &np, pts)); 5857 } 5858 *numPoints = np; 5859 *points = pts; 5860 *clp = cla; 5861 PetscFunctionReturn(PETSC_SUCCESS); 5862 } 5863 5864 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5865 { 5866 PetscFunctionBeginHot; 5867 if (!*clPoints) { 5868 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5869 } else { 5870 PetscCall(ISRestoreIndices(*clPoints, clp)); 5871 } 5872 *numPoints = 0; 5873 *points = NULL; 5874 *clSec = NULL; 5875 *clPoints = NULL; 5876 *clp = NULL; 5877 PetscFunctionReturn(PETSC_SUCCESS); 5878 } 5879 5880 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5881 { 5882 PetscInt offset = 0, p; 5883 const PetscInt **perms = NULL; 5884 const PetscScalar **flips = NULL; 5885 5886 PetscFunctionBeginHot; 5887 *size = 0; 5888 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5889 for (p = 0; p < numPoints; p++) { 5890 const PetscInt point = points[2 * p]; 5891 const PetscInt *perm = perms ? perms[p] : NULL; 5892 const PetscScalar *flip = flips ? flips[p] : NULL; 5893 PetscInt dof, off, d; 5894 const PetscScalar *varr; 5895 5896 PetscCall(PetscSectionGetDof(section, point, &dof)); 5897 PetscCall(PetscSectionGetOffset(section, point, &off)); 5898 varr = &vArray[off]; 5899 if (clperm) { 5900 if (perm) { 5901 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5902 } else { 5903 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5904 } 5905 if (flip) { 5906 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5907 } 5908 } else { 5909 if (perm) { 5910 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5911 } else { 5912 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5913 } 5914 if (flip) { 5915 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5916 } 5917 } 5918 offset += dof; 5919 } 5920 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5921 *size = offset; 5922 PetscFunctionReturn(PETSC_SUCCESS); 5923 } 5924 5925 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[]) 5926 { 5927 PetscInt offset = 0, f; 5928 5929 PetscFunctionBeginHot; 5930 *size = 0; 5931 for (f = 0; f < numFields; ++f) { 5932 PetscInt p; 5933 const PetscInt **perms = NULL; 5934 const PetscScalar **flips = NULL; 5935 5936 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5937 for (p = 0; p < numPoints; p++) { 5938 const PetscInt point = points[2 * p]; 5939 PetscInt fdof, foff, b; 5940 const PetscScalar *varr; 5941 const PetscInt *perm = perms ? perms[p] : NULL; 5942 const PetscScalar *flip = flips ? flips[p] : NULL; 5943 5944 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5945 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5946 varr = &vArray[foff]; 5947 if (clperm) { 5948 if (perm) { 5949 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5950 } else { 5951 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5952 } 5953 if (flip) { 5954 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5955 } 5956 } else { 5957 if (perm) { 5958 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5959 } else { 5960 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5961 } 5962 if (flip) { 5963 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5964 } 5965 } 5966 offset += fdof; 5967 } 5968 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5969 } 5970 *size = offset; 5971 PetscFunctionReturn(PETSC_SUCCESS); 5972 } 5973 5974 /*@C 5975 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5976 5977 Not collective 5978 5979 Input Parameters: 5980 + dm - The `DM` 5981 . section - The section describing the layout in v, or NULL to use the default section 5982 . v - The local vector 5983 - point - The point in the `DM` 5984 5985 Input/Output Parameters: 5986 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5987 - values - An array to use for the values, or NULL to have it allocated automatically; 5988 if the user provided NULL, it is a borrowed array and should not be freed 5989 5990 Level: intermediate 5991 5992 Notes: 5993 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to NULL in the 5994 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 5995 assembly function, and a user may already have allocated storage for this operation. 5996 5997 A typical use could be 5998 .vb 5999 values = NULL; 6000 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6001 for (cl = 0; cl < clSize; ++cl) { 6002 <Compute on closure> 6003 } 6004 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6005 .ve 6006 or 6007 .vb 6008 PetscMalloc1(clMaxSize, &values); 6009 for (p = pStart; p < pEnd; ++p) { 6010 clSize = clMaxSize; 6011 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6012 for (cl = 0; cl < clSize; ++cl) { 6013 <Compute on closure> 6014 } 6015 } 6016 PetscFree(values); 6017 .ve 6018 6019 Fortran Note: 6020 The csize argument is not present in the Fortran binding since it is internal to the array. 6021 6022 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6023 @*/ 6024 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6025 { 6026 PetscSection clSection; 6027 IS clPoints; 6028 PetscInt *points = NULL; 6029 const PetscInt *clp, *perm; 6030 PetscInt depth, numFields, numPoints, asize; 6031 6032 PetscFunctionBeginHot; 6033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6034 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6035 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6036 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6037 PetscCall(DMPlexGetDepth(dm, &depth)); 6038 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6039 if (depth == 1 && numFields < 2) { 6040 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6041 PetscFunctionReturn(PETSC_SUCCESS); 6042 } 6043 /* Get points */ 6044 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6045 /* Get sizes */ 6046 asize = 0; 6047 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6048 PetscInt dof; 6049 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6050 asize += dof; 6051 } 6052 if (values) { 6053 const PetscScalar *vArray; 6054 PetscInt size; 6055 6056 if (*values) { 6057 PetscCheck(*csize >= asize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %" PetscInt_FMT " not sufficient to hold closure size %" PetscInt_FMT, *csize, asize); 6058 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6059 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6060 PetscCall(VecGetArrayRead(v, &vArray)); 6061 /* Get values */ 6062 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6063 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6064 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6065 /* Cleanup array */ 6066 PetscCall(VecRestoreArrayRead(v, &vArray)); 6067 } 6068 if (csize) *csize = asize; 6069 /* Cleanup points */ 6070 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6071 PetscFunctionReturn(PETSC_SUCCESS); 6072 } 6073 6074 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6075 { 6076 DMLabel depthLabel; 6077 PetscSection clSection; 6078 IS clPoints; 6079 PetscScalar *array; 6080 const PetscScalar *vArray; 6081 PetscInt *points = NULL; 6082 const PetscInt *clp, *perm = NULL; 6083 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6084 6085 PetscFunctionBeginHot; 6086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6087 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6088 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6089 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6090 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6091 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6092 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6093 if (mdepth == 1 && numFields < 2) { 6094 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6095 PetscFunctionReturn(PETSC_SUCCESS); 6096 } 6097 /* Get points */ 6098 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6099 for (clsize = 0, p = 0; p < Np; p++) { 6100 PetscInt dof; 6101 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6102 clsize += dof; 6103 } 6104 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6105 /* Filter points */ 6106 for (p = 0; p < numPoints * 2; p += 2) { 6107 PetscInt dep; 6108 6109 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6110 if (dep != depth) continue; 6111 points[Np * 2 + 0] = points[p]; 6112 points[Np * 2 + 1] = points[p + 1]; 6113 ++Np; 6114 } 6115 /* Get array */ 6116 if (!values || !*values) { 6117 PetscInt asize = 0, dof; 6118 6119 for (p = 0; p < Np * 2; p += 2) { 6120 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6121 asize += dof; 6122 } 6123 if (!values) { 6124 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6125 if (csize) *csize = asize; 6126 PetscFunctionReturn(PETSC_SUCCESS); 6127 } 6128 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6129 } else { 6130 array = *values; 6131 } 6132 PetscCall(VecGetArrayRead(v, &vArray)); 6133 /* Get values */ 6134 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6135 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6136 /* Cleanup points */ 6137 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6138 /* Cleanup array */ 6139 PetscCall(VecRestoreArrayRead(v, &vArray)); 6140 if (!*values) { 6141 if (csize) *csize = size; 6142 *values = array; 6143 } else { 6144 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6145 *csize = size; 6146 } 6147 PetscFunctionReturn(PETSC_SUCCESS); 6148 } 6149 6150 /*@C 6151 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6152 6153 Not collective 6154 6155 Input Parameters: 6156 + dm - The `DM` 6157 . section - The section describing the layout in v, or NULL to use the default section 6158 . v - The local vector 6159 . point - The point in the `DM` 6160 . csize - The number of values in the closure, or NULL 6161 - values - The array of values, which is a borrowed array and should not be freed 6162 6163 Level: intermediate 6164 6165 Note: 6166 The array values are discarded and not copied back into v. In order to copy values back to v, use `DMPlexVecSetClosure()` 6167 6168 Fortran Note: 6169 The csize argument is not present in the Fortran binding since it is internal to the array. 6170 6171 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6172 @*/ 6173 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6174 { 6175 PetscInt size = 0; 6176 6177 PetscFunctionBegin; 6178 /* Should work without recalculating size */ 6179 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6180 *values = NULL; 6181 PetscFunctionReturn(PETSC_SUCCESS); 6182 } 6183 6184 static inline void add(PetscScalar *x, PetscScalar y) 6185 { 6186 *x += y; 6187 } 6188 static inline void insert(PetscScalar *x, PetscScalar y) 6189 { 6190 *x = y; 6191 } 6192 6193 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[]) 6194 { 6195 PetscInt cdof; /* The number of constraints on this point */ 6196 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6197 PetscScalar *a; 6198 PetscInt off, cind = 0, k; 6199 6200 PetscFunctionBegin; 6201 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6202 PetscCall(PetscSectionGetOffset(section, point, &off)); 6203 a = &array[off]; 6204 if (!cdof || setBC) { 6205 if (clperm) { 6206 if (perm) { 6207 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6208 } else { 6209 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6210 } 6211 } else { 6212 if (perm) { 6213 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6214 } else { 6215 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6216 } 6217 } 6218 } else { 6219 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6220 if (clperm) { 6221 if (perm) { 6222 for (k = 0; k < dof; ++k) { 6223 if ((cind < cdof) && (k == cdofs[cind])) { 6224 ++cind; 6225 continue; 6226 } 6227 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6228 } 6229 } else { 6230 for (k = 0; k < dof; ++k) { 6231 if ((cind < cdof) && (k == cdofs[cind])) { 6232 ++cind; 6233 continue; 6234 } 6235 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6236 } 6237 } 6238 } else { 6239 if (perm) { 6240 for (k = 0; k < dof; ++k) { 6241 if ((cind < cdof) && (k == cdofs[cind])) { 6242 ++cind; 6243 continue; 6244 } 6245 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6246 } 6247 } else { 6248 for (k = 0; k < dof; ++k) { 6249 if ((cind < cdof) && (k == cdofs[cind])) { 6250 ++cind; 6251 continue; 6252 } 6253 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6254 } 6255 } 6256 } 6257 } 6258 PetscFunctionReturn(PETSC_SUCCESS); 6259 } 6260 6261 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[]) 6262 { 6263 PetscInt cdof; /* The number of constraints on this point */ 6264 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6265 PetscScalar *a; 6266 PetscInt off, cind = 0, k; 6267 6268 PetscFunctionBegin; 6269 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6270 PetscCall(PetscSectionGetOffset(section, point, &off)); 6271 a = &array[off]; 6272 if (cdof) { 6273 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6274 if (clperm) { 6275 if (perm) { 6276 for (k = 0; k < dof; ++k) { 6277 if ((cind < cdof) && (k == cdofs[cind])) { 6278 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6279 cind++; 6280 } 6281 } 6282 } else { 6283 for (k = 0; k < dof; ++k) { 6284 if ((cind < cdof) && (k == cdofs[cind])) { 6285 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6286 cind++; 6287 } 6288 } 6289 } 6290 } else { 6291 if (perm) { 6292 for (k = 0; k < dof; ++k) { 6293 if ((cind < cdof) && (k == cdofs[cind])) { 6294 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6295 cind++; 6296 } 6297 } 6298 } else { 6299 for (k = 0; k < dof; ++k) { 6300 if ((cind < cdof) && (k == cdofs[cind])) { 6301 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6302 cind++; 6303 } 6304 } 6305 } 6306 } 6307 } 6308 PetscFunctionReturn(PETSC_SUCCESS); 6309 } 6310 6311 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[]) 6312 { 6313 PetscScalar *a; 6314 PetscInt fdof, foff, fcdof, foffset = *offset; 6315 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6316 PetscInt cind = 0, b; 6317 6318 PetscFunctionBegin; 6319 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6320 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6321 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6322 a = &array[foff]; 6323 if (!fcdof || setBC) { 6324 if (clperm) { 6325 if (perm) { 6326 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6327 } else { 6328 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6329 } 6330 } else { 6331 if (perm) { 6332 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6333 } else { 6334 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6335 } 6336 } 6337 } else { 6338 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6339 if (clperm) { 6340 if (perm) { 6341 for (b = 0; b < fdof; b++) { 6342 if ((cind < fcdof) && (b == fcdofs[cind])) { 6343 ++cind; 6344 continue; 6345 } 6346 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6347 } 6348 } else { 6349 for (b = 0; b < fdof; b++) { 6350 if ((cind < fcdof) && (b == fcdofs[cind])) { 6351 ++cind; 6352 continue; 6353 } 6354 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6355 } 6356 } 6357 } else { 6358 if (perm) { 6359 for (b = 0; b < fdof; b++) { 6360 if ((cind < fcdof) && (b == fcdofs[cind])) { 6361 ++cind; 6362 continue; 6363 } 6364 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6365 } 6366 } else { 6367 for (b = 0; b < fdof; b++) { 6368 if ((cind < fcdof) && (b == fcdofs[cind])) { 6369 ++cind; 6370 continue; 6371 } 6372 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6373 } 6374 } 6375 } 6376 } 6377 *offset += fdof; 6378 PetscFunctionReturn(PETSC_SUCCESS); 6379 } 6380 6381 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[]) 6382 { 6383 PetscScalar *a; 6384 PetscInt fdof, foff, fcdof, foffset = *offset; 6385 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6386 PetscInt Nc, cind = 0, ncind = 0, b; 6387 PetscBool ncSet, fcSet; 6388 6389 PetscFunctionBegin; 6390 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6391 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6392 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6393 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6394 a = &array[foff]; 6395 if (fcdof) { 6396 /* We just override fcdof and fcdofs with Ncc and comps */ 6397 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6398 if (clperm) { 6399 if (perm) { 6400 if (comps) { 6401 for (b = 0; b < fdof; b++) { 6402 ncSet = fcSet = PETSC_FALSE; 6403 if (b % Nc == comps[ncind]) { 6404 ncind = (ncind + 1) % Ncc; 6405 ncSet = PETSC_TRUE; 6406 } 6407 if ((cind < fcdof) && (b == fcdofs[cind])) { 6408 ++cind; 6409 fcSet = PETSC_TRUE; 6410 } 6411 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6412 } 6413 } else { 6414 for (b = 0; b < fdof; b++) { 6415 if ((cind < fcdof) && (b == fcdofs[cind])) { 6416 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6417 ++cind; 6418 } 6419 } 6420 } 6421 } else { 6422 if (comps) { 6423 for (b = 0; b < fdof; b++) { 6424 ncSet = fcSet = PETSC_FALSE; 6425 if (b % Nc == comps[ncind]) { 6426 ncind = (ncind + 1) % Ncc; 6427 ncSet = PETSC_TRUE; 6428 } 6429 if ((cind < fcdof) && (b == fcdofs[cind])) { 6430 ++cind; 6431 fcSet = PETSC_TRUE; 6432 } 6433 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6434 } 6435 } else { 6436 for (b = 0; b < fdof; b++) { 6437 if ((cind < fcdof) && (b == fcdofs[cind])) { 6438 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6439 ++cind; 6440 } 6441 } 6442 } 6443 } 6444 } else { 6445 if (perm) { 6446 if (comps) { 6447 for (b = 0; b < fdof; b++) { 6448 ncSet = fcSet = PETSC_FALSE; 6449 if (b % Nc == comps[ncind]) { 6450 ncind = (ncind + 1) % Ncc; 6451 ncSet = PETSC_TRUE; 6452 } 6453 if ((cind < fcdof) && (b == fcdofs[cind])) { 6454 ++cind; 6455 fcSet = PETSC_TRUE; 6456 } 6457 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6458 } 6459 } else { 6460 for (b = 0; b < fdof; b++) { 6461 if ((cind < fcdof) && (b == fcdofs[cind])) { 6462 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6463 ++cind; 6464 } 6465 } 6466 } 6467 } else { 6468 if (comps) { 6469 for (b = 0; b < fdof; b++) { 6470 ncSet = fcSet = PETSC_FALSE; 6471 if (b % Nc == comps[ncind]) { 6472 ncind = (ncind + 1) % Ncc; 6473 ncSet = PETSC_TRUE; 6474 } 6475 if ((cind < fcdof) && (b == fcdofs[cind])) { 6476 ++cind; 6477 fcSet = PETSC_TRUE; 6478 } 6479 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6480 } 6481 } else { 6482 for (b = 0; b < fdof; b++) { 6483 if ((cind < fcdof) && (b == fcdofs[cind])) { 6484 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6485 ++cind; 6486 } 6487 } 6488 } 6489 } 6490 } 6491 } 6492 *offset += fdof; 6493 PetscFunctionReturn(PETSC_SUCCESS); 6494 } 6495 6496 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6497 { 6498 PetscScalar *array; 6499 const PetscInt *cone, *coneO; 6500 PetscInt pStart, pEnd, p, numPoints, off, dof; 6501 6502 PetscFunctionBeginHot; 6503 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6504 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6505 PetscCall(DMPlexGetCone(dm, point, &cone)); 6506 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6507 PetscCall(VecGetArray(v, &array)); 6508 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6509 const PetscInt cp = !p ? point : cone[p - 1]; 6510 const PetscInt o = !p ? 0 : coneO[p - 1]; 6511 6512 if ((cp < pStart) || (cp >= pEnd)) { 6513 dof = 0; 6514 continue; 6515 } 6516 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6517 /* ADD_VALUES */ 6518 { 6519 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6520 PetscScalar *a; 6521 PetscInt cdof, coff, cind = 0, k; 6522 6523 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6524 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6525 a = &array[coff]; 6526 if (!cdof) { 6527 if (o >= 0) { 6528 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6529 } else { 6530 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6531 } 6532 } else { 6533 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6534 if (o >= 0) { 6535 for (k = 0; k < dof; ++k) { 6536 if ((cind < cdof) && (k == cdofs[cind])) { 6537 ++cind; 6538 continue; 6539 } 6540 a[k] += values[off + k]; 6541 } 6542 } else { 6543 for (k = 0; k < dof; ++k) { 6544 if ((cind < cdof) && (k == cdofs[cind])) { 6545 ++cind; 6546 continue; 6547 } 6548 a[k] += values[off + dof - k - 1]; 6549 } 6550 } 6551 } 6552 } 6553 } 6554 PetscCall(VecRestoreArray(v, &array)); 6555 PetscFunctionReturn(PETSC_SUCCESS); 6556 } 6557 6558 /*@C 6559 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6560 6561 Not collective 6562 6563 Input Parameters: 6564 + dm - The `DM` 6565 . section - The section describing the layout in v, or NULL to use the default section 6566 . v - The local vector 6567 . point - The point in the DM 6568 . values - The array of values 6569 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6570 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6571 6572 Level: intermediate 6573 6574 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6575 @*/ 6576 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6577 { 6578 PetscSection clSection; 6579 IS clPoints; 6580 PetscScalar *array; 6581 PetscInt *points = NULL; 6582 const PetscInt *clp, *clperm = NULL; 6583 PetscInt depth, numFields, numPoints, p, clsize; 6584 6585 PetscFunctionBeginHot; 6586 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6587 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6588 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6589 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6590 PetscCall(DMPlexGetDepth(dm, &depth)); 6591 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6592 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6593 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6594 PetscFunctionReturn(PETSC_SUCCESS); 6595 } 6596 /* Get points */ 6597 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6598 for (clsize = 0, p = 0; p < numPoints; p++) { 6599 PetscInt dof; 6600 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6601 clsize += dof; 6602 } 6603 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6604 /* Get array */ 6605 PetscCall(VecGetArray(v, &array)); 6606 /* Get values */ 6607 if (numFields > 0) { 6608 PetscInt offset = 0, f; 6609 for (f = 0; f < numFields; ++f) { 6610 const PetscInt **perms = NULL; 6611 const PetscScalar **flips = NULL; 6612 6613 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6614 switch (mode) { 6615 case INSERT_VALUES: 6616 for (p = 0; p < numPoints; p++) { 6617 const PetscInt point = points[2 * p]; 6618 const PetscInt *perm = perms ? perms[p] : NULL; 6619 const PetscScalar *flip = flips ? flips[p] : NULL; 6620 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6621 } 6622 break; 6623 case INSERT_ALL_VALUES: 6624 for (p = 0; p < numPoints; p++) { 6625 const PetscInt point = points[2 * p]; 6626 const PetscInt *perm = perms ? perms[p] : NULL; 6627 const PetscScalar *flip = flips ? flips[p] : NULL; 6628 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6629 } 6630 break; 6631 case INSERT_BC_VALUES: 6632 for (p = 0; p < numPoints; p++) { 6633 const PetscInt point = points[2 * p]; 6634 const PetscInt *perm = perms ? perms[p] : NULL; 6635 const PetscScalar *flip = flips ? flips[p] : NULL; 6636 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6637 } 6638 break; 6639 case ADD_VALUES: 6640 for (p = 0; p < numPoints; p++) { 6641 const PetscInt point = points[2 * p]; 6642 const PetscInt *perm = perms ? perms[p] : NULL; 6643 const PetscScalar *flip = flips ? flips[p] : NULL; 6644 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6645 } 6646 break; 6647 case ADD_ALL_VALUES: 6648 for (p = 0; p < numPoints; p++) { 6649 const PetscInt point = points[2 * p]; 6650 const PetscInt *perm = perms ? perms[p] : NULL; 6651 const PetscScalar *flip = flips ? flips[p] : NULL; 6652 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6653 } 6654 break; 6655 case ADD_BC_VALUES: 6656 for (p = 0; p < numPoints; p++) { 6657 const PetscInt point = points[2 * p]; 6658 const PetscInt *perm = perms ? perms[p] : NULL; 6659 const PetscScalar *flip = flips ? flips[p] : NULL; 6660 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6661 } 6662 break; 6663 default: 6664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6665 } 6666 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6667 } 6668 } else { 6669 PetscInt dof, off; 6670 const PetscInt **perms = NULL; 6671 const PetscScalar **flips = NULL; 6672 6673 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6674 switch (mode) { 6675 case INSERT_VALUES: 6676 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6677 const PetscInt point = points[2 * p]; 6678 const PetscInt *perm = perms ? perms[p] : NULL; 6679 const PetscScalar *flip = flips ? flips[p] : NULL; 6680 PetscCall(PetscSectionGetDof(section, point, &dof)); 6681 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6682 } 6683 break; 6684 case INSERT_ALL_VALUES: 6685 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6686 const PetscInt point = points[2 * p]; 6687 const PetscInt *perm = perms ? perms[p] : NULL; 6688 const PetscScalar *flip = flips ? flips[p] : NULL; 6689 PetscCall(PetscSectionGetDof(section, point, &dof)); 6690 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6691 } 6692 break; 6693 case INSERT_BC_VALUES: 6694 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6695 const PetscInt point = points[2 * p]; 6696 const PetscInt *perm = perms ? perms[p] : NULL; 6697 const PetscScalar *flip = flips ? flips[p] : NULL; 6698 PetscCall(PetscSectionGetDof(section, point, &dof)); 6699 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6700 } 6701 break; 6702 case ADD_VALUES: 6703 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6704 const PetscInt point = points[2 * p]; 6705 const PetscInt *perm = perms ? perms[p] : NULL; 6706 const PetscScalar *flip = flips ? flips[p] : NULL; 6707 PetscCall(PetscSectionGetDof(section, point, &dof)); 6708 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6709 } 6710 break; 6711 case ADD_ALL_VALUES: 6712 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6713 const PetscInt point = points[2 * p]; 6714 const PetscInt *perm = perms ? perms[p] : NULL; 6715 const PetscScalar *flip = flips ? flips[p] : NULL; 6716 PetscCall(PetscSectionGetDof(section, point, &dof)); 6717 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6718 } 6719 break; 6720 case ADD_BC_VALUES: 6721 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6722 const PetscInt point = points[2 * p]; 6723 const PetscInt *perm = perms ? perms[p] : NULL; 6724 const PetscScalar *flip = flips ? flips[p] : NULL; 6725 PetscCall(PetscSectionGetDof(section, point, &dof)); 6726 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6727 } 6728 break; 6729 default: 6730 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6731 } 6732 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6733 } 6734 /* Cleanup points */ 6735 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6736 /* Cleanup array */ 6737 PetscCall(VecRestoreArray(v, &array)); 6738 PetscFunctionReturn(PETSC_SUCCESS); 6739 } 6740 6741 PetscErrorCode DMPlexVecSetStar(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6742 { 6743 const PetscInt *supp, *cone; 6744 PetscScalar *a; 6745 PetscInt dim, Ns, dof, off, n = 0; 6746 6747 PetscFunctionBegin; 6748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6749 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6750 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6751 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6752 if (PetscDefined(USE_DEBUG)) { 6753 PetscInt vStart, vEnd; 6754 6755 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6756 PetscCheck(point >= vStart && point < vEnd, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " must be a vertex in [%" PetscInt_FMT ", %" PetscInt_FMT "]", point, vStart, vEnd); 6757 } 6758 PetscValidScalarPointer(values, 5); 6759 6760 PetscCall(DMGetDimension(dm, &dim)); 6761 PetscCall(DMPlexGetSupportSize(dm, point, &Ns)); 6762 PetscCall(DMPlexGetSupport(dm, point, &supp)); 6763 PetscCheck(Ns == 2 * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " has support size %" PetscInt_FMT " != %" PetscInt_FMT, point, Ns, 2 * dim); 6764 PetscCall(VecGetArray(v, &a)); 6765 PetscCall(PetscSectionGetDof(section, point, &dof)); 6766 PetscCall(PetscSectionGetOffset(section, point, &off)); 6767 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6768 for (PetscInt d = 0; d < dim; ++d) { 6769 // Left edge 6770 PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone)); 6771 PetscCall(PetscSectionGetDof(section, cone[0], &dof)); 6772 PetscCall(PetscSectionGetOffset(section, cone[0], &off)); 6773 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6774 // Right edge 6775 PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone)); 6776 PetscCall(PetscSectionGetDof(section, cone[1], &dof)); 6777 PetscCall(PetscSectionGetOffset(section, cone[1], &off)); 6778 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6779 } 6780 PetscCall(VecRestoreArray(v, &a)); 6781 PetscFunctionReturn(PETSC_SUCCESS); 6782 } 6783 6784 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6785 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6786 { 6787 PetscFunctionBegin; 6788 *contains = PETSC_TRUE; 6789 if (label) { 6790 PetscInt fdof; 6791 6792 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6793 if (!*contains) { 6794 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6795 *offset += fdof; 6796 PetscFunctionReturn(PETSC_SUCCESS); 6797 } 6798 } 6799 PetscFunctionReturn(PETSC_SUCCESS); 6800 } 6801 6802 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6803 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) 6804 { 6805 PetscSection clSection; 6806 IS clPoints; 6807 PetscScalar *array; 6808 PetscInt *points = NULL; 6809 const PetscInt *clp; 6810 PetscInt numFields, numPoints, p; 6811 PetscInt offset = 0, f; 6812 6813 PetscFunctionBeginHot; 6814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6815 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6816 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6817 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6818 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6819 /* Get points */ 6820 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6821 /* Get array */ 6822 PetscCall(VecGetArray(v, &array)); 6823 /* Get values */ 6824 for (f = 0; f < numFields; ++f) { 6825 const PetscInt **perms = NULL; 6826 const PetscScalar **flips = NULL; 6827 PetscBool contains; 6828 6829 if (!fieldActive[f]) { 6830 for (p = 0; p < numPoints * 2; p += 2) { 6831 PetscInt fdof; 6832 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6833 offset += fdof; 6834 } 6835 continue; 6836 } 6837 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6838 switch (mode) { 6839 case INSERT_VALUES: 6840 for (p = 0; p < numPoints; p++) { 6841 const PetscInt point = points[2 * p]; 6842 const PetscInt *perm = perms ? perms[p] : NULL; 6843 const PetscScalar *flip = flips ? flips[p] : NULL; 6844 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6845 if (!contains) continue; 6846 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6847 } 6848 break; 6849 case INSERT_ALL_VALUES: 6850 for (p = 0; p < numPoints; p++) { 6851 const PetscInt point = points[2 * p]; 6852 const PetscInt *perm = perms ? perms[p] : NULL; 6853 const PetscScalar *flip = flips ? flips[p] : NULL; 6854 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6855 if (!contains) continue; 6856 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6857 } 6858 break; 6859 case INSERT_BC_VALUES: 6860 for (p = 0; p < numPoints; p++) { 6861 const PetscInt point = points[2 * p]; 6862 const PetscInt *perm = perms ? perms[p] : NULL; 6863 const PetscScalar *flip = flips ? flips[p] : NULL; 6864 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6865 if (!contains) continue; 6866 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6867 } 6868 break; 6869 case ADD_VALUES: 6870 for (p = 0; p < numPoints; p++) { 6871 const PetscInt point = points[2 * p]; 6872 const PetscInt *perm = perms ? perms[p] : NULL; 6873 const PetscScalar *flip = flips ? flips[p] : NULL; 6874 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6875 if (!contains) continue; 6876 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6877 } 6878 break; 6879 case ADD_ALL_VALUES: 6880 for (p = 0; p < numPoints; p++) { 6881 const PetscInt point = points[2 * p]; 6882 const PetscInt *perm = perms ? perms[p] : NULL; 6883 const PetscScalar *flip = flips ? flips[p] : NULL; 6884 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6885 if (!contains) continue; 6886 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6887 } 6888 break; 6889 default: 6890 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6891 } 6892 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6893 } 6894 /* Cleanup points */ 6895 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6896 /* Cleanup array */ 6897 PetscCall(VecRestoreArray(v, &array)); 6898 PetscFunctionReturn(PETSC_SUCCESS); 6899 } 6900 6901 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6902 { 6903 PetscMPIInt rank; 6904 PetscInt i, j; 6905 6906 PetscFunctionBegin; 6907 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6908 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6909 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6910 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6911 numCIndices = numCIndices ? numCIndices : numRIndices; 6912 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6913 for (i = 0; i < numRIndices; i++) { 6914 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6915 for (j = 0; j < numCIndices; j++) { 6916 #if defined(PETSC_USE_COMPLEX) 6917 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6918 #else 6919 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6920 #endif 6921 } 6922 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6923 } 6924 PetscFunctionReturn(PETSC_SUCCESS); 6925 } 6926 6927 /* 6928 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6929 6930 Input Parameters: 6931 + section - The section for this data layout 6932 . islocal - Is the section (and thus indices being requested) local or global? 6933 . point - The point contributing dofs with these indices 6934 . off - The global offset of this point 6935 . loff - The local offset of each field 6936 . setBC - The flag determining whether to include indices of boundary values 6937 . perm - A permutation of the dofs on this point, or NULL 6938 - indperm - A permutation of the entire indices array, or NULL 6939 6940 Output Parameter: 6941 . indices - Indices for dofs on this point 6942 6943 Level: developer 6944 6945 Note: The indices could be local or global, depending on the value of 'off'. 6946 */ 6947 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6948 { 6949 PetscInt dof; /* The number of unknowns on this point */ 6950 PetscInt cdof; /* The number of constraints on this point */ 6951 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6952 PetscInt cind = 0, k; 6953 6954 PetscFunctionBegin; 6955 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6956 PetscCall(PetscSectionGetDof(section, point, &dof)); 6957 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6958 if (!cdof || setBC) { 6959 for (k = 0; k < dof; ++k) { 6960 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6961 const PetscInt ind = indperm ? indperm[preind] : preind; 6962 6963 indices[ind] = off + k; 6964 } 6965 } else { 6966 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6967 for (k = 0; k < dof; ++k) { 6968 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6969 const PetscInt ind = indperm ? indperm[preind] : preind; 6970 6971 if ((cind < cdof) && (k == cdofs[cind])) { 6972 /* Insert check for returning constrained indices */ 6973 indices[ind] = -(off + k + 1); 6974 ++cind; 6975 } else { 6976 indices[ind] = off + k - (islocal ? 0 : cind); 6977 } 6978 } 6979 } 6980 *loff += dof; 6981 PetscFunctionReturn(PETSC_SUCCESS); 6982 } 6983 6984 /* 6985 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6986 6987 Input Parameters: 6988 + section - a section (global or local) 6989 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6990 . point - point within section 6991 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6992 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6993 . setBC - identify constrained (boundary condition) points via involution. 6994 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6995 . permsoff - offset 6996 - indperm - index permutation 6997 6998 Output Parameter: 6999 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7000 . indices - array to hold indices (as defined by section) of each dof associated with point 7001 7002 Notes: 7003 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7004 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7005 in the local vector. 7006 7007 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7008 significant). It is invalid to call with a global section and setBC=true. 7009 7010 Developer Note: 7011 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7012 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7013 offset could be obtained from the section instead of passing it explicitly as we do now. 7014 7015 Example: 7016 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7017 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7018 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7019 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. 7020 7021 Level: developer 7022 */ 7023 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[]) 7024 { 7025 PetscInt numFields, foff, f; 7026 7027 PetscFunctionBegin; 7028 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7029 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7030 for (f = 0, foff = 0; f < numFields; ++f) { 7031 PetscInt fdof, cfdof; 7032 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7033 PetscInt cind = 0, b; 7034 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7035 7036 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7037 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7038 if (!cfdof || setBC) { 7039 for (b = 0; b < fdof; ++b) { 7040 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7041 const PetscInt ind = indperm ? indperm[preind] : preind; 7042 7043 indices[ind] = off + foff + b; 7044 } 7045 } else { 7046 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7047 for (b = 0; b < fdof; ++b) { 7048 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7049 const PetscInt ind = indperm ? indperm[preind] : preind; 7050 7051 if ((cind < cfdof) && (b == fcdofs[cind])) { 7052 indices[ind] = -(off + foff + b + 1); 7053 ++cind; 7054 } else { 7055 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7056 } 7057 } 7058 } 7059 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7060 foffs[f] += fdof; 7061 } 7062 PetscFunctionReturn(PETSC_SUCCESS); 7063 } 7064 7065 /* 7066 This version believes the globalSection offsets for each field, rather than just the point offset 7067 7068 . foffs - The offset into 'indices' for each field, since it is segregated by field 7069 7070 Notes: 7071 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7072 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7073 */ 7074 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7075 { 7076 PetscInt numFields, foff, f; 7077 7078 PetscFunctionBegin; 7079 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7080 for (f = 0; f < numFields; ++f) { 7081 PetscInt fdof, cfdof; 7082 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7083 PetscInt cind = 0, b; 7084 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7085 7086 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7087 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7088 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7089 if (!cfdof) { 7090 for (b = 0; b < fdof; ++b) { 7091 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7092 const PetscInt ind = indperm ? indperm[preind] : preind; 7093 7094 indices[ind] = foff + b; 7095 } 7096 } else { 7097 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7098 for (b = 0; b < fdof; ++b) { 7099 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7100 const PetscInt ind = indperm ? indperm[preind] : preind; 7101 7102 if ((cind < cfdof) && (b == fcdofs[cind])) { 7103 indices[ind] = -(foff + b + 1); 7104 ++cind; 7105 } else { 7106 indices[ind] = foff + b - cind; 7107 } 7108 } 7109 } 7110 foffs[f] += fdof; 7111 } 7112 PetscFunctionReturn(PETSC_SUCCESS); 7113 } 7114 7115 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) 7116 { 7117 Mat cMat; 7118 PetscSection aSec, cSec; 7119 IS aIS; 7120 PetscInt aStart = -1, aEnd = -1; 7121 const PetscInt *anchors; 7122 PetscInt numFields, f, p, q, newP = 0; 7123 PetscInt newNumPoints = 0, newNumIndices = 0; 7124 PetscInt *newPoints, *indices, *newIndices; 7125 PetscInt maxAnchor, maxDof; 7126 PetscInt newOffsets[32]; 7127 PetscInt *pointMatOffsets[32]; 7128 PetscInt *newPointOffsets[32]; 7129 PetscScalar *pointMat[32]; 7130 PetscScalar *newValues = NULL, *tmpValues; 7131 PetscBool anyConstrained = PETSC_FALSE; 7132 7133 PetscFunctionBegin; 7134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7135 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7136 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7137 7138 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7139 /* if there are point-to-point constraints */ 7140 if (aSec) { 7141 PetscCall(PetscArrayzero(newOffsets, 32)); 7142 PetscCall(ISGetIndices(aIS, &anchors)); 7143 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7144 /* figure out how many points are going to be in the new element matrix 7145 * (we allow double counting, because it's all just going to be summed 7146 * into the global matrix anyway) */ 7147 for (p = 0; p < 2 * numPoints; p += 2) { 7148 PetscInt b = points[p]; 7149 PetscInt bDof = 0, bSecDof; 7150 7151 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7152 if (!bSecDof) continue; 7153 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7154 if (bDof) { 7155 /* this point is constrained */ 7156 /* it is going to be replaced by its anchors */ 7157 PetscInt bOff, q; 7158 7159 anyConstrained = PETSC_TRUE; 7160 newNumPoints += bDof; 7161 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7162 for (q = 0; q < bDof; q++) { 7163 PetscInt a = anchors[bOff + q]; 7164 PetscInt aDof; 7165 7166 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7167 newNumIndices += aDof; 7168 for (f = 0; f < numFields; ++f) { 7169 PetscInt fDof; 7170 7171 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7172 newOffsets[f + 1] += fDof; 7173 } 7174 } 7175 } else { 7176 /* this point is not constrained */ 7177 newNumPoints++; 7178 newNumIndices += bSecDof; 7179 for (f = 0; f < numFields; ++f) { 7180 PetscInt fDof; 7181 7182 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7183 newOffsets[f + 1] += fDof; 7184 } 7185 } 7186 } 7187 } 7188 if (!anyConstrained) { 7189 if (outNumPoints) *outNumPoints = 0; 7190 if (outNumIndices) *outNumIndices = 0; 7191 if (outPoints) *outPoints = NULL; 7192 if (outValues) *outValues = NULL; 7193 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7194 PetscFunctionReturn(PETSC_SUCCESS); 7195 } 7196 7197 if (outNumPoints) *outNumPoints = newNumPoints; 7198 if (outNumIndices) *outNumIndices = newNumIndices; 7199 7200 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7201 7202 if (!outPoints && !outValues) { 7203 if (offsets) { 7204 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7205 } 7206 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7207 PetscFunctionReturn(PETSC_SUCCESS); 7208 } 7209 7210 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7211 7212 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7213 7214 /* workspaces */ 7215 if (numFields) { 7216 for (f = 0; f < numFields; f++) { 7217 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7218 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7219 } 7220 } else { 7221 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7222 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7223 } 7224 7225 /* get workspaces for the point-to-point matrices */ 7226 if (numFields) { 7227 PetscInt totalOffset, totalMatOffset; 7228 7229 for (p = 0; p < numPoints; p++) { 7230 PetscInt b = points[2 * p]; 7231 PetscInt bDof = 0, bSecDof; 7232 7233 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7234 if (!bSecDof) { 7235 for (f = 0; f < numFields; f++) { 7236 newPointOffsets[f][p + 1] = 0; 7237 pointMatOffsets[f][p + 1] = 0; 7238 } 7239 continue; 7240 } 7241 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7242 if (bDof) { 7243 for (f = 0; f < numFields; f++) { 7244 PetscInt fDof, q, bOff, allFDof = 0; 7245 7246 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7247 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7248 for (q = 0; q < bDof; q++) { 7249 PetscInt a = anchors[bOff + q]; 7250 PetscInt aFDof; 7251 7252 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7253 allFDof += aFDof; 7254 } 7255 newPointOffsets[f][p + 1] = allFDof; 7256 pointMatOffsets[f][p + 1] = fDof * allFDof; 7257 } 7258 } else { 7259 for (f = 0; f < numFields; f++) { 7260 PetscInt fDof; 7261 7262 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7263 newPointOffsets[f][p + 1] = fDof; 7264 pointMatOffsets[f][p + 1] = 0; 7265 } 7266 } 7267 } 7268 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7269 newPointOffsets[f][0] = totalOffset; 7270 pointMatOffsets[f][0] = totalMatOffset; 7271 for (p = 0; p < numPoints; p++) { 7272 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7273 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7274 } 7275 totalOffset = newPointOffsets[f][numPoints]; 7276 totalMatOffset = pointMatOffsets[f][numPoints]; 7277 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7278 } 7279 } else { 7280 for (p = 0; p < numPoints; p++) { 7281 PetscInt b = points[2 * p]; 7282 PetscInt bDof = 0, bSecDof; 7283 7284 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7285 if (!bSecDof) { 7286 newPointOffsets[0][p + 1] = 0; 7287 pointMatOffsets[0][p + 1] = 0; 7288 continue; 7289 } 7290 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7291 if (bDof) { 7292 PetscInt bOff, q, allDof = 0; 7293 7294 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7295 for (q = 0; q < bDof; q++) { 7296 PetscInt a = anchors[bOff + q], aDof; 7297 7298 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7299 allDof += aDof; 7300 } 7301 newPointOffsets[0][p + 1] = allDof; 7302 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7303 } else { 7304 newPointOffsets[0][p + 1] = bSecDof; 7305 pointMatOffsets[0][p + 1] = 0; 7306 } 7307 } 7308 newPointOffsets[0][0] = 0; 7309 pointMatOffsets[0][0] = 0; 7310 for (p = 0; p < numPoints; p++) { 7311 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7312 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7313 } 7314 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7315 } 7316 7317 /* output arrays */ 7318 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7319 7320 /* get the point-to-point matrices; construct newPoints */ 7321 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7322 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7323 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7324 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7325 if (numFields) { 7326 for (p = 0, newP = 0; p < numPoints; p++) { 7327 PetscInt b = points[2 * p]; 7328 PetscInt o = points[2 * p + 1]; 7329 PetscInt bDof = 0, bSecDof; 7330 7331 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7332 if (!bSecDof) continue; 7333 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7334 if (bDof) { 7335 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7336 7337 fStart[0] = 0; 7338 fEnd[0] = 0; 7339 for (f = 0; f < numFields; f++) { 7340 PetscInt fDof; 7341 7342 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7343 fStart[f + 1] = fStart[f] + fDof; 7344 fEnd[f + 1] = fStart[f + 1]; 7345 } 7346 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7347 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7348 7349 fAnchorStart[0] = 0; 7350 fAnchorEnd[0] = 0; 7351 for (f = 0; f < numFields; f++) { 7352 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7353 7354 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7355 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7356 } 7357 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7358 for (q = 0; q < bDof; q++) { 7359 PetscInt a = anchors[bOff + q], aOff; 7360 7361 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7362 newPoints[2 * (newP + q)] = a; 7363 newPoints[2 * (newP + q) + 1] = 0; 7364 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7365 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7366 } 7367 newP += bDof; 7368 7369 if (outValues) { 7370 /* get the point-to-point submatrix */ 7371 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])); 7372 } 7373 } else { 7374 newPoints[2 * newP] = b; 7375 newPoints[2 * newP + 1] = o; 7376 newP++; 7377 } 7378 } 7379 } else { 7380 for (p = 0; p < numPoints; p++) { 7381 PetscInt b = points[2 * p]; 7382 PetscInt o = points[2 * p + 1]; 7383 PetscInt bDof = 0, bSecDof; 7384 7385 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7386 if (!bSecDof) continue; 7387 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7388 if (bDof) { 7389 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7390 7391 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7392 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7393 7394 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7395 for (q = 0; q < bDof; q++) { 7396 PetscInt a = anchors[bOff + q], aOff; 7397 7398 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7399 7400 newPoints[2 * (newP + q)] = a; 7401 newPoints[2 * (newP + q) + 1] = 0; 7402 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7403 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7404 } 7405 newP += bDof; 7406 7407 /* get the point-to-point submatrix */ 7408 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7409 } else { 7410 newPoints[2 * newP] = b; 7411 newPoints[2 * newP + 1] = o; 7412 newP++; 7413 } 7414 } 7415 } 7416 7417 if (outValues) { 7418 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7419 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7420 /* multiply constraints on the right */ 7421 if (numFields) { 7422 for (f = 0; f < numFields; f++) { 7423 PetscInt oldOff = offsets[f]; 7424 7425 for (p = 0; p < numPoints; p++) { 7426 PetscInt cStart = newPointOffsets[f][p]; 7427 PetscInt b = points[2 * p]; 7428 PetscInt c, r, k; 7429 PetscInt dof; 7430 7431 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7432 if (!dof) continue; 7433 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7434 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7435 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7436 7437 for (r = 0; r < numIndices; r++) { 7438 for (c = 0; c < nCols; c++) { 7439 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7440 } 7441 } 7442 } else { 7443 /* copy this column as is */ 7444 for (r = 0; r < numIndices; r++) { 7445 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7446 } 7447 } 7448 oldOff += dof; 7449 } 7450 } 7451 } else { 7452 PetscInt oldOff = 0; 7453 for (p = 0; p < numPoints; p++) { 7454 PetscInt cStart = newPointOffsets[0][p]; 7455 PetscInt b = points[2 * p]; 7456 PetscInt c, r, k; 7457 PetscInt dof; 7458 7459 PetscCall(PetscSectionGetDof(section, b, &dof)); 7460 if (!dof) continue; 7461 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7462 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7463 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7464 7465 for (r = 0; r < numIndices; r++) { 7466 for (c = 0; c < nCols; c++) { 7467 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7468 } 7469 } 7470 } else { 7471 /* copy this column as is */ 7472 for (r = 0; r < numIndices; r++) { 7473 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7474 } 7475 } 7476 oldOff += dof; 7477 } 7478 } 7479 7480 if (multiplyLeft) { 7481 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7482 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7483 /* multiply constraints transpose on the left */ 7484 if (numFields) { 7485 for (f = 0; f < numFields; f++) { 7486 PetscInt oldOff = offsets[f]; 7487 7488 for (p = 0; p < numPoints; p++) { 7489 PetscInt rStart = newPointOffsets[f][p]; 7490 PetscInt b = points[2 * p]; 7491 PetscInt c, r, k; 7492 PetscInt dof; 7493 7494 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7495 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7496 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7497 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7498 7499 for (r = 0; r < nRows; r++) { 7500 for (c = 0; c < newNumIndices; c++) { 7501 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7502 } 7503 } 7504 } else { 7505 /* copy this row as is */ 7506 for (r = 0; r < dof; r++) { 7507 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7508 } 7509 } 7510 oldOff += dof; 7511 } 7512 } 7513 } else { 7514 PetscInt oldOff = 0; 7515 7516 for (p = 0; p < numPoints; p++) { 7517 PetscInt rStart = newPointOffsets[0][p]; 7518 PetscInt b = points[2 * p]; 7519 PetscInt c, r, k; 7520 PetscInt dof; 7521 7522 PetscCall(PetscSectionGetDof(section, b, &dof)); 7523 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7524 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7525 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7526 7527 for (r = 0; r < nRows; r++) { 7528 for (c = 0; c < newNumIndices; c++) { 7529 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7530 } 7531 } 7532 } else { 7533 /* copy this row as is */ 7534 for (r = 0; r < dof; r++) { 7535 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7536 } 7537 } 7538 oldOff += dof; 7539 } 7540 } 7541 7542 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7543 } else { 7544 newValues = tmpValues; 7545 } 7546 } 7547 7548 /* clean up */ 7549 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7550 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7551 7552 if (numFields) { 7553 for (f = 0; f < numFields; f++) { 7554 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7555 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7556 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7557 } 7558 } else { 7559 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7560 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7561 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7562 } 7563 PetscCall(ISRestoreIndices(aIS, &anchors)); 7564 7565 /* output */ 7566 if (outPoints) { 7567 *outPoints = newPoints; 7568 } else { 7569 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7570 } 7571 if (outValues) *outValues = newValues; 7572 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7573 PetscFunctionReturn(PETSC_SUCCESS); 7574 } 7575 7576 /*@C 7577 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7578 7579 Not collective 7580 7581 Input Parameters: 7582 + dm - The `DM` 7583 . section - The `PetscSection` describing the points (a local section) 7584 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7585 . point - The point defining the closure 7586 - useClPerm - Use the closure point permutation if available 7587 7588 Output Parameters: 7589 + numIndices - The number of dof indices in the closure of point with the input sections 7590 . indices - The dof indices 7591 . outOffsets - Array to write the field offsets into, or NULL 7592 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7593 7594 Level: advanced 7595 7596 Notes: 7597 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7598 7599 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7600 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7601 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7602 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7603 indices (with the above semantics) are implied. 7604 7605 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7606 `PetscSection`, `DMGetGlobalSection()` 7607 @*/ 7608 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7609 { 7610 /* Closure ordering */ 7611 PetscSection clSection; 7612 IS clPoints; 7613 const PetscInt *clp; 7614 PetscInt *points; 7615 const PetscInt *clperm = NULL; 7616 /* Dof permutation and sign flips */ 7617 const PetscInt **perms[32] = {NULL}; 7618 const PetscScalar **flips[32] = {NULL}; 7619 PetscScalar *valCopy = NULL; 7620 /* Hanging node constraints */ 7621 PetscInt *pointsC = NULL; 7622 PetscScalar *valuesC = NULL; 7623 PetscInt NclC, NiC; 7624 7625 PetscInt *idx; 7626 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7627 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7628 7629 PetscFunctionBeginHot; 7630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7631 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7632 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7633 if (numIndices) PetscValidIntPointer(numIndices, 6); 7634 if (indices) PetscValidPointer(indices, 7); 7635 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7636 if (values) PetscValidPointer(values, 9); 7637 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7638 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7639 PetscCall(PetscArrayzero(offsets, 32)); 7640 /* 1) Get points in closure */ 7641 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7642 if (useClPerm) { 7643 PetscInt depth, clsize; 7644 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7645 for (clsize = 0, p = 0; p < Ncl; p++) { 7646 PetscInt dof; 7647 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7648 clsize += dof; 7649 } 7650 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7651 } 7652 /* 2) Get number of indices on these points and field offsets from section */ 7653 for (p = 0; p < Ncl * 2; p += 2) { 7654 PetscInt dof, fdof; 7655 7656 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7657 for (f = 0; f < Nf; ++f) { 7658 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7659 offsets[f + 1] += fdof; 7660 } 7661 Ni += dof; 7662 } 7663 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7664 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7665 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7666 for (f = 0; f < PetscMax(1, Nf); ++f) { 7667 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7668 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7669 /* may need to apply sign changes to the element matrix */ 7670 if (values && flips[f]) { 7671 PetscInt foffset = offsets[f]; 7672 7673 for (p = 0; p < Ncl; ++p) { 7674 PetscInt pnt = points[2 * p], fdof; 7675 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7676 7677 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7678 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7679 if (flip) { 7680 PetscInt i, j, k; 7681 7682 if (!valCopy) { 7683 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7684 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7685 *values = valCopy; 7686 } 7687 for (i = 0; i < fdof; ++i) { 7688 PetscScalar fval = flip[i]; 7689 7690 for (k = 0; k < Ni; ++k) { 7691 valCopy[Ni * (foffset + i) + k] *= fval; 7692 valCopy[Ni * k + (foffset + i)] *= fval; 7693 } 7694 } 7695 } 7696 foffset += fdof; 7697 } 7698 } 7699 } 7700 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7701 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7702 if (NclC) { 7703 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7704 for (f = 0; f < PetscMax(1, Nf); ++f) { 7705 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7706 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7707 } 7708 for (f = 0; f < PetscMax(1, Nf); ++f) { 7709 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7710 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7711 } 7712 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7713 Ncl = NclC; 7714 Ni = NiC; 7715 points = pointsC; 7716 if (values) *values = valuesC; 7717 } 7718 /* 5) Calculate indices */ 7719 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7720 if (Nf) { 7721 PetscInt idxOff; 7722 PetscBool useFieldOffsets; 7723 7724 if (outOffsets) { 7725 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7726 } 7727 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7728 if (useFieldOffsets) { 7729 for (p = 0; p < Ncl; ++p) { 7730 const PetscInt pnt = points[p * 2]; 7731 7732 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7733 } 7734 } else { 7735 for (p = 0; p < Ncl; ++p) { 7736 const PetscInt pnt = points[p * 2]; 7737 7738 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7739 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7740 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7741 * global section. */ 7742 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7743 } 7744 } 7745 } else { 7746 PetscInt off = 0, idxOff; 7747 7748 for (p = 0; p < Ncl; ++p) { 7749 const PetscInt pnt = points[p * 2]; 7750 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7751 7752 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7753 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7754 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7755 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7756 } 7757 } 7758 /* 6) Cleanup */ 7759 for (f = 0; f < PetscMax(1, Nf); ++f) { 7760 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7761 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7762 } 7763 if (NclC) { 7764 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7765 } else { 7766 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7767 } 7768 7769 if (numIndices) *numIndices = Ni; 7770 if (indices) *indices = idx; 7771 PetscFunctionReturn(PETSC_SUCCESS); 7772 } 7773 7774 /*@C 7775 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7776 7777 Not collective 7778 7779 Input Parameters: 7780 + dm - The `DM` 7781 . section - The `PetscSection` describing the points (a local section) 7782 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7783 . point - The point defining the closure 7784 - useClPerm - Use the closure point permutation if available 7785 7786 Output Parameters: 7787 + numIndices - The number of dof indices in the closure of point with the input sections 7788 . indices - The dof indices 7789 . outOffsets - Array to write the field offsets into, or NULL 7790 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7791 7792 Level: advanced 7793 7794 Notes: 7795 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7796 7797 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7798 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7799 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7800 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7801 indices (with the above semantics) are implied. 7802 7803 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7804 @*/ 7805 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7806 { 7807 PetscFunctionBegin; 7808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7809 PetscValidPointer(indices, 7); 7810 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7811 PetscFunctionReturn(PETSC_SUCCESS); 7812 } 7813 7814 /*@C 7815 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7816 7817 Not collective 7818 7819 Input Parameters: 7820 + dm - The `DM` 7821 . section - The section describing the layout in v, or NULL to use the default section 7822 . globalSection - The section describing the layout in v, or NULL to use the default global section 7823 . A - The matrix 7824 . point - The point in the `DM` 7825 . values - The array of values 7826 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7827 7828 Level: intermediate 7829 7830 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7831 @*/ 7832 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7833 { 7834 DM_Plex *mesh = (DM_Plex *)dm->data; 7835 PetscInt *indices; 7836 PetscInt numIndices; 7837 const PetscScalar *valuesOrig = values; 7838 PetscErrorCode ierr; 7839 7840 PetscFunctionBegin; 7841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7842 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7843 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7844 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7845 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7846 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7847 7848 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7849 7850 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7851 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7852 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7853 if (ierr) { 7854 PetscMPIInt rank; 7855 7856 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7857 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7858 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7859 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7860 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7861 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7862 } 7863 if (mesh->printFEM > 1) { 7864 PetscInt i; 7865 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7866 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7867 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7868 } 7869 7870 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7871 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7872 PetscFunctionReturn(PETSC_SUCCESS); 7873 } 7874 7875 /*@C 7876 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7877 7878 Not collective 7879 7880 Input Parameters: 7881 + dmRow - The `DM` for the row fields 7882 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7883 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7884 . dmCol - The `DM` for the column fields 7885 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7886 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7887 . A - The matrix 7888 . point - The point in the `DM` 7889 . values - The array of values 7890 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7891 7892 Level: intermediate 7893 7894 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7895 @*/ 7896 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7897 { 7898 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7899 PetscInt *indicesRow, *indicesCol; 7900 PetscInt numIndicesRow, numIndicesCol; 7901 const PetscScalar *valuesOrig = values; 7902 PetscErrorCode ierr; 7903 7904 PetscFunctionBegin; 7905 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7906 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7907 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7908 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7909 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7910 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7911 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7912 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7913 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7914 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7915 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7916 7917 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7918 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7919 7920 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7921 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7922 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7923 if (ierr) { 7924 PetscMPIInt rank; 7925 7926 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7927 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7928 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7929 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7930 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7931 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7932 } 7933 7934 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7935 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7936 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7937 PetscFunctionReturn(PETSC_SUCCESS); 7938 } 7939 7940 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7941 { 7942 DM_Plex *mesh = (DM_Plex *)dmf->data; 7943 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7944 PetscInt *cpoints = NULL; 7945 PetscInt *findices, *cindices; 7946 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7947 PetscInt foffsets[32], coffsets[32]; 7948 DMPolytopeType ct; 7949 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7950 PetscErrorCode ierr; 7951 7952 PetscFunctionBegin; 7953 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7954 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7955 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7956 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7957 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7958 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7959 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7960 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7961 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7962 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7963 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7964 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7965 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7966 PetscCall(PetscArrayzero(foffsets, 32)); 7967 PetscCall(PetscArrayzero(coffsets, 32)); 7968 /* Column indices */ 7969 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7970 maxFPoints = numCPoints; 7971 /* Compress out points not in the section */ 7972 /* TODO: Squeeze out points with 0 dof as well */ 7973 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7974 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7975 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7976 cpoints[q * 2] = cpoints[p]; 7977 cpoints[q * 2 + 1] = cpoints[p + 1]; 7978 ++q; 7979 } 7980 } 7981 numCPoints = q; 7982 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7983 PetscInt fdof; 7984 7985 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7986 if (!dof) continue; 7987 for (f = 0; f < numFields; ++f) { 7988 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7989 coffsets[f + 1] += fdof; 7990 } 7991 numCIndices += dof; 7992 } 7993 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7994 /* Row indices */ 7995 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7996 { 7997 DMPlexTransform tr; 7998 DMPolytopeType *rct; 7999 PetscInt *rsize, *rcone, *rornt, Nt; 8000 8001 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8002 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8003 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8004 numSubcells = rsize[Nt - 1]; 8005 PetscCall(DMPlexTransformDestroy(&tr)); 8006 } 8007 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8008 for (r = 0, q = 0; r < numSubcells; ++r) { 8009 /* TODO Map from coarse to fine cells */ 8010 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8011 /* Compress out points not in the section */ 8012 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8013 for (p = 0; p < numFPoints * 2; p += 2) { 8014 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8015 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8016 if (!dof) continue; 8017 for (s = 0; s < q; ++s) 8018 if (fpoints[p] == ftotpoints[s * 2]) break; 8019 if (s < q) continue; 8020 ftotpoints[q * 2] = fpoints[p]; 8021 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8022 ++q; 8023 } 8024 } 8025 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8026 } 8027 numFPoints = q; 8028 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8029 PetscInt fdof; 8030 8031 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8032 if (!dof) continue; 8033 for (f = 0; f < numFields; ++f) { 8034 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8035 foffsets[f + 1] += fdof; 8036 } 8037 numFIndices += dof; 8038 } 8039 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8040 8041 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8042 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8043 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8044 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8045 if (numFields) { 8046 const PetscInt **permsF[32] = {NULL}; 8047 const PetscInt **permsC[32] = {NULL}; 8048 8049 for (f = 0; f < numFields; f++) { 8050 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8051 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8052 } 8053 for (p = 0; p < numFPoints; p++) { 8054 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8055 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8056 } 8057 for (p = 0; p < numCPoints; p++) { 8058 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8059 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8060 } 8061 for (f = 0; f < numFields; f++) { 8062 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8063 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8064 } 8065 } else { 8066 const PetscInt **permsF = NULL; 8067 const PetscInt **permsC = NULL; 8068 8069 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8070 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8071 for (p = 0, off = 0; p < numFPoints; p++) { 8072 const PetscInt *perm = permsF ? permsF[p] : NULL; 8073 8074 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8075 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8076 } 8077 for (p = 0, off = 0; p < numCPoints; p++) { 8078 const PetscInt *perm = permsC ? permsC[p] : NULL; 8079 8080 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8081 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8082 } 8083 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8084 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8085 } 8086 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8087 /* TODO: flips */ 8088 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8089 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8090 if (ierr) { 8091 PetscMPIInt rank; 8092 8093 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8094 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8095 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8096 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8097 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8098 } 8099 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8100 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8101 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8102 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8103 PetscFunctionReturn(PETSC_SUCCESS); 8104 } 8105 8106 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8107 { 8108 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8109 PetscInt *cpoints = NULL; 8110 PetscInt foffsets[32], coffsets[32]; 8111 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8112 DMPolytopeType ct; 8113 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8114 8115 PetscFunctionBegin; 8116 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8117 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8118 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8119 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8120 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8121 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8122 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8123 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8124 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8125 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8126 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8127 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8128 PetscCall(PetscArrayzero(foffsets, 32)); 8129 PetscCall(PetscArrayzero(coffsets, 32)); 8130 /* Column indices */ 8131 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8132 maxFPoints = numCPoints; 8133 /* Compress out points not in the section */ 8134 /* TODO: Squeeze out points with 0 dof as well */ 8135 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8136 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8137 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8138 cpoints[q * 2] = cpoints[p]; 8139 cpoints[q * 2 + 1] = cpoints[p + 1]; 8140 ++q; 8141 } 8142 } 8143 numCPoints = q; 8144 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8145 PetscInt fdof; 8146 8147 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8148 if (!dof) continue; 8149 for (f = 0; f < numFields; ++f) { 8150 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8151 coffsets[f + 1] += fdof; 8152 } 8153 numCIndices += dof; 8154 } 8155 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8156 /* Row indices */ 8157 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8158 { 8159 DMPlexTransform tr; 8160 DMPolytopeType *rct; 8161 PetscInt *rsize, *rcone, *rornt, Nt; 8162 8163 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8164 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8165 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8166 numSubcells = rsize[Nt - 1]; 8167 PetscCall(DMPlexTransformDestroy(&tr)); 8168 } 8169 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8170 for (r = 0, q = 0; r < numSubcells; ++r) { 8171 /* TODO Map from coarse to fine cells */ 8172 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8173 /* Compress out points not in the section */ 8174 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8175 for (p = 0; p < numFPoints * 2; p += 2) { 8176 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8177 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8178 if (!dof) continue; 8179 for (s = 0; s < q; ++s) 8180 if (fpoints[p] == ftotpoints[s * 2]) break; 8181 if (s < q) continue; 8182 ftotpoints[q * 2] = fpoints[p]; 8183 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8184 ++q; 8185 } 8186 } 8187 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8188 } 8189 numFPoints = q; 8190 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8191 PetscInt fdof; 8192 8193 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8194 if (!dof) continue; 8195 for (f = 0; f < numFields; ++f) { 8196 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8197 foffsets[f + 1] += fdof; 8198 } 8199 numFIndices += dof; 8200 } 8201 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8202 8203 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8204 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8205 if (numFields) { 8206 const PetscInt **permsF[32] = {NULL}; 8207 const PetscInt **permsC[32] = {NULL}; 8208 8209 for (f = 0; f < numFields; f++) { 8210 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8211 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8212 } 8213 for (p = 0; p < numFPoints; p++) { 8214 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8215 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8216 } 8217 for (p = 0; p < numCPoints; p++) { 8218 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8219 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8220 } 8221 for (f = 0; f < numFields; f++) { 8222 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8223 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8224 } 8225 } else { 8226 const PetscInt **permsF = NULL; 8227 const PetscInt **permsC = NULL; 8228 8229 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8230 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8231 for (p = 0, off = 0; p < numFPoints; p++) { 8232 const PetscInt *perm = permsF ? permsF[p] : NULL; 8233 8234 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8235 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8236 } 8237 for (p = 0, off = 0; p < numCPoints; p++) { 8238 const PetscInt *perm = permsC ? permsC[p] : NULL; 8239 8240 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8241 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8242 } 8243 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8244 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8245 } 8246 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8247 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8248 PetscFunctionReturn(PETSC_SUCCESS); 8249 } 8250 8251 /*@C 8252 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8253 8254 Input Parameter: 8255 . dm - The `DMPLEX` object 8256 8257 Output Parameter: 8258 . cellHeight - The height of a cell 8259 8260 Level: developer 8261 8262 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8263 @*/ 8264 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8265 { 8266 DM_Plex *mesh = (DM_Plex *)dm->data; 8267 8268 PetscFunctionBegin; 8269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8270 PetscValidIntPointer(cellHeight, 2); 8271 *cellHeight = mesh->vtkCellHeight; 8272 PetscFunctionReturn(PETSC_SUCCESS); 8273 } 8274 8275 /*@C 8276 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8277 8278 Input Parameters: 8279 + dm - The `DMPLEX` object 8280 - cellHeight - The height of a cell 8281 8282 Level: developer 8283 8284 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8285 @*/ 8286 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8287 { 8288 DM_Plex *mesh = (DM_Plex *)dm->data; 8289 8290 PetscFunctionBegin; 8291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8292 mesh->vtkCellHeight = cellHeight; 8293 PetscFunctionReturn(PETSC_SUCCESS); 8294 } 8295 8296 /*@ 8297 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8298 8299 Input Parameter: 8300 . dm - The `DMPLEX` object 8301 8302 Output Parameters: 8303 + gcStart - The first ghost cell, or NULL 8304 - gcEnd - The upper bound on ghost cells, or NULL 8305 8306 Level: advanced 8307 8308 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8309 @*/ 8310 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8311 { 8312 DMLabel ctLabel; 8313 8314 PetscFunctionBegin; 8315 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8316 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8317 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8318 // Reset label for fast lookup 8319 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8320 PetscFunctionReturn(PETSC_SUCCESS); 8321 } 8322 8323 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8324 { 8325 PetscSection section, globalSection; 8326 PetscInt *numbers, p; 8327 8328 PetscFunctionBegin; 8329 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8330 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8331 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8332 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8333 PetscCall(PetscSectionSetUp(section)); 8334 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8335 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8336 for (p = pStart; p < pEnd; ++p) { 8337 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8338 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8339 else numbers[p - pStart] += shift; 8340 } 8341 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8342 if (globalSize) { 8343 PetscLayout layout; 8344 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8345 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8346 PetscCall(PetscLayoutDestroy(&layout)); 8347 } 8348 PetscCall(PetscSectionDestroy(§ion)); 8349 PetscCall(PetscSectionDestroy(&globalSection)); 8350 PetscFunctionReturn(PETSC_SUCCESS); 8351 } 8352 8353 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8354 { 8355 PetscInt cellHeight, cStart, cEnd; 8356 8357 PetscFunctionBegin; 8358 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8359 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8360 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8361 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8362 PetscFunctionReturn(PETSC_SUCCESS); 8363 } 8364 8365 /*@ 8366 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8367 8368 Input Parameter: 8369 . dm - The `DMPLEX` object 8370 8371 Output Parameter: 8372 . globalCellNumbers - Global cell numbers for all cells on this process 8373 8374 Level: developer 8375 8376 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8377 @*/ 8378 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8379 { 8380 DM_Plex *mesh = (DM_Plex *)dm->data; 8381 8382 PetscFunctionBegin; 8383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8384 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8385 *globalCellNumbers = mesh->globalCellNumbers; 8386 PetscFunctionReturn(PETSC_SUCCESS); 8387 } 8388 8389 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8390 { 8391 PetscInt vStart, vEnd; 8392 8393 PetscFunctionBegin; 8394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8395 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8396 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8397 PetscFunctionReturn(PETSC_SUCCESS); 8398 } 8399 8400 /*@ 8401 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8402 8403 Input Parameter: 8404 . dm - The `DMPLEX` object 8405 8406 Output Parameter: 8407 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8408 8409 Level: developer 8410 8411 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8412 @*/ 8413 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8414 { 8415 DM_Plex *mesh = (DM_Plex *)dm->data; 8416 8417 PetscFunctionBegin; 8418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8419 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8420 *globalVertexNumbers = mesh->globalVertexNumbers; 8421 PetscFunctionReturn(PETSC_SUCCESS); 8422 } 8423 8424 /*@ 8425 DMPlexCreatePointNumbering - Create a global numbering for all points. 8426 8427 Collective on dm 8428 8429 Input Parameter: 8430 . dm - The `DMPLEX` object 8431 8432 Output Parameter: 8433 . globalPointNumbers - Global numbers for all points on this process 8434 8435 Level: developer 8436 8437 Notes: 8438 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8439 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8440 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8441 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8442 8443 The partitioned mesh is 8444 ``` 8445 (2)--0--(3)--1--(4) (1)--0--(2) 8446 ``` 8447 and its global numbering is 8448 ``` 8449 (3)--0--(4)--1--(5)--2--(6) 8450 ``` 8451 Then the global numbering is provided as 8452 ``` 8453 [0] Number of indices in set 5 8454 [0] 0 0 8455 [0] 1 1 8456 [0] 2 3 8457 [0] 3 4 8458 [0] 4 -6 8459 [1] Number of indices in set 3 8460 [1] 0 2 8461 [1] 1 5 8462 [1] 2 6 8463 ``` 8464 8465 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8466 @*/ 8467 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8468 { 8469 IS nums[4]; 8470 PetscInt depths[4], gdepths[4], starts[4]; 8471 PetscInt depth, d, shift = 0; 8472 PetscBool empty = PETSC_FALSE; 8473 8474 PetscFunctionBegin; 8475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8476 PetscCall(DMPlexGetDepth(dm, &depth)); 8477 // For unstratified meshes use dim instead of depth 8478 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8479 // If any stratum is empty, we must mark all empty 8480 for (d = 0; d <= depth; ++d) { 8481 PetscInt end; 8482 8483 depths[d] = depth - d; 8484 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8485 if (!(starts[d] - end)) empty = PETSC_TRUE; 8486 } 8487 if (empty) 8488 for (d = 0; d <= depth; ++d) { 8489 depths[d] = -1; 8490 starts[d] = -1; 8491 } 8492 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8493 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8494 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]); 8495 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8496 for (d = 0; d <= depth; ++d) { 8497 PetscInt pStart, pEnd, gsize; 8498 8499 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8500 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8501 shift += gsize; 8502 } 8503 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8504 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8505 PetscFunctionReturn(PETSC_SUCCESS); 8506 } 8507 8508 /*@ 8509 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8510 8511 Input Parameter: 8512 . dm - The `DMPLEX` object 8513 8514 Output Parameter: 8515 . ranks - The rank field 8516 8517 Options Database Key: 8518 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8519 8520 Level: intermediate 8521 8522 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8523 @*/ 8524 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8525 { 8526 DM rdm; 8527 PetscFE fe; 8528 PetscScalar *r; 8529 PetscMPIInt rank; 8530 DMPolytopeType ct; 8531 PetscInt dim, cStart, cEnd, c; 8532 PetscBool simplex; 8533 8534 PetscFunctionBeginUser; 8535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8536 PetscValidPointer(ranks, 2); 8537 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8538 PetscCall(DMClone(dm, &rdm)); 8539 PetscCall(DMGetDimension(rdm, &dim)); 8540 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8541 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8542 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8543 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8544 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8545 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8546 PetscCall(PetscFEDestroy(&fe)); 8547 PetscCall(DMCreateDS(rdm)); 8548 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8549 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8550 PetscCall(VecGetArray(*ranks, &r)); 8551 for (c = cStart; c < cEnd; ++c) { 8552 PetscScalar *lr; 8553 8554 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8555 if (lr) *lr = rank; 8556 } 8557 PetscCall(VecRestoreArray(*ranks, &r)); 8558 PetscCall(DMDestroy(&rdm)); 8559 PetscFunctionReturn(PETSC_SUCCESS); 8560 } 8561 8562 /*@ 8563 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8564 8565 Input Parameters: 8566 + dm - The DMPlex 8567 - label - The DMLabel 8568 8569 Output Parameter: 8570 . val - The label value field 8571 8572 Options Database Keys: 8573 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8574 8575 Level: intermediate 8576 8577 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8578 @*/ 8579 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8580 { 8581 DM rdm; 8582 PetscFE fe; 8583 PetscScalar *v; 8584 PetscInt dim, cStart, cEnd, c; 8585 8586 PetscFunctionBeginUser; 8587 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8588 PetscValidPointer(label, 2); 8589 PetscValidPointer(val, 3); 8590 PetscCall(DMClone(dm, &rdm)); 8591 PetscCall(DMGetDimension(rdm, &dim)); 8592 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8593 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8594 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8595 PetscCall(PetscFEDestroy(&fe)); 8596 PetscCall(DMCreateDS(rdm)); 8597 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8598 PetscCall(DMCreateGlobalVector(rdm, val)); 8599 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8600 PetscCall(VecGetArray(*val, &v)); 8601 for (c = cStart; c < cEnd; ++c) { 8602 PetscScalar *lv; 8603 PetscInt cval; 8604 8605 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8606 PetscCall(DMLabelGetValue(label, c, &cval)); 8607 *lv = cval; 8608 } 8609 PetscCall(VecRestoreArray(*val, &v)); 8610 PetscCall(DMDestroy(&rdm)); 8611 PetscFunctionReturn(PETSC_SUCCESS); 8612 } 8613 8614 /*@ 8615 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8616 8617 Input Parameter: 8618 . dm - The `DMPLEX` object 8619 8620 Level: developer 8621 8622 Notes: 8623 This is a useful diagnostic when creating meshes programmatically. 8624 8625 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8626 8627 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8628 @*/ 8629 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8630 { 8631 PetscSection coneSection, supportSection; 8632 const PetscInt *cone, *support; 8633 PetscInt coneSize, c, supportSize, s; 8634 PetscInt pStart, pEnd, p, pp, csize, ssize; 8635 PetscBool storagecheck = PETSC_TRUE; 8636 8637 PetscFunctionBegin; 8638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8639 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8640 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8641 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8642 /* Check that point p is found in the support of its cone points, and vice versa */ 8643 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8644 for (p = pStart; p < pEnd; ++p) { 8645 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8646 PetscCall(DMPlexGetCone(dm, p, &cone)); 8647 for (c = 0; c < coneSize; ++c) { 8648 PetscBool dup = PETSC_FALSE; 8649 PetscInt d; 8650 for (d = c - 1; d >= 0; --d) { 8651 if (cone[c] == cone[d]) { 8652 dup = PETSC_TRUE; 8653 break; 8654 } 8655 } 8656 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8657 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8658 for (s = 0; s < supportSize; ++s) { 8659 if (support[s] == p) break; 8660 } 8661 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8662 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8663 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8664 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8665 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8666 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8667 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8668 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]); 8669 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8670 } 8671 } 8672 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8673 if (p != pp) { 8674 storagecheck = PETSC_FALSE; 8675 continue; 8676 } 8677 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8678 PetscCall(DMPlexGetSupport(dm, p, &support)); 8679 for (s = 0; s < supportSize; ++s) { 8680 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8681 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8682 for (c = 0; c < coneSize; ++c) { 8683 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8684 if (cone[c] != pp) { 8685 c = 0; 8686 break; 8687 } 8688 if (cone[c] == p) break; 8689 } 8690 if (c >= coneSize) { 8691 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8692 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8693 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8694 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8695 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8696 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8697 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8698 } 8699 } 8700 } 8701 if (storagecheck) { 8702 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8703 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8704 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8705 } 8706 PetscFunctionReturn(PETSC_SUCCESS); 8707 } 8708 8709 /* 8710 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. 8711 */ 8712 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8713 { 8714 DMPolytopeType cct; 8715 PetscInt ptpoints[4]; 8716 const PetscInt *cone, *ccone, *ptcone; 8717 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8718 8719 PetscFunctionBegin; 8720 *unsplit = 0; 8721 switch (ct) { 8722 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8723 ptpoints[npt++] = c; 8724 break; 8725 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8726 PetscCall(DMPlexGetCone(dm, c, &cone)); 8727 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8728 for (cp = 0; cp < coneSize; ++cp) { 8729 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8730 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8731 } 8732 break; 8733 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8734 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8735 PetscCall(DMPlexGetCone(dm, c, &cone)); 8736 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8737 for (cp = 0; cp < coneSize; ++cp) { 8738 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8739 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8740 for (ccp = 0; ccp < cconeSize; ++ccp) { 8741 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8742 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8743 PetscInt p; 8744 for (p = 0; p < npt; ++p) 8745 if (ptpoints[p] == ccone[ccp]) break; 8746 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8747 } 8748 } 8749 } 8750 break; 8751 default: 8752 break; 8753 } 8754 for (pt = 0; pt < npt; ++pt) { 8755 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8756 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8757 } 8758 PetscFunctionReturn(PETSC_SUCCESS); 8759 } 8760 8761 /*@ 8762 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8763 8764 Input Parameters: 8765 + dm - The `DMPLEX` object 8766 - cellHeight - Normally 0 8767 8768 Level: developer 8769 8770 Notes: 8771 This is a useful diagnostic when creating meshes programmatically. 8772 Currently applicable only to homogeneous simplex or tensor meshes. 8773 8774 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8775 8776 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8777 @*/ 8778 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8779 { 8780 DMPlexInterpolatedFlag interp; 8781 DMPolytopeType ct; 8782 PetscInt vStart, vEnd, cStart, cEnd, c; 8783 8784 PetscFunctionBegin; 8785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8786 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8787 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8788 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8789 for (c = cStart; c < cEnd; ++c) { 8790 PetscInt *closure = NULL; 8791 PetscInt coneSize, closureSize, cl, Nv = 0; 8792 8793 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8794 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8795 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8796 if (interp == DMPLEX_INTERPOLATED_FULL) { 8797 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8798 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)); 8799 } 8800 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8801 for (cl = 0; cl < closureSize * 2; cl += 2) { 8802 const PetscInt p = closure[cl]; 8803 if ((p >= vStart) && (p < vEnd)) ++Nv; 8804 } 8805 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8806 /* Special Case: Tensor faces with identified vertices */ 8807 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8808 PetscInt unsplit; 8809 8810 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8811 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8812 } 8813 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)); 8814 } 8815 PetscFunctionReturn(PETSC_SUCCESS); 8816 } 8817 8818 /*@ 8819 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8820 8821 Collective on dm 8822 8823 Input Parameters: 8824 + dm - The `DMPLEX` object 8825 - cellHeight - Normally 0 8826 8827 Level: developer 8828 8829 Notes: 8830 This is a useful diagnostic when creating meshes programmatically. 8831 This routine is only relevant for meshes that are fully interpolated across all ranks. 8832 It will error out if a partially interpolated mesh is given on some rank. 8833 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8834 8835 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8836 8837 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8838 @*/ 8839 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8840 { 8841 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8842 DMPlexInterpolatedFlag interpEnum; 8843 8844 PetscFunctionBegin; 8845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8846 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8847 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8848 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8849 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8850 PetscFunctionReturn(PETSC_SUCCESS); 8851 } 8852 8853 PetscCall(DMGetDimension(dm, &dim)); 8854 PetscCall(DMPlexGetDepth(dm, &depth)); 8855 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8856 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8857 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8858 for (c = cStart; c < cEnd; ++c) { 8859 const PetscInt *cone, *ornt, *faceSizes, *faces; 8860 const DMPolytopeType *faceTypes; 8861 DMPolytopeType ct; 8862 PetscInt numFaces, coneSize, f; 8863 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8864 8865 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8866 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8867 if (unsplit) continue; 8868 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8869 PetscCall(DMPlexGetCone(dm, c, &cone)); 8870 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8871 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8872 for (cl = 0; cl < closureSize * 2; cl += 2) { 8873 const PetscInt p = closure[cl]; 8874 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8875 } 8876 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8877 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); 8878 for (f = 0; f < numFaces; ++f) { 8879 DMPolytopeType fct; 8880 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8881 8882 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8883 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8884 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8885 const PetscInt p = fclosure[cl]; 8886 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8887 } 8888 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]); 8889 for (v = 0; v < fnumCorners; ++v) { 8890 if (fclosure[v] != faces[fOff + v]) { 8891 PetscInt v1; 8892 8893 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8894 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8895 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8896 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8897 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8898 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]); 8899 } 8900 } 8901 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8902 fOff += faceSizes[f]; 8903 } 8904 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8905 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8906 } 8907 } 8908 PetscFunctionReturn(PETSC_SUCCESS); 8909 } 8910 8911 /*@ 8912 DMPlexCheckGeometry - Check the geometry of mesh cells 8913 8914 Input Parameter: 8915 . dm - The `DMPLEX` object 8916 8917 Level: developer 8918 8919 Notes: 8920 This is a useful diagnostic when creating meshes programmatically. 8921 8922 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8923 8924 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8925 @*/ 8926 PetscErrorCode DMPlexCheckGeometry(DM dm) 8927 { 8928 Vec coordinates; 8929 PetscReal detJ, J[9], refVol = 1.0; 8930 PetscReal vol; 8931 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8932 8933 PetscFunctionBegin; 8934 PetscCall(DMGetDimension(dm, &dim)); 8935 PetscCall(DMGetCoordinateDim(dm, &dE)); 8936 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 8937 PetscCall(DMPlexGetDepth(dm, &depth)); 8938 for (d = 0; d < dim; ++d) refVol *= 2.0; 8939 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8940 /* Make sure local coordinates are created, because that step is collective */ 8941 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8942 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 8943 for (c = cStart; c < cEnd; ++c) { 8944 DMPolytopeType ct; 8945 PetscInt unsplit; 8946 PetscBool ignoreZeroVol = PETSC_FALSE; 8947 8948 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8949 switch (ct) { 8950 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8951 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8952 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8953 ignoreZeroVol = PETSC_TRUE; 8954 break; 8955 default: 8956 break; 8957 } 8958 switch (ct) { 8959 case DM_POLYTOPE_TRI_PRISM: 8960 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8961 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8962 case DM_POLYTOPE_PYRAMID: 8963 continue; 8964 default: 8965 break; 8966 } 8967 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8968 if (unsplit) continue; 8969 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8970 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); 8971 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8972 /* This should work with periodicity since DG coordinates should be used */ 8973 if (depth > 1) { 8974 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8975 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); 8976 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8977 } 8978 } 8979 PetscFunctionReturn(PETSC_SUCCESS); 8980 } 8981 8982 /*@ 8983 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8984 8985 Collective on dm 8986 8987 Input Parameters: 8988 + dm - The `DMPLEX` object 8989 . pointSF - The `PetscSF`, or NULL for `PointSF` attached to `DM` 8990 - allowExtraRoots - Flag to allow extra points not present in the `DM` 8991 8992 Level: developer 8993 8994 Notes: 8995 This is mainly intended for debugging/testing purposes. 8996 8997 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8998 8999 Extra roots can come from priodic cuts, where additional points appear on the boundary 9000 9001 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9002 @*/ 9003 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9004 { 9005 PetscInt l, nleaves, nroots, overlap; 9006 const PetscInt *locals; 9007 const PetscSFNode *remotes; 9008 PetscBool distributed; 9009 MPI_Comm comm; 9010 PetscMPIInt rank; 9011 9012 PetscFunctionBegin; 9013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9014 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9015 else pointSF = dm->sf; 9016 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9017 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9018 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9019 { 9020 PetscMPIInt mpiFlag; 9021 9022 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9023 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9024 } 9025 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9026 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9027 if (!distributed) { 9028 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); 9029 PetscFunctionReturn(PETSC_SUCCESS); 9030 } 9031 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); 9032 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9033 9034 /* Check SF graph is compatible with DMPlex chart */ 9035 { 9036 PetscInt pStart, pEnd, maxLeaf; 9037 9038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9039 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9040 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9041 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9042 } 9043 9044 /* Check Point SF has no local points referenced */ 9045 for (l = 0; l < nleaves; l++) { 9046 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); 9047 } 9048 9049 /* Check there are no cells in interface */ 9050 if (!overlap) { 9051 PetscInt cellHeight, cStart, cEnd; 9052 9053 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9054 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9055 for (l = 0; l < nleaves; ++l) { 9056 const PetscInt point = locals ? locals[l] : l; 9057 9058 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9059 } 9060 } 9061 9062 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9063 { 9064 const PetscInt *rootdegree; 9065 9066 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9067 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9068 for (l = 0; l < nleaves; ++l) { 9069 const PetscInt point = locals ? locals[l] : l; 9070 const PetscInt *cone; 9071 PetscInt coneSize, c, idx; 9072 9073 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9074 PetscCall(DMPlexGetCone(dm, point, &cone)); 9075 for (c = 0; c < coneSize; ++c) { 9076 if (!rootdegree[cone[c]]) { 9077 if (locals) { 9078 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9079 } else { 9080 idx = (cone[c] < nleaves) ? cone[c] : -1; 9081 } 9082 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9083 } 9084 } 9085 } 9086 } 9087 PetscFunctionReturn(PETSC_SUCCESS); 9088 } 9089 9090 /*@ 9091 DMPlexCheck - Perform various checks of Plex sanity 9092 9093 Input Parameter: 9094 . dm - The `DMPLEX` object 9095 9096 Level: developer 9097 9098 Notes: 9099 This is a useful diagnostic when creating meshes programmatically. 9100 9101 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 9102 9103 Currently does not include DMPlexCheckCellShape(). 9104 9105 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, DMCreate(), DMSetFromOptions() 9106 @*/ 9107 PetscErrorCode DMPlexCheck(DM dm) 9108 { 9109 PetscInt cellHeight; 9110 9111 PetscFunctionBegin; 9112 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9113 PetscCall(DMPlexCheckSymmetry(dm)); 9114 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9115 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9116 PetscCall(DMPlexCheckGeometry(dm)); 9117 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9118 PetscCall(DMPlexCheckInterfaceCones(dm)); 9119 PetscFunctionReturn(PETSC_SUCCESS); 9120 } 9121 9122 typedef struct cell_stats { 9123 PetscReal min, max, sum, squaresum; 9124 PetscInt count; 9125 } cell_stats_t; 9126 9127 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9128 { 9129 PetscInt i, N = *len; 9130 9131 for (i = 0; i < N; i++) { 9132 cell_stats_t *A = (cell_stats_t *)a; 9133 cell_stats_t *B = (cell_stats_t *)b; 9134 9135 B->min = PetscMin(A->min, B->min); 9136 B->max = PetscMax(A->max, B->max); 9137 B->sum += A->sum; 9138 B->squaresum += A->squaresum; 9139 B->count += A->count; 9140 } 9141 } 9142 9143 /*@ 9144 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9145 9146 Collective on dm 9147 9148 Input Parameters: 9149 + dm - The `DMPLEX` object 9150 . output - If true, statistics will be displayed on stdout 9151 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9152 9153 Level: developer 9154 9155 Notes: 9156 This is mainly intended for debugging/testing purposes. 9157 9158 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9159 9160 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9161 @*/ 9162 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9163 { 9164 DM dmCoarse; 9165 cell_stats_t stats, globalStats; 9166 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9167 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9168 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9169 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9170 PetscMPIInt rank, size; 9171 9172 PetscFunctionBegin; 9173 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9174 stats.min = PETSC_MAX_REAL; 9175 stats.max = PETSC_MIN_REAL; 9176 stats.sum = stats.squaresum = 0.; 9177 stats.count = 0; 9178 9179 PetscCallMPI(MPI_Comm_size(comm, &size)); 9180 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9181 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9182 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9183 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9184 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9185 for (c = cStart; c < cEnd; c++) { 9186 PetscInt i; 9187 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9188 9189 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9190 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9191 for (i = 0; i < PetscSqr(cdim); ++i) { 9192 frobJ += J[i] * J[i]; 9193 frobInvJ += invJ[i] * invJ[i]; 9194 } 9195 cond2 = frobJ * frobInvJ; 9196 cond = PetscSqrtReal(cond2); 9197 9198 stats.min = PetscMin(stats.min, cond); 9199 stats.max = PetscMax(stats.max, cond); 9200 stats.sum += cond; 9201 stats.squaresum += cond2; 9202 stats.count++; 9203 if (output && cond > limit) { 9204 PetscSection coordSection; 9205 Vec coordsLocal; 9206 PetscScalar *coords = NULL; 9207 PetscInt Nv, d, clSize, cl, *closure = NULL; 9208 9209 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9210 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9211 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9212 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9213 for (i = 0; i < Nv / cdim; ++i) { 9214 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9215 for (d = 0; d < cdim; ++d) { 9216 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9217 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9218 } 9219 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9220 } 9221 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9222 for (cl = 0; cl < clSize * 2; cl += 2) { 9223 const PetscInt edge = closure[cl]; 9224 9225 if ((edge >= eStart) && (edge < eEnd)) { 9226 PetscReal len; 9227 9228 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9229 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9230 } 9231 } 9232 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9233 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9234 } 9235 } 9236 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9237 9238 if (size > 1) { 9239 PetscMPIInt blockLengths[2] = {4, 1}; 9240 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9241 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9242 MPI_Op statReduce; 9243 9244 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9245 PetscCallMPI(MPI_Type_commit(&statType)); 9246 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9247 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9248 PetscCallMPI(MPI_Op_free(&statReduce)); 9249 PetscCallMPI(MPI_Type_free(&statType)); 9250 } else { 9251 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9252 } 9253 if (rank == 0) { 9254 count = globalStats.count; 9255 min = globalStats.min; 9256 max = globalStats.max; 9257 mean = globalStats.sum / globalStats.count; 9258 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9259 } 9260 9261 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)); 9262 PetscCall(PetscFree2(J, invJ)); 9263 9264 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9265 if (dmCoarse) { 9266 PetscBool isplex; 9267 9268 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9269 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9270 } 9271 PetscFunctionReturn(PETSC_SUCCESS); 9272 } 9273 9274 /*@ 9275 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9276 orthogonal quality below given tolerance. 9277 9278 Collective on dm 9279 9280 Input Parameters: 9281 + dm - The `DMPLEX` object 9282 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9283 - atol - [0, 1] Absolute tolerance for tagging cells. 9284 9285 Output Parameters: 9286 + OrthQual - Vec containing orthogonal quality per cell 9287 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9288 9289 Options Database Keys: 9290 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9291 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9292 9293 Level: intermediate 9294 9295 Notes: 9296 Orthogonal quality is given by the following formula: 9297 9298 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9299 9300 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 9301 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9302 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9303 calculating the cosine of the angle between these vectors. 9304 9305 Orthogonal quality ranges from 1 (best) to 0 (worst). 9306 9307 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9308 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9309 9310 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9311 9312 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9313 @*/ 9314 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9315 { 9316 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9317 PetscInt *idx; 9318 PetscScalar *oqVals; 9319 const PetscScalar *cellGeomArr, *faceGeomArr; 9320 PetscReal *ci, *fi, *Ai; 9321 MPI_Comm comm; 9322 Vec cellgeom, facegeom; 9323 DM dmFace, dmCell; 9324 IS glob; 9325 ISLocalToGlobalMapping ltog; 9326 PetscViewer vwr; 9327 9328 PetscFunctionBegin; 9329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9330 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9331 PetscValidPointer(OrthQual, 4); 9332 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9333 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9334 PetscCall(DMGetDimension(dm, &nc)); 9335 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9336 { 9337 DMPlexInterpolatedFlag interpFlag; 9338 9339 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9340 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9341 PetscMPIInt rank; 9342 9343 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9344 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9345 } 9346 } 9347 if (OrthQualLabel) { 9348 PetscValidPointer(OrthQualLabel, 5); 9349 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9350 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9351 } else { 9352 *OrthQualLabel = NULL; 9353 } 9354 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9355 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9356 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9357 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9358 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9359 PetscCall(VecCreate(comm, OrthQual)); 9360 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9361 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9362 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9363 PetscCall(VecSetUp(*OrthQual)); 9364 PetscCall(ISDestroy(&glob)); 9365 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9366 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9367 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9368 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9369 PetscCall(VecGetDM(cellgeom, &dmCell)); 9370 PetscCall(VecGetDM(facegeom, &dmFace)); 9371 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9372 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9373 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9374 PetscInt cellarr[2], *adj = NULL; 9375 PetscScalar *cArr, *fArr; 9376 PetscReal minvalc = 1.0, minvalf = 1.0; 9377 PetscFVCellGeom *cg; 9378 9379 idx[cellIter] = cell - cStart; 9380 cellarr[0] = cell; 9381 /* Make indexing into cellGeom easier */ 9382 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9383 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9384 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9385 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9386 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9387 PetscInt i; 9388 const PetscInt neigh = adj[cellneigh]; 9389 PetscReal normci = 0, normfi = 0, normai = 0; 9390 PetscFVCellGeom *cgneigh; 9391 PetscFVFaceGeom *fg; 9392 9393 /* Don't count ourselves in the neighbor list */ 9394 if (neigh == cell) continue; 9395 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9396 cellarr[1] = neigh; 9397 { 9398 PetscInt numcovpts; 9399 const PetscInt *covpts; 9400 9401 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9402 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9403 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9404 } 9405 9406 /* Compute c_i, f_i and their norms */ 9407 for (i = 0; i < nc; i++) { 9408 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9409 fi[i] = fg->centroid[i] - cg->centroid[i]; 9410 Ai[i] = fg->normal[i]; 9411 normci += PetscPowReal(ci[i], 2); 9412 normfi += PetscPowReal(fi[i], 2); 9413 normai += PetscPowReal(Ai[i], 2); 9414 } 9415 normci = PetscSqrtReal(normci); 9416 normfi = PetscSqrtReal(normfi); 9417 normai = PetscSqrtReal(normai); 9418 9419 /* Normalize and compute for each face-cell-normal pair */ 9420 for (i = 0; i < nc; i++) { 9421 ci[i] = ci[i] / normci; 9422 fi[i] = fi[i] / normfi; 9423 Ai[i] = Ai[i] / normai; 9424 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9425 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9426 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9427 } 9428 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9429 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9430 } 9431 PetscCall(PetscFree(adj)); 9432 PetscCall(PetscFree2(cArr, fArr)); 9433 /* Defer to cell if they're equal */ 9434 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9435 if (OrthQualLabel) { 9436 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9437 } 9438 } 9439 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9440 PetscCall(VecAssemblyBegin(*OrthQual)); 9441 PetscCall(VecAssemblyEnd(*OrthQual)); 9442 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9443 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9444 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9445 if (OrthQualLabel) { 9446 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9447 } 9448 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9449 PetscCall(PetscViewerDestroy(&vwr)); 9450 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9451 PetscFunctionReturn(PETSC_SUCCESS); 9452 } 9453 9454 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9455 * interpolator construction */ 9456 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9457 { 9458 PetscSection section, newSection, gsection; 9459 PetscSF sf; 9460 PetscBool hasConstraints, ghasConstraints; 9461 9462 PetscFunctionBegin; 9463 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9464 PetscValidPointer(odm, 2); 9465 PetscCall(DMGetLocalSection(dm, §ion)); 9466 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9467 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9468 if (!ghasConstraints) { 9469 PetscCall(PetscObjectReference((PetscObject)dm)); 9470 *odm = dm; 9471 PetscFunctionReturn(PETSC_SUCCESS); 9472 } 9473 PetscCall(DMClone(dm, odm)); 9474 PetscCall(DMCopyFields(dm, *odm)); 9475 PetscCall(DMGetLocalSection(*odm, &newSection)); 9476 PetscCall(DMGetPointSF(*odm, &sf)); 9477 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9478 PetscCall(DMSetGlobalSection(*odm, gsection)); 9479 PetscCall(PetscSectionDestroy(&gsection)); 9480 PetscFunctionReturn(PETSC_SUCCESS); 9481 } 9482 9483 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9484 { 9485 DM dmco, dmfo; 9486 Mat interpo; 9487 Vec rscale; 9488 Vec cglobalo, clocal; 9489 Vec fglobal, fglobalo, flocal; 9490 PetscBool regular; 9491 9492 PetscFunctionBegin; 9493 PetscCall(DMGetFullDM(dmc, &dmco)); 9494 PetscCall(DMGetFullDM(dmf, &dmfo)); 9495 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9496 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9497 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9498 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9499 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9500 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9501 PetscCall(VecSet(cglobalo, 0.)); 9502 PetscCall(VecSet(clocal, 0.)); 9503 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9504 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9505 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9506 PetscCall(VecSet(fglobal, 0.)); 9507 PetscCall(VecSet(fglobalo, 0.)); 9508 PetscCall(VecSet(flocal, 0.)); 9509 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9510 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9511 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9512 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9513 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9514 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9515 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9516 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9517 *shift = fglobal; 9518 PetscCall(VecDestroy(&flocal)); 9519 PetscCall(VecDestroy(&fglobalo)); 9520 PetscCall(VecDestroy(&clocal)); 9521 PetscCall(VecDestroy(&cglobalo)); 9522 PetscCall(VecDestroy(&rscale)); 9523 PetscCall(MatDestroy(&interpo)); 9524 PetscCall(DMDestroy(&dmfo)); 9525 PetscCall(DMDestroy(&dmco)); 9526 PetscFunctionReturn(PETSC_SUCCESS); 9527 } 9528 9529 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9530 { 9531 PetscObject shifto; 9532 Vec shift; 9533 9534 PetscFunctionBegin; 9535 if (!interp) { 9536 Vec rscale; 9537 9538 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9539 PetscCall(VecDestroy(&rscale)); 9540 } else { 9541 PetscCall(PetscObjectReference((PetscObject)interp)); 9542 } 9543 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9544 if (!shifto) { 9545 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9546 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9547 shifto = (PetscObject)shift; 9548 PetscCall(VecDestroy(&shift)); 9549 } 9550 shift = (Vec)shifto; 9551 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9552 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9553 PetscCall(MatDestroy(&interp)); 9554 PetscFunctionReturn(PETSC_SUCCESS); 9555 } 9556 9557 /* Pointwise interpolation 9558 Just code FEM for now 9559 u^f = I u^c 9560 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9561 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9562 I_{ij} = psi^f_i phi^c_j 9563 */ 9564 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9565 { 9566 PetscSection gsc, gsf; 9567 PetscInt m, n; 9568 void *ctx; 9569 DM cdm; 9570 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9571 9572 PetscFunctionBegin; 9573 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9574 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9575 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9576 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9577 9578 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9579 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9580 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9581 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9582 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9583 9584 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9585 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9586 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9587 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9588 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9589 if (scaling) { 9590 /* Use naive scaling */ 9591 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9592 } 9593 PetscFunctionReturn(PETSC_SUCCESS); 9594 } 9595 9596 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9597 { 9598 VecScatter ctx; 9599 9600 PetscFunctionBegin; 9601 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9602 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9603 PetscCall(VecScatterDestroy(&ctx)); 9604 PetscFunctionReturn(PETSC_SUCCESS); 9605 } 9606 9607 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[]) 9608 { 9609 const PetscInt Nc = uOff[1] - uOff[0]; 9610 PetscInt c; 9611 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9612 } 9613 9614 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9615 { 9616 DM dmc; 9617 PetscDS ds; 9618 Vec ones, locmass; 9619 IS cellIS; 9620 PetscFormKey key; 9621 PetscInt depth; 9622 9623 PetscFunctionBegin; 9624 PetscCall(DMClone(dm, &dmc)); 9625 PetscCall(DMCopyDisc(dm, dmc)); 9626 PetscCall(DMGetDS(dmc, &ds)); 9627 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9628 PetscCall(DMCreateGlobalVector(dmc, mass)); 9629 PetscCall(DMGetLocalVector(dmc, &ones)); 9630 PetscCall(DMGetLocalVector(dmc, &locmass)); 9631 PetscCall(DMPlexGetDepth(dmc, &depth)); 9632 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9633 PetscCall(VecSet(locmass, 0.0)); 9634 PetscCall(VecSet(ones, 1.0)); 9635 key.label = NULL; 9636 key.value = 0; 9637 key.field = 0; 9638 key.part = 0; 9639 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9640 PetscCall(ISDestroy(&cellIS)); 9641 PetscCall(VecSet(*mass, 0.0)); 9642 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9643 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9644 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9645 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9646 PetscCall(DMDestroy(&dmc)); 9647 PetscFunctionReturn(PETSC_SUCCESS); 9648 } 9649 9650 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9651 { 9652 PetscSection gsc, gsf; 9653 PetscInt m, n; 9654 void *ctx; 9655 DM cdm; 9656 PetscBool regular; 9657 9658 PetscFunctionBegin; 9659 if (dmFine == dmCoarse) { 9660 DM dmc; 9661 PetscDS ds; 9662 PetscWeakForm wf; 9663 Vec u; 9664 IS cellIS; 9665 PetscFormKey key; 9666 PetscInt depth; 9667 9668 PetscCall(DMClone(dmFine, &dmc)); 9669 PetscCall(DMCopyDisc(dmFine, dmc)); 9670 PetscCall(DMGetDS(dmc, &ds)); 9671 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9672 PetscCall(PetscWeakFormClear(wf)); 9673 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9674 PetscCall(DMCreateMatrix(dmc, mass)); 9675 PetscCall(DMGetLocalVector(dmc, &u)); 9676 PetscCall(DMPlexGetDepth(dmc, &depth)); 9677 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9678 PetscCall(MatZeroEntries(*mass)); 9679 key.label = NULL; 9680 key.value = 0; 9681 key.field = 0; 9682 key.part = 0; 9683 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9684 PetscCall(ISDestroy(&cellIS)); 9685 PetscCall(DMRestoreLocalVector(dmc, &u)); 9686 PetscCall(DMDestroy(&dmc)); 9687 } else { 9688 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9689 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9690 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9691 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9692 9693 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9694 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9695 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9696 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9697 9698 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9699 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9700 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9701 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9702 } 9703 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9704 PetscFunctionReturn(PETSC_SUCCESS); 9705 } 9706 9707 /*@ 9708 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9709 9710 Input Parameter: 9711 . dm - The `DMPLEX` object 9712 9713 Output Parameter: 9714 . regular - The flag 9715 9716 Level: intermediate 9717 9718 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9719 @*/ 9720 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9721 { 9722 PetscFunctionBegin; 9723 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9724 PetscValidBoolPointer(regular, 2); 9725 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9726 PetscFunctionReturn(PETSC_SUCCESS); 9727 } 9728 9729 /*@ 9730 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9731 9732 Input Parameters: 9733 + dm - The `DMPLEX` object 9734 - regular - The flag 9735 9736 Level: intermediate 9737 9738 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9739 @*/ 9740 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9741 { 9742 PetscFunctionBegin; 9743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9744 ((DM_Plex *)dm->data)->regularRefinement = regular; 9745 PetscFunctionReturn(PETSC_SUCCESS); 9746 } 9747 9748 /*@ 9749 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9750 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9751 9752 Not Collective 9753 9754 Input Parameter: 9755 . dm - The `DMPLEX` object 9756 9757 Output Parameters: 9758 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9759 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9760 9761 Level: intermediate 9762 9763 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9764 @*/ 9765 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9766 { 9767 DM_Plex *plex = (DM_Plex *)dm->data; 9768 9769 PetscFunctionBegin; 9770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9771 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9772 if (anchorSection) *anchorSection = plex->anchorSection; 9773 if (anchorIS) *anchorIS = plex->anchorIS; 9774 PetscFunctionReturn(PETSC_SUCCESS); 9775 } 9776 9777 /*@ 9778 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9779 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9780 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9781 9782 Collective on dm 9783 9784 Input Parameters: 9785 + dm - The `DMPLEX` object 9786 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9787 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9788 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9789 9790 Level: intermediate 9791 9792 Notes: 9793 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9794 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9795 9796 The reference counts of anchorSection and anchorIS are incremented. 9797 9798 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9799 @*/ 9800 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9801 { 9802 DM_Plex *plex = (DM_Plex *)dm->data; 9803 PetscMPIInt result; 9804 9805 PetscFunctionBegin; 9806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9807 if (anchorSection) { 9808 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9809 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9810 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9811 } 9812 if (anchorIS) { 9813 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9814 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9815 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9816 } 9817 9818 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9819 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9820 plex->anchorSection = anchorSection; 9821 9822 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9823 PetscCall(ISDestroy(&plex->anchorIS)); 9824 plex->anchorIS = anchorIS; 9825 9826 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9827 PetscInt size, a, pStart, pEnd; 9828 const PetscInt *anchors; 9829 9830 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9831 PetscCall(ISGetLocalSize(anchorIS, &size)); 9832 PetscCall(ISGetIndices(anchorIS, &anchors)); 9833 for (a = 0; a < size; a++) { 9834 PetscInt p; 9835 9836 p = anchors[a]; 9837 if (p >= pStart && p < pEnd) { 9838 PetscInt dof; 9839 9840 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9841 if (dof) { 9842 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9843 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9844 } 9845 } 9846 } 9847 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9848 } 9849 /* reset the generic constraints */ 9850 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9851 PetscFunctionReturn(PETSC_SUCCESS); 9852 } 9853 9854 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9855 { 9856 PetscSection anchorSection; 9857 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9858 9859 PetscFunctionBegin; 9860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9861 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9862 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9863 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9864 if (numFields) { 9865 PetscInt f; 9866 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9867 9868 for (f = 0; f < numFields; f++) { 9869 PetscInt numComp; 9870 9871 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9872 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9873 } 9874 } 9875 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9876 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9877 pStart = PetscMax(pStart, sStart); 9878 pEnd = PetscMin(pEnd, sEnd); 9879 pEnd = PetscMax(pStart, pEnd); 9880 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9881 for (p = pStart; p < pEnd; p++) { 9882 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9883 if (dof) { 9884 PetscCall(PetscSectionGetDof(section, p, &dof)); 9885 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9886 for (f = 0; f < numFields; f++) { 9887 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9888 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9889 } 9890 } 9891 } 9892 PetscCall(PetscSectionSetUp(*cSec)); 9893 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9894 PetscFunctionReturn(PETSC_SUCCESS); 9895 } 9896 9897 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9898 { 9899 PetscSection aSec; 9900 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9901 const PetscInt *anchors; 9902 PetscInt numFields, f; 9903 IS aIS; 9904 MatType mtype; 9905 PetscBool iscuda, iskokkos; 9906 9907 PetscFunctionBegin; 9908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9909 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9910 PetscCall(PetscSectionGetStorageSize(section, &n)); 9911 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9912 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9913 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9914 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9915 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9916 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9917 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9918 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9919 else mtype = MATSEQAIJ; 9920 PetscCall(MatSetType(*cMat, mtype)); 9921 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9922 PetscCall(ISGetIndices(aIS, &anchors)); 9923 /* cSec will be a subset of aSec and section */ 9924 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9925 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9926 PetscCall(PetscMalloc1(m + 1, &i)); 9927 i[0] = 0; 9928 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9929 for (p = pStart; p < pEnd; p++) { 9930 PetscInt rDof, rOff, r; 9931 9932 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9933 if (!rDof) continue; 9934 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9935 if (numFields) { 9936 for (f = 0; f < numFields; f++) { 9937 annz = 0; 9938 for (r = 0; r < rDof; r++) { 9939 a = anchors[rOff + r]; 9940 if (a < sStart || a >= sEnd) continue; 9941 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9942 annz += aDof; 9943 } 9944 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9945 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9946 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9947 } 9948 } else { 9949 annz = 0; 9950 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9951 for (q = 0; q < dof; q++) { 9952 a = anchors[rOff + q]; 9953 if (a < sStart || a >= sEnd) continue; 9954 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9955 annz += aDof; 9956 } 9957 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9958 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9959 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9960 } 9961 } 9962 nnz = i[m]; 9963 PetscCall(PetscMalloc1(nnz, &j)); 9964 offset = 0; 9965 for (p = pStart; p < pEnd; p++) { 9966 if (numFields) { 9967 for (f = 0; f < numFields; f++) { 9968 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9969 for (q = 0; q < dof; q++) { 9970 PetscInt rDof, rOff, r; 9971 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9972 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9973 for (r = 0; r < rDof; r++) { 9974 PetscInt s; 9975 9976 a = anchors[rOff + r]; 9977 if (a < sStart || a >= sEnd) continue; 9978 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9979 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9980 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9981 } 9982 } 9983 } 9984 } else { 9985 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9986 for (q = 0; q < dof; q++) { 9987 PetscInt rDof, rOff, r; 9988 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9989 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9990 for (r = 0; r < rDof; r++) { 9991 PetscInt s; 9992 9993 a = anchors[rOff + r]; 9994 if (a < sStart || a >= sEnd) continue; 9995 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9996 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9997 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9998 } 9999 } 10000 } 10001 } 10002 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10003 PetscCall(PetscFree(i)); 10004 PetscCall(PetscFree(j)); 10005 PetscCall(ISRestoreIndices(aIS, &anchors)); 10006 PetscFunctionReturn(PETSC_SUCCESS); 10007 } 10008 10009 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10010 { 10011 DM_Plex *plex = (DM_Plex *)dm->data; 10012 PetscSection anchorSection, section, cSec; 10013 Mat cMat; 10014 10015 PetscFunctionBegin; 10016 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10017 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10018 if (anchorSection) { 10019 PetscInt Nf; 10020 10021 PetscCall(DMGetLocalSection(dm, §ion)); 10022 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10023 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10024 PetscCall(DMGetNumFields(dm, &Nf)); 10025 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10026 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10027 PetscCall(PetscSectionDestroy(&cSec)); 10028 PetscCall(MatDestroy(&cMat)); 10029 } 10030 PetscFunctionReturn(PETSC_SUCCESS); 10031 } 10032 10033 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10034 { 10035 IS subis; 10036 PetscSection section, subsection; 10037 10038 PetscFunctionBegin; 10039 PetscCall(DMGetLocalSection(dm, §ion)); 10040 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10041 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10042 /* Create subdomain */ 10043 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10044 /* Create submodel */ 10045 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10046 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10047 PetscCall(DMSetLocalSection(*subdm, subsection)); 10048 PetscCall(PetscSectionDestroy(&subsection)); 10049 PetscCall(DMCopyDisc(dm, *subdm)); 10050 /* Create map from submodel to global model */ 10051 if (is) { 10052 PetscSection sectionGlobal, subsectionGlobal; 10053 IS spIS; 10054 const PetscInt *spmap; 10055 PetscInt *subIndices; 10056 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10057 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10058 10059 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10060 PetscCall(ISGetIndices(spIS, &spmap)); 10061 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10062 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10063 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10064 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10065 for (p = pStart; p < pEnd; ++p) { 10066 PetscInt gdof, pSubSize = 0; 10067 10068 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10069 if (gdof > 0) { 10070 for (f = 0; f < Nf; ++f) { 10071 PetscInt fdof, fcdof; 10072 10073 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10074 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10075 pSubSize += fdof - fcdof; 10076 } 10077 subSize += pSubSize; 10078 if (pSubSize) { 10079 if (bs < 0) { 10080 bs = pSubSize; 10081 } else if (bs != pSubSize) { 10082 /* Layout does not admit a pointwise block size */ 10083 bs = 1; 10084 } 10085 } 10086 } 10087 } 10088 /* Must have same blocksize on all procs (some might have no points) */ 10089 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10090 bsLocal[1] = bs; 10091 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10092 if (bsMinMax[0] != bsMinMax[1]) { 10093 bs = 1; 10094 } else { 10095 bs = bsMinMax[0]; 10096 } 10097 PetscCall(PetscMalloc1(subSize, &subIndices)); 10098 for (p = pStart; p < pEnd; ++p) { 10099 PetscInt gdof, goff; 10100 10101 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10102 if (gdof > 0) { 10103 const PetscInt point = spmap[p]; 10104 10105 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10106 for (f = 0; f < Nf; ++f) { 10107 PetscInt fdof, fcdof, fc, f2, poff = 0; 10108 10109 /* Can get rid of this loop by storing field information in the global section */ 10110 for (f2 = 0; f2 < f; ++f2) { 10111 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10112 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10113 poff += fdof - fcdof; 10114 } 10115 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10116 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10117 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10118 } 10119 } 10120 } 10121 PetscCall(ISRestoreIndices(spIS, &spmap)); 10122 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10123 if (bs > 1) { 10124 /* We need to check that the block size does not come from non-contiguous fields */ 10125 PetscInt i, j, set = 1; 10126 for (i = 0; i < subSize; i += bs) { 10127 for (j = 0; j < bs; ++j) { 10128 if (subIndices[i + j] != subIndices[i] + j) { 10129 set = 0; 10130 break; 10131 } 10132 } 10133 } 10134 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10135 } 10136 /* Attach nullspace */ 10137 for (f = 0; f < Nf; ++f) { 10138 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10139 if ((*subdm)->nullspaceConstructors[f]) break; 10140 } 10141 if (f < Nf) { 10142 MatNullSpace nullSpace; 10143 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10144 10145 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10146 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10147 } 10148 } 10149 PetscFunctionReturn(PETSC_SUCCESS); 10150 } 10151 10152 /*@ 10153 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10154 10155 Input Parameters: 10156 + dm - The `DM` 10157 - dummy - unused argument 10158 10159 Options Database Key: 10160 . -dm_plex_monitor_throughput - Activate the monitor 10161 10162 Level: developer 10163 10164 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10165 @*/ 10166 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10167 { 10168 #if defined(PETSC_USE_LOG) 10169 PetscStageLog stageLog; 10170 PetscLogEvent event; 10171 PetscLogStage stage; 10172 PetscEventPerfInfo eventInfo; 10173 PetscReal cellRate, flopRate; 10174 PetscInt cStart, cEnd, Nf, N; 10175 const char *name; 10176 #endif 10177 10178 PetscFunctionBegin; 10179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10180 #if defined(PETSC_USE_LOG) 10181 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10182 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10183 PetscCall(DMGetNumFields(dm, &Nf)); 10184 PetscCall(PetscLogGetStageLog(&stageLog)); 10185 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10186 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10187 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10188 N = (cEnd - cStart) * Nf * eventInfo.count; 10189 flopRate = eventInfo.flops / eventInfo.time; 10190 cellRate = N / eventInfo.time; 10191 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))); 10192 #else 10193 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10194 #endif 10195 PetscFunctionReturn(PETSC_SUCCESS); 10196 } 10197