1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The `DMPLEX` object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Level: intermediate 28 29 Note: 30 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 31 If the mesh has no cells, this returns `PETSC_FALSE`. 32 33 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 34 @*/ 35 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 36 { 37 DMPolytopeType ct; 38 PetscInt cStart, cEnd; 39 40 PetscFunctionBegin; 41 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 42 if (cEnd <= cStart) { 43 *simplex = PETSC_FALSE; 44 PetscFunctionReturn(PETSC_SUCCESS); 45 } 46 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 47 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 48 PetscFunctionReturn(PETSC_SUCCESS); 49 } 50 51 /*@ 52 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 53 54 Input Parameters: 55 + dm - The `DMPLEX` object 56 - height - The cell height in the Plex, 0 is the default 57 58 Output Parameters: 59 + cStart - The first "normal" cell 60 - cEnd - The upper bound on "normal"" cells 61 62 Level: developer 63 64 Note: 65 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 66 67 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `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 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 127 if (globalvcdof[0]) { 128 *sStart = vStart; 129 *sEnd = vEnd; 130 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 131 else *ft = PETSC_VTK_POINT_FIELD; 132 } else if (globalvcdof[1]) { 133 *sStart = cStart; 134 *sEnd = cEnd; 135 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 136 else *ft = PETSC_VTK_CELL_FIELD; 137 } else { 138 if (field >= 0) { 139 const char *fieldname; 140 141 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 143 } else { 144 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 145 } 146 } 147 PetscFunctionReturn(PETSC_SUCCESS); 148 } 149 150 /*@ 151 DMPlexVecView1D - Plot many 1D solutions on the same line graph 152 153 Collective 154 155 Input Parameters: 156 + dm - The `DMPLEX` object 157 . n - The number of vectors 158 . u - The array of local vectors 159 - viewer - The `PetscViewer` 160 161 Level: advanced 162 163 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 164 @*/ 165 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 166 { 167 PetscDS ds; 168 PetscDraw draw = NULL; 169 PetscDrawLG lg; 170 Vec coordinates; 171 const PetscScalar *coords, **sol; 172 PetscReal *vals; 173 PetscInt *Nc; 174 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 175 char **names; 176 177 PetscFunctionBegin; 178 PetscCall(DMGetDS(dm, &ds)); 179 PetscCall(PetscDSGetNumFields(ds, &Nf)); 180 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 181 PetscCall(PetscDSGetComponents(ds, &Nc)); 182 183 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 184 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 185 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 186 187 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 188 for (i = 0, l = 0; i < n; ++i) { 189 const char *vname; 190 191 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 192 for (f = 0; f < Nf; ++f) { 193 PetscObject disc; 194 const char *fname; 195 char tmpname[PETSC_MAX_PATH_LEN]; 196 197 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 198 /* TODO Create names for components */ 199 for (c = 0; c < Nc[f]; ++c, ++l) { 200 PetscCall(PetscObjectGetName(disc, &fname)); 201 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 202 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 203 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 204 PetscCall(PetscStrallocpy(tmpname, &names[l])); 205 } 206 } 207 } 208 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 209 /* Just add P_1 support for now */ 210 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 211 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 212 PetscCall(VecGetArrayRead(coordinates, &coords)); 213 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 214 for (v = vStart; v < vEnd; ++v) { 215 PetscScalar *x, *svals; 216 217 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 218 for (i = 0; i < n; ++i) { 219 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 220 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 221 } 222 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 223 } 224 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 225 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 226 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 227 PetscCall(PetscFree3(sol, names, vals)); 228 229 PetscCall(PetscDrawLGDraw(lg)); 230 PetscCall(PetscDrawLGDestroy(&lg)); 231 PetscFunctionReturn(PETSC_SUCCESS); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 235 { 236 DM dm; 237 238 PetscFunctionBegin; 239 PetscCall(VecGetDM(u, &dm)); 240 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 241 PetscFunctionReturn(PETSC_SUCCESS); 242 } 243 244 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 245 { 246 DM dm; 247 PetscSection s; 248 PetscDraw draw, popup; 249 DM cdm; 250 PetscSection coordSection; 251 Vec coordinates; 252 const PetscScalar *array; 253 PetscReal lbound[3], ubound[3]; 254 PetscReal vbound[2], time; 255 PetscBool flg; 256 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 257 const char *name; 258 char title[PETSC_MAX_PATH_LEN]; 259 260 PetscFunctionBegin; 261 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 262 PetscCall(VecGetDM(v, &dm)); 263 PetscCall(DMGetCoordinateDim(dm, &dim)); 264 PetscCall(DMGetLocalSection(dm, &s)); 265 PetscCall(PetscSectionGetNumFields(s, &Nf)); 266 PetscCall(DMGetCoarsenLevel(dm, &level)); 267 PetscCall(DMGetCoordinateDM(dm, &cdm)); 268 PetscCall(DMGetLocalSection(cdm, &coordSection)); 269 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 270 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 271 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 272 273 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 274 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 275 276 PetscCall(VecGetLocalSize(coordinates, &N)); 277 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 278 PetscCall(PetscDrawClear(draw)); 279 280 /* Could implement something like DMDASelectFields() */ 281 for (f = 0; f < Nf; ++f) { 282 DM fdm = dm; 283 Vec fv = v; 284 IS fis; 285 char prefix[PETSC_MAX_PATH_LEN]; 286 const char *fname; 287 288 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 289 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 290 291 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 292 else prefix[0] = '\0'; 293 if (Nf > 1) { 294 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 295 PetscCall(VecGetSubVector(v, fis, &fv)); 296 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 297 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 298 } 299 for (comp = 0; comp < Nc; ++comp, ++w) { 300 PetscInt nmax = 2; 301 302 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 303 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 304 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 305 PetscCall(PetscDrawSetTitle(draw, title)); 306 307 /* TODO Get max and min only for this component */ 308 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 309 if (!flg) { 310 PetscCall(VecMin(fv, NULL, &vbound[0])); 311 PetscCall(VecMax(fv, NULL, &vbound[1])); 312 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 313 } 314 315 PetscCall(PetscDrawGetPopup(draw, &popup)); 316 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 317 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 318 PetscCall(VecGetArrayRead(fv, &array)); 319 for (c = cStart; c < cEnd; ++c) { 320 PetscScalar *coords = NULL, *a = NULL; 321 const PetscScalar *coords_arr; 322 PetscBool isDG; 323 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 324 325 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 326 if (a) { 327 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 328 color[1] = color[2] = color[3] = color[0]; 329 } else { 330 PetscScalar *vals = NULL; 331 PetscInt numVals, va; 332 333 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 334 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 335 switch (numVals / Nc) { 336 case 3: /* P1 Triangle */ 337 case 4: /* P1 Quadrangle */ 338 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 339 break; 340 case 6: /* P2 Triangle */ 341 case 8: /* P2 Quadrangle */ 342 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 343 break; 344 default: 345 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 346 } 347 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 348 } 349 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 350 switch (numCoords) { 351 case 6: 352 case 12: /* Localized triangle */ 353 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 354 break; 355 case 8: 356 case 16: /* Localized quadrilateral */ 357 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 358 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 359 break; 360 default: 361 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 362 } 363 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 364 } 365 PetscCall(VecRestoreArrayRead(fv, &array)); 366 PetscCall(PetscDrawFlush(draw)); 367 PetscCall(PetscDrawPause(draw)); 368 PetscCall(PetscDrawSave(draw)); 369 } 370 if (Nf > 1) { 371 PetscCall(VecRestoreSubVector(v, fis, &fv)); 372 PetscCall(ISDestroy(&fis)); 373 PetscCall(DMDestroy(&fdm)); 374 } 375 } 376 PetscFunctionReturn(PETSC_SUCCESS); 377 } 378 379 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 380 { 381 DM dm; 382 PetscDraw draw; 383 PetscInt dim; 384 PetscBool isnull; 385 386 PetscFunctionBegin; 387 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 388 PetscCall(PetscDrawIsNull(draw, &isnull)); 389 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 390 391 PetscCall(VecGetDM(v, &dm)); 392 PetscCall(DMGetCoordinateDim(dm, &dim)); 393 switch (dim) { 394 case 1: 395 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 396 break; 397 case 2: 398 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 399 break; 400 default: 401 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 402 } 403 PetscFunctionReturn(PETSC_SUCCESS); 404 } 405 406 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 407 { 408 DM dm; 409 Vec locv; 410 const char *name; 411 PetscSection section; 412 PetscInt pStart, pEnd; 413 PetscInt numFields; 414 PetscViewerVTKFieldType ft; 415 416 PetscFunctionBegin; 417 PetscCall(VecGetDM(v, &dm)); 418 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 419 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 420 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 421 PetscCall(VecCopy(v, locv)); 422 PetscCall(DMGetLocalSection(dm, §ion)); 423 PetscCall(PetscSectionGetNumFields(section, &numFields)); 424 if (!numFields) { 425 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 426 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 427 } else { 428 PetscInt f; 429 430 for (f = 0; f < numFields; f++) { 431 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 432 if (ft == PETSC_VTK_INVALID) continue; 433 PetscCall(PetscObjectReference((PetscObject)locv)); 434 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 435 } 436 PetscCall(VecDestroy(&locv)); 437 } 438 PetscFunctionReturn(PETSC_SUCCESS); 439 } 440 441 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 442 { 443 DM dm; 444 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 445 446 PetscFunctionBegin; 447 PetscCall(VecGetDM(v, &dm)); 448 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 449 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 450 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 451 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 453 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 454 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 455 PetscInt i, numFields; 456 PetscObject fe; 457 PetscBool fem = PETSC_FALSE; 458 Vec locv = v; 459 const char *name; 460 PetscInt step; 461 PetscReal time; 462 463 PetscCall(DMGetNumFields(dm, &numFields)); 464 for (i = 0; i < numFields; i++) { 465 PetscCall(DMGetField(dm, i, NULL, &fe)); 466 if (fe->classid == PETSCFE_CLASSID) { 467 fem = PETSC_TRUE; 468 break; 469 } 470 } 471 if (fem) { 472 PetscObject isZero; 473 474 PetscCall(DMGetLocalVector(dm, &locv)); 475 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 476 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 477 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 478 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 479 PetscCall(VecCopy(v, locv)); 480 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 481 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 482 } 483 if (isvtk) { 484 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 485 } else if (ishdf5) { 486 #if defined(PETSC_HAVE_HDF5) 487 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 488 #else 489 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 490 #endif 491 } else if (isdraw) { 492 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 493 } else if (isglvis) { 494 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 495 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 496 PetscCall(VecView_GLVis(locv, viewer)); 497 } else if (iscgns) { 498 #if defined(PETSC_HAVE_CGNS) 499 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 500 #else 501 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 502 #endif 503 } 504 if (fem) { 505 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 506 PetscCall(DMRestoreLocalVector(dm, &locv)); 507 } 508 } else { 509 PetscBool isseq; 510 511 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 512 if (isseq) PetscCall(VecView_Seq(v, viewer)); 513 else PetscCall(VecView_MPI(v, viewer)); 514 } 515 PetscFunctionReturn(PETSC_SUCCESS); 516 } 517 518 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 519 { 520 DM dm; 521 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 526 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 527 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 528 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 529 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 530 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 532 if (isvtk || isdraw || isglvis || iscgns) { 533 Vec locv; 534 PetscObject isZero; 535 const char *name; 536 537 PetscCall(DMGetLocalVector(dm, &locv)); 538 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 539 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 540 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 541 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 542 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 543 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 544 PetscCall(VecView_Plex_Local(locv, viewer)); 545 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 546 PetscCall(DMRestoreLocalVector(dm, &locv)); 547 } else if (ishdf5) { 548 #if defined(PETSC_HAVE_HDF5) 549 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 550 #else 551 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 552 #endif 553 } else if (isexodusii) { 554 #if defined(PETSC_HAVE_EXODUSII) 555 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 556 #else 557 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 558 #endif 559 } else { 560 PetscBool isseq; 561 562 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 563 if (isseq) PetscCall(VecView_Seq(v, viewer)); 564 else PetscCall(VecView_MPI(v, viewer)); 565 } 566 PetscFunctionReturn(PETSC_SUCCESS); 567 } 568 569 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 570 { 571 DM dm; 572 MPI_Comm comm; 573 PetscViewerFormat format; 574 Vec v; 575 PetscBool isvtk, ishdf5; 576 577 PetscFunctionBegin; 578 PetscCall(VecGetDM(originalv, &dm)); 579 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 580 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 581 PetscCall(PetscViewerGetFormat(viewer, &format)); 582 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 583 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 584 if (format == PETSC_VIEWER_NATIVE) { 585 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 586 /* this need a better fix */ 587 if (dm->useNatural) { 588 if (dm->sfNatural) { 589 const char *vecname; 590 PetscInt n, nroots; 591 592 PetscCall(VecGetLocalSize(originalv, &n)); 593 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 594 if (n == nroots) { 595 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 596 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 597 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 598 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 599 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 600 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 601 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 602 } else v = originalv; 603 } else v = originalv; 604 605 if (ishdf5) { 606 #if defined(PETSC_HAVE_HDF5) 607 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 608 #else 609 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 610 #endif 611 } else if (isvtk) { 612 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 613 } else { 614 PetscBool isseq; 615 616 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 617 if (isseq) PetscCall(VecView_Seq(v, viewer)); 618 else PetscCall(VecView_MPI(v, viewer)); 619 } 620 if (v != originalv) PetscCall(VecDestroy(&v)); 621 PetscFunctionReturn(PETSC_SUCCESS); 622 } 623 624 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 625 { 626 DM dm; 627 PetscBool ishdf5; 628 629 PetscFunctionBegin; 630 PetscCall(VecGetDM(v, &dm)); 631 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 632 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 633 if (ishdf5) { 634 DM dmBC; 635 Vec gv; 636 const char *name; 637 638 PetscCall(DMGetOutputDM(dm, &dmBC)); 639 PetscCall(DMGetGlobalVector(dmBC, &gv)); 640 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 641 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 642 PetscCall(VecLoad_Default(gv, viewer)); 643 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 644 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 645 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 646 } else PetscCall(VecLoad_Default(v, viewer)); 647 PetscFunctionReturn(PETSC_SUCCESS); 648 } 649 650 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 651 { 652 DM dm; 653 PetscBool ishdf5, isexodusii; 654 655 PetscFunctionBegin; 656 PetscCall(VecGetDM(v, &dm)); 657 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 658 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 659 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 660 if (ishdf5) { 661 #if defined(PETSC_HAVE_HDF5) 662 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 665 #endif 666 } else if (isexodusii) { 667 #if defined(PETSC_HAVE_EXODUSII) 668 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 669 #else 670 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 671 #endif 672 } else PetscCall(VecLoad_Default(v, viewer)); 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 PetscViewerFormat format; 680 PetscBool ishdf5; 681 682 PetscFunctionBegin; 683 PetscCall(VecGetDM(originalv, &dm)); 684 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 685 PetscCall(PetscViewerGetFormat(viewer, &format)); 686 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 687 if (format == PETSC_VIEWER_NATIVE) { 688 if (dm->useNatural) { 689 if (dm->sfNatural) { 690 if (ishdf5) { 691 #if defined(PETSC_HAVE_HDF5) 692 Vec v; 693 const char *vecname; 694 695 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 696 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 697 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 698 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 699 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 700 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 701 PetscCall(VecDestroy(&v)); 702 #else 703 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 704 #endif 705 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 706 } 707 } else PetscCall(VecLoad_Default(originalv, viewer)); 708 } 709 PetscFunctionReturn(PETSC_SUCCESS); 710 } 711 712 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 713 { 714 PetscSection coordSection; 715 Vec coordinates; 716 DMLabel depthLabel, celltypeLabel; 717 const char *name[4]; 718 const PetscScalar *a; 719 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 720 721 PetscFunctionBegin; 722 PetscCall(DMGetDimension(dm, &dim)); 723 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 724 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 725 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 726 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 727 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 728 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 729 PetscCall(VecGetArrayRead(coordinates, &a)); 730 name[0] = "vertex"; 731 name[1] = "edge"; 732 name[dim - 1] = "face"; 733 name[dim] = "cell"; 734 for (c = cStart; c < cEnd; ++c) { 735 PetscInt *closure = NULL; 736 PetscInt closureSize, cl, ct; 737 738 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 739 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 740 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 741 PetscCall(PetscViewerASCIIPushTab(viewer)); 742 for (cl = 0; cl < closureSize * 2; cl += 2) { 743 PetscInt point = closure[cl], depth, dof, off, d, p; 744 745 if ((point < pStart) || (point >= pEnd)) continue; 746 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 747 if (!dof) continue; 748 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 749 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 750 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 751 for (p = 0; p < dof / dim; ++p) { 752 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 753 for (d = 0; d < dim; ++d) { 754 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 755 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 756 } 757 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 758 } 759 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 760 } 761 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 762 PetscCall(PetscViewerASCIIPopTab(viewer)); 763 } 764 PetscCall(VecRestoreArrayRead(coordinates, &a)); 765 PetscFunctionReturn(PETSC_SUCCESS); 766 } 767 768 typedef enum { 769 CS_CARTESIAN, 770 CS_POLAR, 771 CS_CYLINDRICAL, 772 CS_SPHERICAL 773 } CoordSystem; 774 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 775 776 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 777 { 778 PetscInt i; 779 780 PetscFunctionBegin; 781 if (dim > 3) { 782 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 783 } else { 784 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 785 786 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 787 switch (cs) { 788 case CS_CARTESIAN: 789 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 790 break; 791 case CS_POLAR: 792 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 793 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 794 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 795 break; 796 case CS_CYLINDRICAL: 797 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 798 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 799 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 800 trcoords[2] = coords[2]; 801 break; 802 case CS_SPHERICAL: 803 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 804 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 805 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 806 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 807 break; 808 } 809 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 810 } 811 PetscFunctionReturn(PETSC_SUCCESS); 812 } 813 814 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 815 { 816 DM_Plex *mesh = (DM_Plex *)dm->data; 817 DM cdm, cdmCell; 818 PetscSection coordSection, coordSectionCell; 819 Vec coordinates, coordinatesCell; 820 PetscViewerFormat format; 821 822 PetscFunctionBegin; 823 PetscCall(PetscViewerGetFormat(viewer, &format)); 824 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 825 const char *name; 826 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 827 PetscInt pStart, pEnd, p, numLabels, l; 828 PetscMPIInt rank, size; 829 830 PetscCall(DMGetCoordinateDM(dm, &cdm)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 833 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 834 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 835 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 836 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 837 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 838 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 839 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 840 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 841 PetscCall(DMGetDimension(dm, &dim)); 842 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 843 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 844 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 845 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 847 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 848 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 849 for (p = pStart; p < pEnd; ++p) { 850 PetscInt dof, off, s; 851 852 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 853 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 854 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 855 } 856 PetscCall(PetscViewerFlush(viewer)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 858 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 859 for (p = pStart; p < pEnd; ++p) { 860 PetscInt dof, off, c; 861 862 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 863 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 864 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 865 } 866 PetscCall(PetscViewerFlush(viewer)); 867 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 868 if (coordSection && coordinates) { 869 CoordSystem cs = CS_CARTESIAN; 870 const PetscScalar *array, *arrayCell = NULL; 871 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 872 PetscMPIInt rank; 873 const char *name; 874 875 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 876 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 877 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 878 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 879 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 880 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 881 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 882 pStart = PetscMin(pvStart, pcStart); 883 pEnd = PetscMax(pvEnd, pcEnd); 884 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 885 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 886 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 887 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 888 889 PetscCall(VecGetArrayRead(coordinates, &array)); 890 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 891 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 892 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 893 for (p = pStart; p < pEnd; ++p) { 894 PetscInt dof, off; 895 896 if (p >= pvStart && p < pvEnd) { 897 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 898 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 899 if (dof) { 900 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 901 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 902 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 903 } 904 } 905 if (cdmCell && p >= pcStart && p < pcEnd) { 906 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 907 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 908 if (dof) { 909 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 910 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 911 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 912 } 913 } 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 917 PetscCall(VecRestoreArrayRead(coordinates, &array)); 918 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 919 } 920 PetscCall(DMGetNumLabels(dm, &numLabels)); 921 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 922 for (l = 0; l < numLabels; ++l) { 923 DMLabel label; 924 PetscBool isdepth; 925 const char *name; 926 927 PetscCall(DMGetLabelName(dm, l, &name)); 928 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 929 if (isdepth) continue; 930 PetscCall(DMGetLabel(dm, name, &label)); 931 PetscCall(DMLabelView(label, viewer)); 932 } 933 if (size > 1) { 934 PetscSF sf; 935 936 PetscCall(DMGetPointSF(dm, &sf)); 937 PetscCall(PetscSFView(sf, viewer)); 938 } 939 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 940 PetscCall(PetscViewerFlush(viewer)); 941 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 942 const char *name, *color; 943 const char *defcolors[3] = {"gray", "orange", "green"}; 944 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 945 char lname[PETSC_MAX_PATH_LEN]; 946 PetscReal scale = 2.0; 947 PetscReal tikzscale = 1.0; 948 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 949 double tcoords[3]; 950 PetscScalar *coords; 951 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 952 PetscMPIInt rank, size; 953 char **names, **colors, **lcolors; 954 PetscBool flg, lflg; 955 PetscBT wp = NULL; 956 PetscInt pEnd, pStart; 957 958 PetscCall(DMGetCoordinateDM(dm, &cdm)); 959 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 960 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 961 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 962 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 963 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 964 PetscCall(DMGetDimension(dm, &dim)); 965 PetscCall(DMPlexGetDepth(dm, &depth)); 966 PetscCall(DMGetNumLabels(dm, &numLabels)); 967 numLabels = PetscMax(numLabels, 10); 968 numColors = 10; 969 numLColors = 10; 970 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 971 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 972 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 973 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 974 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 975 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 976 n = 4; 977 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 978 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 979 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 980 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 981 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 982 if (!useLabels) numLabels = 0; 983 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 984 if (!useColors) { 985 numColors = 3; 986 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 987 } 988 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 989 if (!useColors) { 990 numLColors = 4; 991 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 992 } 993 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 994 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 995 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 996 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 997 if (depth < dim) plotEdges = PETSC_FALSE; 998 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 999 1000 /* filter points with labelvalue != labeldefaultvalue */ 1001 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1002 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1003 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1004 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1005 if (lflg) { 1006 DMLabel lbl; 1007 1008 PetscCall(DMGetLabel(dm, lname, &lbl)); 1009 if (lbl) { 1010 PetscInt val, defval; 1011 1012 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1013 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1014 for (c = pStart; c < pEnd; c++) { 1015 PetscInt *closure = NULL; 1016 PetscInt closureSize; 1017 1018 PetscCall(DMLabelGetValue(lbl, c, &val)); 1019 if (val == defval) continue; 1020 1021 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1022 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1023 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1024 } 1025 } 1026 } 1027 1028 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1029 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1030 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1031 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1032 \\documentclass[tikz]{standalone}\n\n\ 1033 \\usepackage{pgflibraryshapes}\n\ 1034 \\usetikzlibrary{backgrounds}\n\ 1035 \\usetikzlibrary{arrows}\n\ 1036 \\begin{document}\n")); 1037 if (size > 1) { 1038 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1039 for (p = 0; p < size; ++p) { 1040 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1041 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1042 } 1043 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1044 } 1045 if (drawHasse) { 1046 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1047 1048 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1049 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1050 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1058 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1060 } 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1062 1063 /* Plot vertices */ 1064 PetscCall(VecGetArray(coordinates, &coords)); 1065 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1066 for (v = vStart; v < vEnd; ++v) { 1067 PetscInt off, dof, d; 1068 PetscBool isLabeled = PETSC_FALSE; 1069 1070 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1071 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1072 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1073 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1074 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1075 for (d = 0; d < dof; ++d) { 1076 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1077 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1078 } 1079 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1080 if (dim == 3) { 1081 PetscReal tmp = tcoords[1]; 1082 tcoords[1] = tcoords[2]; 1083 tcoords[2] = -tmp; 1084 } 1085 for (d = 0; d < dof; ++d) { 1086 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1088 } 1089 if (drawHasse) color = colors[0 % numColors]; 1090 else color = colors[rank % numColors]; 1091 for (l = 0; l < numLabels; ++l) { 1092 PetscInt val; 1093 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1094 if (val >= 0) { 1095 color = lcolors[l % numLColors]; 1096 isLabeled = PETSC_TRUE; 1097 break; 1098 } 1099 } 1100 if (drawNumbers[0]) { 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1102 } else if (drawColors[0]) { 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1104 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1105 } 1106 PetscCall(VecRestoreArray(coordinates, &coords)); 1107 PetscCall(PetscViewerFlush(viewer)); 1108 /* Plot edges */ 1109 if (plotEdges) { 1110 PetscCall(VecGetArray(coordinates, &coords)); 1111 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1112 for (e = eStart; e < eEnd; ++e) { 1113 const PetscInt *cone; 1114 PetscInt coneSize, offA, offB, dof, d; 1115 1116 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1117 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1118 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1119 PetscCall(DMPlexGetCone(dm, e, &cone)); 1120 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1121 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1122 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1123 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1124 for (d = 0; d < dof; ++d) { 1125 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1126 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1127 } 1128 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1129 if (dim == 3) { 1130 PetscReal tmp = tcoords[1]; 1131 tcoords[1] = tcoords[2]; 1132 tcoords[2] = -tmp; 1133 } 1134 for (d = 0; d < dof; ++d) { 1135 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1136 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1137 } 1138 if (drawHasse) color = colors[1 % numColors]; 1139 else color = colors[rank % numColors]; 1140 for (l = 0; l < numLabels; ++l) { 1141 PetscInt val; 1142 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1143 if (val >= 0) { 1144 color = lcolors[l % numLColors]; 1145 break; 1146 } 1147 } 1148 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1149 } 1150 PetscCall(VecRestoreArray(coordinates, &coords)); 1151 PetscCall(PetscViewerFlush(viewer)); 1152 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1153 } 1154 /* Plot cells */ 1155 if (dim == 3 || !drawNumbers[1]) { 1156 for (e = eStart; e < eEnd; ++e) { 1157 const PetscInt *cone; 1158 1159 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1160 color = colors[rank % numColors]; 1161 for (l = 0; l < numLabels; ++l) { 1162 PetscInt val; 1163 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1164 if (val >= 0) { 1165 color = lcolors[l % numLColors]; 1166 break; 1167 } 1168 } 1169 PetscCall(DMPlexGetCone(dm, e, &cone)); 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1171 } 1172 } else { 1173 DMPolytopeType ct; 1174 1175 /* Drawing a 2D polygon */ 1176 for (c = cStart; c < cEnd; ++c) { 1177 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1178 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1179 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1180 const PetscInt *cone; 1181 PetscInt coneSize, e; 1182 1183 PetscCall(DMPlexGetCone(dm, c, &cone)); 1184 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1185 for (e = 0; e < coneSize; ++e) { 1186 const PetscInt *econe; 1187 1188 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1190 } 1191 } else { 1192 PetscInt *closure = NULL; 1193 PetscInt closureSize, Nv = 0, v; 1194 1195 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1196 for (p = 0; p < closureSize * 2; p += 2) { 1197 const PetscInt point = closure[p]; 1198 1199 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1200 } 1201 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1202 for (v = 0; v <= Nv; ++v) { 1203 const PetscInt vertex = closure[v % Nv]; 1204 1205 if (v > 0) { 1206 if (plotEdges) { 1207 const PetscInt *edge; 1208 PetscInt endpoints[2], ne; 1209 1210 endpoints[0] = closure[v - 1]; 1211 endpoints[1] = vertex; 1212 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1213 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1214 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1215 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1216 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1217 } 1218 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1219 } 1220 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1221 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1222 } 1223 } 1224 } 1225 for (c = cStart; c < cEnd; ++c) { 1226 double ccoords[3] = {0.0, 0.0, 0.0}; 1227 PetscBool isLabeled = PETSC_FALSE; 1228 PetscScalar *cellCoords = NULL; 1229 const PetscScalar *array; 1230 PetscInt numCoords, cdim, d; 1231 PetscBool isDG; 1232 1233 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1234 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1235 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1236 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1237 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1238 for (p = 0; p < numCoords / cdim; ++p) { 1239 for (d = 0; d < cdim; ++d) { 1240 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1241 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1242 } 1243 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1244 if (cdim == 3) { 1245 PetscReal tmp = tcoords[1]; 1246 tcoords[1] = tcoords[2]; 1247 tcoords[2] = -tmp; 1248 } 1249 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1250 } 1251 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1252 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1253 for (d = 0; d < cdim; ++d) { 1254 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1255 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1256 } 1257 if (drawHasse) color = colors[depth % numColors]; 1258 else color = colors[rank % numColors]; 1259 for (l = 0; l < numLabels; ++l) { 1260 PetscInt val; 1261 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1262 if (val >= 0) { 1263 color = lcolors[l % numLColors]; 1264 isLabeled = PETSC_TRUE; 1265 break; 1266 } 1267 } 1268 if (drawNumbers[dim]) { 1269 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1270 } else if (drawColors[dim]) { 1271 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1272 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1273 } 1274 if (drawHasse) { 1275 color = colors[depth % numColors]; 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1278 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1279 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1280 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1281 1282 color = colors[1 % numColors]; 1283 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1284 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1286 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1287 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1288 1289 color = colors[0 % numColors]; 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1291 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1293 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1294 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1295 1296 for (p = pStart; p < pEnd; ++p) { 1297 const PetscInt *cone; 1298 PetscInt coneSize, cp; 1299 1300 PetscCall(DMPlexGetCone(dm, p, &cone)); 1301 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1302 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1303 } 1304 } 1305 PetscCall(PetscViewerFlush(viewer)); 1306 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1307 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1308 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1309 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1310 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1311 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1312 PetscCall(PetscFree3(names, colors, lcolors)); 1313 PetscCall(PetscBTDestroy(&wp)); 1314 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1315 Vec cown, acown; 1316 VecScatter sct; 1317 ISLocalToGlobalMapping g2l; 1318 IS gid, acis; 1319 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1320 MPI_Group ggroup, ngroup; 1321 PetscScalar *array, nid; 1322 const PetscInt *idxs; 1323 PetscInt *idxs2, *start, *adjacency, *work; 1324 PetscInt64 lm[3], gm[3]; 1325 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1326 PetscMPIInt d1, d2, rank; 1327 1328 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1329 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1330 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1331 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1332 #endif 1333 if (ncomm != MPI_COMM_NULL) { 1334 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1335 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1336 d1 = 0; 1337 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1338 nid = d2; 1339 PetscCallMPI(MPI_Group_free(&ggroup)); 1340 PetscCallMPI(MPI_Group_free(&ngroup)); 1341 PetscCallMPI(MPI_Comm_free(&ncomm)); 1342 } else nid = 0.0; 1343 1344 /* Get connectivity */ 1345 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1346 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1347 1348 /* filter overlapped local cells */ 1349 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1350 PetscCall(ISGetIndices(gid, &idxs)); 1351 PetscCall(ISGetLocalSize(gid, &cum)); 1352 PetscCall(PetscMalloc1(cum, &idxs2)); 1353 for (c = cStart, cum = 0; c < cEnd; c++) { 1354 if (idxs[c - cStart] < 0) continue; 1355 idxs2[cum++] = idxs[c - cStart]; 1356 } 1357 PetscCall(ISRestoreIndices(gid, &idxs)); 1358 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1359 PetscCall(ISDestroy(&gid)); 1360 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1361 1362 /* support for node-aware cell locality */ 1363 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1364 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1365 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1366 PetscCall(VecGetArray(cown, &array)); 1367 for (c = 0; c < numVertices; c++) array[c] = nid; 1368 PetscCall(VecRestoreArray(cown, &array)); 1369 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1370 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1371 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1372 PetscCall(ISDestroy(&acis)); 1373 PetscCall(VecScatterDestroy(&sct)); 1374 PetscCall(VecDestroy(&cown)); 1375 1376 /* compute edgeCut */ 1377 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1378 PetscCall(PetscMalloc1(cum, &work)); 1379 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1380 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1381 PetscCall(ISDestroy(&gid)); 1382 PetscCall(VecGetArray(acown, &array)); 1383 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1384 PetscInt totl; 1385 1386 totl = start[c + 1] - start[c]; 1387 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1388 for (i = 0; i < totl; i++) { 1389 if (work[i] < 0) { 1390 ect += 1; 1391 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1392 } 1393 } 1394 } 1395 PetscCall(PetscFree(work)); 1396 PetscCall(VecRestoreArray(acown, &array)); 1397 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1398 lm[1] = -numVertices; 1399 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1401 lm[0] = ect; /* edgeCut */ 1402 lm[1] = ectn; /* node-aware edgeCut */ 1403 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1404 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1406 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1407 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1408 #else 1409 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1410 #endif 1411 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1412 PetscCall(PetscFree(start)); 1413 PetscCall(PetscFree(adjacency)); 1414 PetscCall(VecDestroy(&acown)); 1415 } else { 1416 const char *name; 1417 PetscInt *sizes, *hybsizes, *ghostsizes; 1418 PetscInt locDepth, depth, cellHeight, dim, d; 1419 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1420 PetscInt numLabels, l, maxSize = 17; 1421 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1422 MPI_Comm comm; 1423 PetscMPIInt size, rank; 1424 1425 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1426 PetscCallMPI(MPI_Comm_size(comm, &size)); 1427 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1428 PetscCall(DMGetDimension(dm, &dim)); 1429 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1430 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1431 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1432 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1433 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1434 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1435 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1436 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1437 gcNum = gcEnd - gcStart; 1438 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1439 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1440 for (d = 0; d <= depth; d++) { 1441 PetscInt Nc[2] = {0, 0}, ict; 1442 1443 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1444 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1445 ict = ct0; 1446 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1447 ct0 = (DMPolytopeType)ict; 1448 for (p = pStart; p < pEnd; ++p) { 1449 DMPolytopeType ct; 1450 1451 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1452 if (ct == ct0) ++Nc[0]; 1453 else ++Nc[1]; 1454 } 1455 if (size < maxSize) { 1456 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1457 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1458 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1459 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1460 for (p = 0; p < size; ++p) { 1461 if (rank == 0) { 1462 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1463 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1464 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1465 } 1466 } 1467 } else { 1468 PetscInt locMinMax[2]; 1469 1470 locMinMax[0] = Nc[0] + Nc[1]; 1471 locMinMax[1] = Nc[0] + Nc[1]; 1472 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1473 locMinMax[0] = Nc[1]; 1474 locMinMax[1] = Nc[1]; 1475 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1476 if (d == depth) { 1477 locMinMax[0] = gcNum; 1478 locMinMax[1] = gcNum; 1479 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1480 } 1481 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1483 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1484 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1485 } 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1487 } 1488 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1489 { 1490 const PetscReal *maxCell; 1491 const PetscReal *L; 1492 PetscBool localized; 1493 1494 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1495 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1496 if (L || localized) { 1497 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1498 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1499 if (L) { 1500 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1501 for (d = 0; d < dim; ++d) { 1502 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1504 } 1505 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1506 } 1507 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1508 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1509 } 1510 } 1511 PetscCall(DMGetNumLabels(dm, &numLabels)); 1512 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1513 for (l = 0; l < numLabels; ++l) { 1514 DMLabel label; 1515 const char *name; 1516 IS valueIS; 1517 const PetscInt *values; 1518 PetscInt numValues, v; 1519 1520 PetscCall(DMGetLabelName(dm, l, &name)); 1521 PetscCall(DMGetLabel(dm, name, &label)); 1522 PetscCall(DMLabelGetNumValues(label, &numValues)); 1523 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1524 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1525 PetscCall(ISGetIndices(valueIS, &values)); 1526 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1527 for (v = 0; v < numValues; ++v) { 1528 PetscInt size; 1529 1530 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1531 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1532 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1533 } 1534 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1535 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1536 PetscCall(ISRestoreIndices(valueIS, &values)); 1537 PetscCall(ISDestroy(&valueIS)); 1538 } 1539 { 1540 char **labelNames; 1541 PetscInt Nl = numLabels; 1542 PetscBool flg; 1543 1544 PetscCall(PetscMalloc1(Nl, &labelNames)); 1545 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1546 for (l = 0; l < Nl; ++l) { 1547 DMLabel label; 1548 1549 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1550 if (flg) { 1551 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1552 PetscCall(DMLabelView(label, viewer)); 1553 } 1554 PetscCall(PetscFree(labelNames[l])); 1555 } 1556 PetscCall(PetscFree(labelNames)); 1557 } 1558 /* If no fields are specified, people do not want to see adjacency */ 1559 if (dm->Nf) { 1560 PetscInt f; 1561 1562 for (f = 0; f < dm->Nf; ++f) { 1563 const char *name; 1564 1565 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1566 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1567 PetscCall(PetscViewerASCIIPushTab(viewer)); 1568 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1569 if (dm->fields[f].adjacency[0]) { 1570 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1571 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1572 } else { 1573 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1574 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1575 } 1576 PetscCall(PetscViewerASCIIPopTab(viewer)); 1577 } 1578 } 1579 PetscCall(DMGetCoarseDM(dm, &cdm)); 1580 if (cdm) { 1581 PetscCall(PetscViewerASCIIPushTab(viewer)); 1582 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1583 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1584 PetscCall(PetscViewerASCIIPopTab(viewer)); 1585 } 1586 } 1587 PetscFunctionReturn(PETSC_SUCCESS); 1588 } 1589 1590 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1591 { 1592 DMPolytopeType ct; 1593 PetscMPIInt rank; 1594 PetscInt cdim; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1600 switch (ct) { 1601 case DM_POLYTOPE_SEGMENT: 1602 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1603 switch (cdim) { 1604 case 1: { 1605 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1606 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1607 1608 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1609 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1610 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1611 } break; 1612 case 2: { 1613 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1614 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1615 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1616 1617 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1618 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1619 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1620 } break; 1621 default: 1622 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1623 } 1624 break; 1625 case DM_POLYTOPE_TRIANGLE: 1626 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1627 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1628 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1629 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1630 break; 1631 case DM_POLYTOPE_QUADRILATERAL: 1632 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1633 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1634 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1635 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1636 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1637 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1638 break; 1639 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1640 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1641 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1642 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1643 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1644 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1645 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1646 break; 1647 case DM_POLYTOPE_FV_GHOST: 1648 break; 1649 default: 1650 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1651 } 1652 PetscFunctionReturn(PETSC_SUCCESS); 1653 } 1654 1655 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1656 { 1657 DMPolytopeType ct; 1658 PetscReal centroid[2] = {0., 0.}; 1659 PetscMPIInt rank; 1660 PetscInt fillColor, v, e, d; 1661 1662 PetscFunctionBegin; 1663 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1664 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1665 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1666 switch (ct) { 1667 case DM_POLYTOPE_TRIANGLE: { 1668 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1669 1670 for (v = 0; v < 3; ++v) { 1671 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1672 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1673 } 1674 for (e = 0; e < 3; ++e) { 1675 refCoords[0] = refVertices[e * 2 + 0]; 1676 refCoords[1] = refVertices[e * 2 + 1]; 1677 for (d = 1; d <= edgeDiv; ++d) { 1678 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1679 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1680 } 1681 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1682 for (d = 0; d < edgeDiv; ++d) { 1683 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1684 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1685 } 1686 } 1687 } break; 1688 default: 1689 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1690 } 1691 PetscFunctionReturn(PETSC_SUCCESS); 1692 } 1693 1694 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1695 { 1696 PetscDraw draw; 1697 DM cdm; 1698 PetscSection coordSection; 1699 Vec coordinates; 1700 PetscReal xyl[3], xyr[3]; 1701 PetscReal *refCoords, *edgeCoords; 1702 PetscBool isnull, drawAffine = PETSC_TRUE; 1703 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1704 1705 PetscFunctionBegin; 1706 PetscCall(DMGetCoordinateDim(dm, &dim)); 1707 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1708 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1709 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1710 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1711 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1712 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1713 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1714 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1715 1716 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1717 PetscCall(PetscDrawIsNull(draw, &isnull)); 1718 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1719 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1720 1721 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1722 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1723 PetscCall(PetscDrawClear(draw)); 1724 1725 for (c = cStart; c < cEnd; ++c) { 1726 PetscScalar *coords = NULL; 1727 const PetscScalar *coords_arr; 1728 PetscInt numCoords; 1729 PetscBool isDG; 1730 1731 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1732 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1733 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1734 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1735 } 1736 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1737 PetscCall(PetscDrawFlush(draw)); 1738 PetscCall(PetscDrawPause(draw)); 1739 PetscCall(PetscDrawSave(draw)); 1740 PetscFunctionReturn(PETSC_SUCCESS); 1741 } 1742 1743 #if defined(PETSC_HAVE_EXODUSII) 1744 #include <exodusII.h> 1745 #include <petscviewerexodusii.h> 1746 #endif 1747 1748 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1749 { 1750 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1751 char name[PETSC_MAX_PATH_LEN]; 1752 1753 PetscFunctionBegin; 1754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1755 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1756 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1757 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1758 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1759 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1760 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1761 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1762 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1763 if (iascii) { 1764 PetscViewerFormat format; 1765 PetscCall(PetscViewerGetFormat(viewer, &format)); 1766 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1767 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1768 } else if (ishdf5) { 1769 #if defined(PETSC_HAVE_HDF5) 1770 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1771 #else 1772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1773 #endif 1774 } else if (isvtk) { 1775 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1776 } else if (isdraw) { 1777 PetscCall(DMPlexView_Draw(dm, viewer)); 1778 } else if (isglvis) { 1779 PetscCall(DMPlexView_GLVis(dm, viewer)); 1780 #if defined(PETSC_HAVE_EXODUSII) 1781 } else if (isexodus) { 1782 /* 1783 exodusII requires that all sets be part of exactly one cell set. 1784 If the dm does not have a "Cell Sets" label defined, we create one 1785 with ID 1, containing all cells. 1786 Note that if the Cell Sets label is defined but does not cover all cells, 1787 we may still have a problem. This should probably be checked here or in the viewer; 1788 */ 1789 PetscInt numCS; 1790 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1791 if (!numCS) { 1792 PetscInt cStart, cEnd, c; 1793 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1794 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1795 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1796 } 1797 PetscCall(DMView_PlexExodusII(dm, viewer)); 1798 #endif 1799 #if defined(PETSC_HAVE_CGNS) 1800 } else if (iscgns) { 1801 PetscCall(DMView_PlexCGNS(dm, viewer)); 1802 #endif 1803 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1804 /* Optionally view the partition */ 1805 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1806 if (flg) { 1807 Vec ranks; 1808 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1809 PetscCall(VecView(ranks, viewer)); 1810 PetscCall(VecDestroy(&ranks)); 1811 } 1812 /* Optionally view a label */ 1813 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1814 if (flg) { 1815 DMLabel label; 1816 Vec val; 1817 1818 PetscCall(DMGetLabel(dm, name, &label)); 1819 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1820 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1821 PetscCall(VecView(val, viewer)); 1822 PetscCall(VecDestroy(&val)); 1823 } 1824 PetscFunctionReturn(PETSC_SUCCESS); 1825 } 1826 1827 /*@ 1828 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1829 1830 Collective 1831 1832 Input Parameters: 1833 + dm - The `DM` whose topology is to be saved 1834 - viewer - The `PetscViewer` to save it in 1835 1836 Level: advanced 1837 1838 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1839 @*/ 1840 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1841 { 1842 PetscBool ishdf5; 1843 1844 PetscFunctionBegin; 1845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1846 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1848 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1849 if (ishdf5) { 1850 #if defined(PETSC_HAVE_HDF5) 1851 PetscViewerFormat format; 1852 PetscCall(PetscViewerGetFormat(viewer, &format)); 1853 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1854 IS globalPointNumbering; 1855 1856 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1857 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1858 PetscCall(ISDestroy(&globalPointNumbering)); 1859 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1860 #else 1861 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1862 #endif 1863 } 1864 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 /*@ 1869 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1870 1871 Collective 1872 1873 Input Parameters: 1874 + dm - The `DM` whose coordinates are to be saved 1875 - viewer - The `PetscViewer` for saving 1876 1877 Level: advanced 1878 1879 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1880 @*/ 1881 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1882 { 1883 PetscBool ishdf5; 1884 1885 PetscFunctionBegin; 1886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1887 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1888 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1889 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1890 if (ishdf5) { 1891 #if defined(PETSC_HAVE_HDF5) 1892 PetscViewerFormat format; 1893 PetscCall(PetscViewerGetFormat(viewer, &format)); 1894 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1895 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1896 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1897 #else 1898 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1899 #endif 1900 } 1901 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1902 PetscFunctionReturn(PETSC_SUCCESS); 1903 } 1904 1905 /*@ 1906 DMPlexLabelsView - Saves `DMPLEX` labels into a file 1907 1908 Collective 1909 1910 Input Parameters: 1911 + dm - The `DM` whose labels are to be saved 1912 - viewer - The `PetscViewer` for saving 1913 1914 Level: advanced 1915 1916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 1917 @*/ 1918 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1919 { 1920 PetscBool ishdf5; 1921 1922 PetscFunctionBegin; 1923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1924 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1925 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1926 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1927 if (ishdf5) { 1928 #if defined(PETSC_HAVE_HDF5) 1929 IS globalPointNumbering; 1930 PetscViewerFormat format; 1931 1932 PetscCall(PetscViewerGetFormat(viewer, &format)); 1933 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1934 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1935 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1936 PetscCall(ISDestroy(&globalPointNumbering)); 1937 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1938 #else 1939 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1940 #endif 1941 } 1942 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1943 PetscFunctionReturn(PETSC_SUCCESS); 1944 } 1945 1946 /*@ 1947 DMPlexSectionView - Saves a section associated with a `DMPLEX` 1948 1949 Collective 1950 1951 Input Parameters: 1952 + dm - The `DM` that contains the topology on which the section to be saved is defined 1953 . viewer - The `PetscViewer` for saving 1954 - sectiondm - The `DM` that contains the section to be saved 1955 1956 Level: advanced 1957 1958 Notes: 1959 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 1960 1961 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1962 1963 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 1964 @*/ 1965 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1966 { 1967 PetscBool ishdf5; 1968 1969 PetscFunctionBegin; 1970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1971 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1972 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1973 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1974 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1975 if (ishdf5) { 1976 #if defined(PETSC_HAVE_HDF5) 1977 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1978 #else 1979 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1980 #endif 1981 } 1982 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1983 PetscFunctionReturn(PETSC_SUCCESS); 1984 } 1985 1986 /*@ 1987 DMPlexGlobalVectorView - Saves a global vector 1988 1989 Collective 1990 1991 Input Parameters: 1992 + dm - The `DM` that represents the topology 1993 . viewer - The `PetscViewer` to save data with 1994 . sectiondm - The `DM` that contains the global section on which vec is defined 1995 - vec - The global vector to be saved 1996 1997 Level: advanced 1998 1999 Notes: 2000 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2001 2002 Typical calling sequence: 2003 .vb 2004 DMCreate(PETSC_COMM_WORLD, &dm); 2005 DMSetType(dm, DMPLEX); 2006 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2007 DMClone(dm, §iondm); 2008 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2009 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2010 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2011 PetscSectionSetChart(section, pStart, pEnd); 2012 PetscSectionSetUp(section); 2013 DMSetLocalSection(sectiondm, section); 2014 PetscSectionDestroy(§ion); 2015 DMGetGlobalVector(sectiondm, &vec); 2016 PetscObjectSetName((PetscObject)vec, "vec_name"); 2017 DMPlexTopologyView(dm, viewer); 2018 DMPlexSectionView(dm, viewer, sectiondm); 2019 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2020 DMRestoreGlobalVector(sectiondm, &vec); 2021 DMDestroy(§iondm); 2022 DMDestroy(&dm); 2023 .ve 2024 2025 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2026 @*/ 2027 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2028 { 2029 PetscBool ishdf5; 2030 2031 PetscFunctionBegin; 2032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2033 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2034 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2035 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2036 /* Check consistency */ 2037 { 2038 PetscSection section; 2039 PetscBool includesConstraints; 2040 PetscInt m, m1; 2041 2042 PetscCall(VecGetLocalSize(vec, &m1)); 2043 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2044 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2045 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2046 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2047 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2048 } 2049 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2050 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2051 if (ishdf5) { 2052 #if defined(PETSC_HAVE_HDF5) 2053 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2054 #else 2055 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2056 #endif 2057 } 2058 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2059 PetscFunctionReturn(PETSC_SUCCESS); 2060 } 2061 2062 /*@ 2063 DMPlexLocalVectorView - Saves a local vector 2064 2065 Collective 2066 2067 Input Parameters: 2068 + dm - The `DM` that represents the topology 2069 . viewer - The `PetscViewer` to save data with 2070 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2071 - vec - The local vector to be saved 2072 2073 Level: advanced 2074 2075 Note: 2076 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2077 2078 Typical calling sequence: 2079 .vb 2080 DMCreate(PETSC_COMM_WORLD, &dm); 2081 DMSetType(dm, DMPLEX); 2082 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2083 DMClone(dm, §iondm); 2084 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2085 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2086 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2087 PetscSectionSetChart(section, pStart, pEnd); 2088 PetscSectionSetUp(section); 2089 DMSetLocalSection(sectiondm, section); 2090 DMGetLocalVector(sectiondm, &vec); 2091 PetscObjectSetName((PetscObject)vec, "vec_name"); 2092 DMPlexTopologyView(dm, viewer); 2093 DMPlexSectionView(dm, viewer, sectiondm); 2094 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2095 DMRestoreLocalVector(sectiondm, &vec); 2096 DMDestroy(§iondm); 2097 DMDestroy(&dm); 2098 .ve 2099 2100 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2101 @*/ 2102 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2103 { 2104 PetscBool ishdf5; 2105 2106 PetscFunctionBegin; 2107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2108 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2109 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2110 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2111 /* Check consistency */ 2112 { 2113 PetscSection section; 2114 PetscBool includesConstraints; 2115 PetscInt m, m1; 2116 2117 PetscCall(VecGetLocalSize(vec, &m1)); 2118 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2119 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2120 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2121 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2122 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2123 } 2124 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2125 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2126 if (ishdf5) { 2127 #if defined(PETSC_HAVE_HDF5) 2128 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2129 #else 2130 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2131 #endif 2132 } 2133 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2134 PetscFunctionReturn(PETSC_SUCCESS); 2135 } 2136 2137 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2138 { 2139 PetscBool ishdf5; 2140 2141 PetscFunctionBegin; 2142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2143 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2144 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2145 if (ishdf5) { 2146 #if defined(PETSC_HAVE_HDF5) 2147 PetscViewerFormat format; 2148 PetscCall(PetscViewerGetFormat(viewer, &format)); 2149 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2150 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2151 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2152 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2153 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2154 PetscFunctionReturn(PETSC_SUCCESS); 2155 #else 2156 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2157 #endif 2158 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2159 } 2160 2161 /*@ 2162 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2163 2164 Collective 2165 2166 Input Parameters: 2167 + dm - The `DM` into which the topology is loaded 2168 - viewer - The `PetscViewer` for the saved topology 2169 2170 Output Parameter: 2171 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2172 2173 Level: advanced 2174 2175 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2176 `PetscViewer`, `PetscSF` 2177 @*/ 2178 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2179 { 2180 PetscBool ishdf5; 2181 2182 PetscFunctionBegin; 2183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2184 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2185 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2186 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2187 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2188 if (ishdf5) { 2189 #if defined(PETSC_HAVE_HDF5) 2190 PetscViewerFormat format; 2191 PetscCall(PetscViewerGetFormat(viewer, &format)); 2192 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2193 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2194 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2195 #else 2196 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2197 #endif 2198 } 2199 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2200 PetscFunctionReturn(PETSC_SUCCESS); 2201 } 2202 2203 /*@ 2204 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2205 2206 Collective 2207 2208 Input Parameters: 2209 + dm - The `DM` into which the coordinates are loaded 2210 . viewer - The `PetscViewer` for the saved coordinates 2211 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2212 2213 Level: advanced 2214 2215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2216 `PetscSF`, `PetscViewer` 2217 @*/ 2218 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2219 { 2220 PetscBool ishdf5; 2221 2222 PetscFunctionBegin; 2223 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2224 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2225 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2226 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2227 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2228 if (ishdf5) { 2229 #if defined(PETSC_HAVE_HDF5) 2230 PetscViewerFormat format; 2231 PetscCall(PetscViewerGetFormat(viewer, &format)); 2232 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2233 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2234 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2235 #else 2236 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2237 #endif 2238 } 2239 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2240 PetscFunctionReturn(PETSC_SUCCESS); 2241 } 2242 2243 /*@ 2244 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2245 2246 Collective 2247 2248 Input Parameters: 2249 + dm - The `DM` into which the labels are loaded 2250 . viewer - The `PetscViewer` for the saved labels 2251 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2252 2253 Level: advanced 2254 2255 Note: 2256 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2257 2258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2259 `PetscSF`, `PetscViewer` 2260 @*/ 2261 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2262 { 2263 PetscBool ishdf5; 2264 2265 PetscFunctionBegin; 2266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2267 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2268 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2269 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2270 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2271 if (ishdf5) { 2272 #if defined(PETSC_HAVE_HDF5) 2273 PetscViewerFormat format; 2274 2275 PetscCall(PetscViewerGetFormat(viewer, &format)); 2276 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2277 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2278 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2279 #else 2280 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2281 #endif 2282 } 2283 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2284 PetscFunctionReturn(PETSC_SUCCESS); 2285 } 2286 2287 /*@ 2288 DMPlexSectionLoad - Loads section into a `DMPLEX` 2289 2290 Collective 2291 2292 Input Parameters: 2293 + dm - The `DM` that represents the topology 2294 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2295 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2296 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2297 2298 Output Parameters 2299 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2300 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2301 2302 Level: advanced 2303 2304 Notes: 2305 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2306 2307 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2308 2309 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2310 2311 Example using 2 processes: 2312 .vb 2313 NX (number of points on dm): 4 2314 sectionA : the on-disk section 2315 vecA : a vector associated with sectionA 2316 sectionB : sectiondm's local section constructed in this function 2317 vecB (local) : a vector associated with sectiondm's local section 2318 vecB (global) : a vector associated with sectiondm's global section 2319 2320 rank 0 rank 1 2321 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2322 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2323 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2324 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2325 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2326 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2327 sectionB->atlasDof : 1 0 1 | 1 3 2328 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2329 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2330 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2331 .ve 2332 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2333 2334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2335 @*/ 2336 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2344 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2345 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2346 if (localDofSF) PetscValidPointer(localDofSF, 6); 2347 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2348 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2349 if (ishdf5) { 2350 #if defined(PETSC_HAVE_HDF5) 2351 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2352 #else 2353 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2354 #endif 2355 } 2356 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2357 PetscFunctionReturn(PETSC_SUCCESS); 2358 } 2359 2360 /*@ 2361 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2362 2363 Collective 2364 2365 Input Parameters: 2366 + dm - The `DM` that represents the topology 2367 . viewer - The `PetscViewer` that represents the on-disk vector data 2368 . sectiondm - The `DM` that contains the global section on which vec is defined 2369 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2370 - vec - The global vector to set values of 2371 2372 Level: advanced 2373 2374 Notes: 2375 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2376 2377 Typical calling sequence: 2378 .vb 2379 DMCreate(PETSC_COMM_WORLD, &dm); 2380 DMSetType(dm, DMPLEX); 2381 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2382 DMPlexTopologyLoad(dm, viewer, &sfX); 2383 DMClone(dm, §iondm); 2384 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2385 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2386 DMGetGlobalVector(sectiondm, &vec); 2387 PetscObjectSetName((PetscObject)vec, "vec_name"); 2388 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2389 DMRestoreGlobalVector(sectiondm, &vec); 2390 PetscSFDestroy(&gsf); 2391 PetscSFDestroy(&sfX); 2392 DMDestroy(§iondm); 2393 DMDestroy(&dm); 2394 .ve 2395 2396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2397 `PetscSF`, `PetscViewer` 2398 @*/ 2399 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2400 { 2401 PetscBool ishdf5; 2402 2403 PetscFunctionBegin; 2404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2405 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2406 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2407 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2408 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2409 /* Check consistency */ 2410 { 2411 PetscSection section; 2412 PetscBool includesConstraints; 2413 PetscInt m, m1; 2414 2415 PetscCall(VecGetLocalSize(vec, &m1)); 2416 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2417 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2418 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2419 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2420 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2421 } 2422 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2423 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2424 if (ishdf5) { 2425 #if defined(PETSC_HAVE_HDF5) 2426 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2427 #else 2428 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2429 #endif 2430 } 2431 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2432 PetscFunctionReturn(PETSC_SUCCESS); 2433 } 2434 2435 /*@ 2436 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2437 2438 Collective 2439 2440 Input Parameters: 2441 + dm - The `DM` that represents the topology 2442 . viewer - The `PetscViewer` that represents the on-disk vector data 2443 . sectiondm - The `DM` that contains the local section on which vec is defined 2444 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2445 - vec - The local vector to set values of 2446 2447 Level: advanced 2448 2449 Notes: 2450 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2451 2452 Typical calling sequence: 2453 .vb 2454 DMCreate(PETSC_COMM_WORLD, &dm); 2455 DMSetType(dm, DMPLEX); 2456 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2457 DMPlexTopologyLoad(dm, viewer, &sfX); 2458 DMClone(dm, §iondm); 2459 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2460 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2461 DMGetLocalVector(sectiondm, &vec); 2462 PetscObjectSetName((PetscObject)vec, "vec_name"); 2463 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2464 DMRestoreLocalVector(sectiondm, &vec); 2465 PetscSFDestroy(&lsf); 2466 PetscSFDestroy(&sfX); 2467 DMDestroy(§iondm); 2468 DMDestroy(&dm); 2469 .ve 2470 2471 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2472 `PetscSF`, `PetscViewer` 2473 @*/ 2474 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2475 { 2476 PetscBool ishdf5; 2477 2478 PetscFunctionBegin; 2479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2480 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2481 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2482 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2483 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2484 /* Check consistency */ 2485 { 2486 PetscSection section; 2487 PetscBool includesConstraints; 2488 PetscInt m, m1; 2489 2490 PetscCall(VecGetLocalSize(vec, &m1)); 2491 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2492 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2493 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2494 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2495 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2496 } 2497 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2498 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2499 if (ishdf5) { 2500 #if defined(PETSC_HAVE_HDF5) 2501 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2502 #else 2503 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2504 #endif 2505 } 2506 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2507 PetscFunctionReturn(PETSC_SUCCESS); 2508 } 2509 2510 PetscErrorCode DMDestroy_Plex(DM dm) 2511 { 2512 DM_Plex *mesh = (DM_Plex *)dm->data; 2513 2514 PetscFunctionBegin; 2515 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2516 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2517 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2518 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2519 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2520 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2521 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2522 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2523 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2524 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2525 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2526 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2527 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2528 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2529 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2530 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2531 PetscCall(PetscFree(mesh->cones)); 2532 PetscCall(PetscFree(mesh->coneOrientations)); 2533 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2534 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2535 PetscCall(PetscFree(mesh->supports)); 2536 PetscCall(PetscFree(mesh->cellTypes)); 2537 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2538 PetscCall(PetscFree(mesh->tetgenOpts)); 2539 PetscCall(PetscFree(mesh->triangleOpts)); 2540 PetscCall(PetscFree(mesh->transformType)); 2541 PetscCall(PetscFree(mesh->distributionName)); 2542 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2543 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2544 PetscCall(ISDestroy(&mesh->subpointIS)); 2545 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2546 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2547 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2548 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2549 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2550 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2551 PetscCall(ISDestroy(&mesh->anchorIS)); 2552 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2553 PetscCall(PetscFree(mesh->parents)); 2554 PetscCall(PetscFree(mesh->childIDs)); 2555 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2556 PetscCall(PetscFree(mesh->children)); 2557 PetscCall(DMDestroy(&mesh->referenceTree)); 2558 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2559 PetscCall(PetscFree(mesh->neighbors)); 2560 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2561 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2562 PetscCall(PetscFree(mesh)); 2563 PetscFunctionReturn(PETSC_SUCCESS); 2564 } 2565 2566 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2567 { 2568 PetscSection sectionGlobal; 2569 PetscInt bs = -1, mbs; 2570 PetscInt localSize, localStart = 0; 2571 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2572 MatType mtype; 2573 ISLocalToGlobalMapping ltog; 2574 2575 PetscFunctionBegin; 2576 PetscCall(MatInitializePackage()); 2577 mtype = dm->mattype; 2578 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2579 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2580 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2581 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2582 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2583 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2584 PetscCall(MatSetType(*J, mtype)); 2585 PetscCall(MatSetFromOptions(*J)); 2586 PetscCall(MatGetBlockSize(*J, &mbs)); 2587 if (mbs > 1) bs = mbs; 2588 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2589 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2590 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2591 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2592 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2593 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2594 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2595 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2596 if (!isShell) { 2597 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2598 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2599 PetscInt pStart, pEnd, p, dof, cdof, num_fields; 2600 2601 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2602 2603 PetscCall(PetscCalloc1(localSize, &pblocks)); 2604 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2605 PetscCall(PetscSectionGetNumFields(sectionGlobal, &num_fields)); 2606 for (p = pStart; p < pEnd; ++p) { 2607 switch (dm->blocking_type) { 2608 case DM_BLOCKING_TOPOLOGICAL_POINT: { // One block per topological point 2609 PetscInt bdof, offset; 2610 2611 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2612 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2613 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2614 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2615 dof = dof < 0 ? -(dof + 1) : dof; 2616 bdof = cdof && (dof - cdof) ? 1 : dof; 2617 if (dof) { 2618 if (bs < 0) { 2619 bs = bdof; 2620 } else if (bs != bdof) { 2621 bs = 1; 2622 } 2623 } 2624 } break; 2625 case DM_BLOCKING_FIELD_NODE: { 2626 for (PetscInt field = 0; field < num_fields; field++) { 2627 PetscInt num_comp, bdof, offset; 2628 PetscCall(PetscSectionGetFieldComponents(sectionGlobal, field, &num_comp)); 2629 PetscCall(PetscSectionGetFieldDof(sectionGlobal, p, field, &dof)); 2630 if (dof < 0) continue; 2631 PetscCall(PetscSectionGetFieldOffset(sectionGlobal, p, field, &offset)); 2632 PetscCall(PetscSectionGetFieldConstraintDof(sectionGlobal, p, field, &cdof)); 2633 PetscAssert(dof % num_comp == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " field %" PetscInt_FMT " has %" PetscInt_FMT " dof, not divisible by %" PetscInt_FMT " component ", p, field, dof, num_comp); 2634 PetscInt num_nodes = dof / num_comp; 2635 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = (dof - cdof) / num_nodes; 2636 // Handle possibly constant block size (unlikely) 2637 bdof = cdof && (dof - cdof) ? 1 : dof; 2638 if (dof) { 2639 if (bs < 0) { 2640 bs = bdof; 2641 } else if (bs != bdof) { 2642 bs = 1; 2643 } 2644 } 2645 } 2646 } break; 2647 } 2648 } 2649 /* Must have same blocksize on all procs (some might have no points) */ 2650 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2651 bsLocal[1] = bs; 2652 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2653 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2654 else bs = bsMinMax[0]; 2655 bs = PetscMax(1, bs); 2656 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2657 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2658 PetscCall(MatSetBlockSize(*J, bs)); 2659 PetscCall(MatSetUp(*J)); 2660 } else { 2661 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2662 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2663 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2664 } 2665 { // Consolidate blocks 2666 PetscInt nblocks = 0; 2667 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2668 if (pblocks[i] == 0) continue; 2669 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2670 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2671 } 2672 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2673 } 2674 PetscCall(PetscFree(pblocks)); 2675 } 2676 PetscCall(MatSetDM(*J, dm)); 2677 PetscFunctionReturn(PETSC_SUCCESS); 2678 } 2679 2680 /*@ 2681 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2682 2683 Not Collective 2684 2685 Input Parameter: 2686 . mesh - The `DMPLEX` 2687 2688 Output Parameter: 2689 . subsection - The subdomain section 2690 2691 Level: developer 2692 2693 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2694 @*/ 2695 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2696 { 2697 DM_Plex *mesh = (DM_Plex *)dm->data; 2698 2699 PetscFunctionBegin; 2700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2701 if (!mesh->subdomainSection) { 2702 PetscSection section; 2703 PetscSF sf; 2704 2705 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2706 PetscCall(DMGetLocalSection(dm, §ion)); 2707 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2708 PetscCall(PetscSFDestroy(&sf)); 2709 } 2710 *subsection = mesh->subdomainSection; 2711 PetscFunctionReturn(PETSC_SUCCESS); 2712 } 2713 2714 /*@ 2715 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2716 2717 Not Collective 2718 2719 Input Parameter: 2720 . mesh - The `DMPLEX` 2721 2722 Output Parameters: 2723 + pStart - The first mesh point 2724 - pEnd - The upper bound for mesh points 2725 2726 Level: beginner 2727 2728 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2729 @*/ 2730 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2731 { 2732 DM_Plex *mesh = (DM_Plex *)dm->data; 2733 2734 PetscFunctionBegin; 2735 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2736 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2737 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2738 PetscFunctionReturn(PETSC_SUCCESS); 2739 } 2740 2741 /*@ 2742 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2743 2744 Not Collective 2745 2746 Input Parameters: 2747 + mesh - The `DMPLEX` 2748 . pStart - The first mesh point 2749 - pEnd - The upper bound for mesh points 2750 2751 Level: beginner 2752 2753 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2754 @*/ 2755 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2756 { 2757 DM_Plex *mesh = (DM_Plex *)dm->data; 2758 PetscInt pStartO, pEndO; 2759 2760 PetscFunctionBegin; 2761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2762 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStartO, &pEndO)); 2763 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2764 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2765 PetscCall(PetscFree(mesh->cellTypes)); 2766 PetscFunctionReturn(PETSC_SUCCESS); 2767 } 2768 2769 /*@ 2770 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2771 2772 Not Collective 2773 2774 Input Parameters: 2775 + mesh - The `DMPLEX` 2776 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2777 2778 Output Parameter: 2779 . size - The cone size for point `p` 2780 2781 Level: beginner 2782 2783 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2784 @*/ 2785 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2786 { 2787 DM_Plex *mesh = (DM_Plex *)dm->data; 2788 2789 PetscFunctionBegin; 2790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2791 PetscValidIntPointer(size, 3); 2792 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2793 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2794 PetscFunctionReturn(PETSC_SUCCESS); 2795 } 2796 2797 /*@ 2798 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2799 2800 Not Collective 2801 2802 Input Parameters: 2803 + mesh - The `DMPLEX` 2804 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2805 - size - The cone size for point `p` 2806 2807 Level: beginner 2808 2809 Note: 2810 This should be called after `DMPlexSetChart()`. 2811 2812 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2813 @*/ 2814 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2815 { 2816 DM_Plex *mesh = (DM_Plex *)dm->data; 2817 2818 PetscFunctionBegin; 2819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2820 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2821 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2822 PetscFunctionReturn(PETSC_SUCCESS); 2823 } 2824 2825 /*@C 2826 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2827 2828 Not Collective 2829 2830 Input Parameters: 2831 + dm - The `DMPLEX` 2832 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2833 2834 Output Parameter: 2835 . cone - An array of points which are on the in-edges for point `p` 2836 2837 Level: beginner 2838 2839 Fortran Note: 2840 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2841 `DMPlexRestoreCone()` is not needed/available in C. 2842 2843 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2844 @*/ 2845 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2846 { 2847 DM_Plex *mesh = (DM_Plex *)dm->data; 2848 PetscInt off; 2849 2850 PetscFunctionBegin; 2851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2852 PetscValidPointer(cone, 3); 2853 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2854 *cone = &mesh->cones[off]; 2855 PetscFunctionReturn(PETSC_SUCCESS); 2856 } 2857 2858 /*@C 2859 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2860 2861 Not Collective 2862 2863 Input Parameters: 2864 + dm - The `DMPLEX` 2865 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2866 2867 Output Parameters: 2868 + pConesSection - `PetscSection` describing the layout of `pCones` 2869 - pCones - An array of points which are on the in-edges for the point set `p` 2870 2871 Level: intermediate 2872 2873 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2874 @*/ 2875 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2876 { 2877 PetscSection cs, newcs; 2878 PetscInt *cones; 2879 PetscInt *newarr = NULL; 2880 PetscInt n; 2881 2882 PetscFunctionBegin; 2883 PetscCall(DMPlexGetCones(dm, &cones)); 2884 PetscCall(DMPlexGetConeSection(dm, &cs)); 2885 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2886 if (pConesSection) *pConesSection = newcs; 2887 if (pCones) { 2888 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2889 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2890 } 2891 PetscFunctionReturn(PETSC_SUCCESS); 2892 } 2893 2894 /*@ 2895 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2896 2897 Not Collective 2898 2899 Input Parameters: 2900 + dm - The `DMPLEX` 2901 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2902 2903 Output Parameter: 2904 . expandedPoints - An array of vertices recursively expanded from input points 2905 2906 Level: advanced 2907 2908 Notes: 2909 Like `DMPlexGetConeRecursive()` but returns only the 0-depth `IS` (i.e. vertices only) and no sections. 2910 2911 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 2912 2913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 2914 `DMPlexGetDepth()`, `IS` 2915 @*/ 2916 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2917 { 2918 IS *expandedPointsAll; 2919 PetscInt depth; 2920 2921 PetscFunctionBegin; 2922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2923 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2924 PetscValidPointer(expandedPoints, 3); 2925 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2926 *expandedPoints = expandedPointsAll[0]; 2927 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2928 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2929 PetscFunctionReturn(PETSC_SUCCESS); 2930 } 2931 2932 /*@ 2933 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 2934 2935 Not Collective 2936 2937 Input Parameters: 2938 + dm - The `DMPLEX` 2939 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2940 2941 Output Parameters: 2942 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 2943 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2944 - sections - (optional) An array of sections which describe mappings from points to their cone points 2945 2946 Level: advanced 2947 2948 Notes: 2949 Like `DMPlexGetConeTuple()` but recursive. 2950 2951 Array `expandedPoints` has size equal to `depth`. `Each expandedPoints`[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 2952 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2953 2954 Array section has size equal to depth. Each `PetscSection` sections[d] realizes mapping from `expandedPoints`[d+1] (section points) to `expandedPoints`[d] (section dofs) as follows: 2955 (1) DAG points in expandedPoints[d+1] with `depth` d+1 to their cone points in `expandedPoints`[d]; 2956 (2) DAG points in expandedPoints[d+1] with `depth` in [0,d] to the same points in `expandedPoints`[d]. 2957 2958 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 2959 `DMPlexGetDepth()`, `PetscSection`, `IS` 2960 @*/ 2961 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2962 { 2963 const PetscInt *arr0 = NULL, *cone = NULL; 2964 PetscInt *arr = NULL, *newarr = NULL; 2965 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2966 IS *expandedPoints_; 2967 PetscSection *sections_; 2968 2969 PetscFunctionBegin; 2970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2971 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2972 if (depth) PetscValidIntPointer(depth, 3); 2973 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2974 if (sections) PetscValidPointer(sections, 5); 2975 PetscCall(ISGetLocalSize(points, &n)); 2976 PetscCall(ISGetIndices(points, &arr0)); 2977 PetscCall(DMPlexGetDepth(dm, &depth_)); 2978 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2979 PetscCall(PetscCalloc1(depth_, §ions_)); 2980 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2981 for (d = depth_ - 1; d >= 0; d--) { 2982 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2983 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2984 for (i = 0; i < n; i++) { 2985 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2986 if (arr[i] >= start && arr[i] < end) { 2987 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2988 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2989 } else { 2990 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2991 } 2992 } 2993 PetscCall(PetscSectionSetUp(sections_[d])); 2994 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2995 PetscCall(PetscMalloc1(newn, &newarr)); 2996 for (i = 0; i < n; i++) { 2997 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2998 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2999 if (cn > 1) { 3000 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 3001 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 3002 } else { 3003 newarr[co] = arr[i]; 3004 } 3005 } 3006 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 3007 arr = newarr; 3008 n = newn; 3009 } 3010 PetscCall(ISRestoreIndices(points, &arr0)); 3011 *depth = depth_; 3012 if (expandedPoints) *expandedPoints = expandedPoints_; 3013 else { 3014 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 3015 PetscCall(PetscFree(expandedPoints_)); 3016 } 3017 if (sections) *sections = sections_; 3018 else { 3019 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3020 PetscCall(PetscFree(sections_)); 3021 } 3022 PetscFunctionReturn(PETSC_SUCCESS); 3023 } 3024 3025 /*@ 3026 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3027 3028 Not Collective 3029 3030 Input Parameters: 3031 + dm - The `DMPLEX` 3032 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3033 3034 Output Parameters: 3035 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3036 . expandedPoints - (optional) An array of recursively expanded cones 3037 - sections - (optional) An array of sections which describe mappings from points to their cone points 3038 3039 Level: advanced 3040 3041 Note: 3042 See `DMPlexGetConeRecursive()` 3043 3044 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3045 `DMPlexGetDepth()`, `IS`, `PetscSection` 3046 @*/ 3047 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3048 { 3049 PetscInt d, depth_; 3050 3051 PetscFunctionBegin; 3052 PetscCall(DMPlexGetDepth(dm, &depth_)); 3053 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3054 if (depth) *depth = 0; 3055 if (expandedPoints) { 3056 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3057 PetscCall(PetscFree(*expandedPoints)); 3058 } 3059 if (sections) { 3060 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3061 PetscCall(PetscFree(*sections)); 3062 } 3063 PetscFunctionReturn(PETSC_SUCCESS); 3064 } 3065 3066 /*@ 3067 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 3068 3069 Not Collective 3070 3071 Input Parameters: 3072 + mesh - The `DMPLEX` 3073 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3074 - cone - An array of points which are on the in-edges for point `p` 3075 3076 Level: beginner 3077 3078 Note: 3079 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3080 3081 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3082 @*/ 3083 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3084 { 3085 DM_Plex *mesh = (DM_Plex *)dm->data; 3086 PetscInt dof, off, c; 3087 3088 PetscFunctionBegin; 3089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3090 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3091 if (dof) PetscValidIntPointer(cone, 3); 3092 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3093 if (PetscDefined(USE_DEBUG)) { 3094 PetscInt pStart, pEnd; 3095 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3096 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3097 for (c = 0; c < dof; ++c) { 3098 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3099 mesh->cones[off + c] = cone[c]; 3100 } 3101 } else { 3102 for (c = 0; c < dof; ++c) mesh->cones[off + c] = cone[c]; 3103 } 3104 PetscFunctionReturn(PETSC_SUCCESS); 3105 } 3106 3107 /*@C 3108 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3109 3110 Not Collective 3111 3112 Input Parameters: 3113 + mesh - The `DMPLEX` 3114 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3115 3116 Output Parameter: 3117 . coneOrientation - An array of orientations which are on the in-edges for point `p`. An orientation is an 3118 integer giving the prescription for cone traversal. 3119 3120 Level: beginner 3121 3122 Note: 3123 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3124 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3125 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3126 with the identity. 3127 3128 Fortran Note: 3129 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3130 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3131 3132 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3133 @*/ 3134 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3135 { 3136 DM_Plex *mesh = (DM_Plex *)dm->data; 3137 PetscInt off; 3138 3139 PetscFunctionBegin; 3140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3141 if (PetscDefined(USE_DEBUG)) { 3142 PetscInt dof; 3143 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3144 if (dof) PetscValidPointer(coneOrientation, 3); 3145 } 3146 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3147 3148 *coneOrientation = &mesh->coneOrientations[off]; 3149 PetscFunctionReturn(PETSC_SUCCESS); 3150 } 3151 3152 /*@ 3153 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3154 3155 Not Collective 3156 3157 Input Parameters: 3158 + mesh - The `DMPLEX` 3159 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3160 - coneOrientation - An array of orientations 3161 3162 Level: beginner 3163 3164 Notes: 3165 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3166 3167 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3168 3169 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3170 @*/ 3171 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3172 { 3173 DM_Plex *mesh = (DM_Plex *)dm->data; 3174 PetscInt pStart, pEnd; 3175 PetscInt dof, off, c; 3176 3177 PetscFunctionBegin; 3178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3179 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3180 if (dof) PetscValidIntPointer(coneOrientation, 3); 3181 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3182 if (PetscDefined(USE_DEBUG)) { 3183 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3184 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3185 for (c = 0; c < dof; ++c) { 3186 PetscInt cdof, o = coneOrientation[c]; 3187 3188 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3189 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3190 mesh->coneOrientations[off + c] = o; 3191 } 3192 } else { 3193 for (c = 0; c < dof; ++c) mesh->coneOrientations[off + c] = coneOrientation[c]; 3194 } 3195 PetscFunctionReturn(PETSC_SUCCESS); 3196 } 3197 3198 /*@ 3199 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3200 3201 Not Collective 3202 3203 Input Parameters: 3204 + mesh - The `DMPLEX` 3205 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3206 . conePos - The local index in the cone where the point should be put 3207 - conePoint - The mesh point to insert 3208 3209 Level: beginner 3210 3211 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3212 @*/ 3213 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3214 { 3215 DM_Plex *mesh = (DM_Plex *)dm->data; 3216 PetscInt pStart, pEnd; 3217 PetscInt dof, off; 3218 3219 PetscFunctionBegin; 3220 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3221 if (PetscDefined(USE_DEBUG)) { 3222 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3223 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3224 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3225 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3226 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3227 } 3228 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3229 mesh->cones[off + conePos] = conePoint; 3230 PetscFunctionReturn(PETSC_SUCCESS); 3231 } 3232 3233 /*@ 3234 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3235 3236 Not Collective 3237 3238 Input Parameters: 3239 + mesh - The `DMPLEX` 3240 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3241 . conePos - The local index in the cone where the point should be put 3242 - coneOrientation - The point orientation to insert 3243 3244 Level: beginner 3245 3246 Note: 3247 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3248 3249 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3250 @*/ 3251 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3252 { 3253 DM_Plex *mesh = (DM_Plex *)dm->data; 3254 PetscInt pStart, pEnd; 3255 PetscInt dof, off; 3256 3257 PetscFunctionBegin; 3258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3259 if (PetscDefined(USE_DEBUG)) { 3260 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3261 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3262 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3263 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3264 } 3265 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3266 mesh->coneOrientations[off + conePos] = coneOrientation; 3267 PetscFunctionReturn(PETSC_SUCCESS); 3268 } 3269 3270 /*@C 3271 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3272 3273 Not collective 3274 3275 Input Parameters: 3276 + dm - The DMPlex 3277 - p - The point, which must lie in the chart set with DMPlexSetChart() 3278 3279 Output Parameters: 3280 + cone - An array of points which are on the in-edges for point `p` 3281 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3282 integer giving the prescription for cone traversal. 3283 3284 Level: beginner 3285 3286 Notes: 3287 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3288 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3289 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3290 with the identity. 3291 3292 Fortran Notes: 3293 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3294 `DMPlexRestoreCone()` is not needed/available in C. 3295 3296 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3297 @*/ 3298 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3299 { 3300 DM_Plex *mesh = (DM_Plex *)dm->data; 3301 3302 PetscFunctionBegin; 3303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3304 if (mesh->tr) { 3305 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3306 } else { 3307 PetscInt off; 3308 if (PetscDefined(USE_DEBUG)) { 3309 PetscInt dof; 3310 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3311 if (dof) { 3312 if (cone) PetscValidPointer(cone, 3); 3313 if (ornt) PetscValidPointer(ornt, 4); 3314 } 3315 } 3316 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3317 if (cone) *cone = &mesh->cones[off]; 3318 if (ornt) *ornt = &mesh->coneOrientations[off]; 3319 } 3320 PetscFunctionReturn(PETSC_SUCCESS); 3321 } 3322 3323 /*@C 3324 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3325 3326 Not Collective 3327 3328 Input Parameters: 3329 + dm - The DMPlex 3330 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3331 . cone - An array of points which are on the in-edges for point p 3332 - ornt - An array of orientations which are on the in-edges for point `p`. An orientation is an 3333 integer giving the prescription for cone traversal. 3334 3335 Level: beginner 3336 3337 Notes: 3338 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3339 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3340 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3341 with the identity. 3342 3343 Fortran Note: 3344 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 3345 `DMPlexRestoreCone()` is not needed/available in C. 3346 3347 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3348 @*/ 3349 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3350 { 3351 DM_Plex *mesh = (DM_Plex *)dm->data; 3352 3353 PetscFunctionBegin; 3354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3355 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3356 PetscFunctionReturn(PETSC_SUCCESS); 3357 } 3358 3359 /*@ 3360 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3361 3362 Not Collective 3363 3364 Input Parameters: 3365 + mesh - The `DMPLEX` 3366 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3367 3368 Output Parameter: 3369 . size - The support size for point `p` 3370 3371 Level: beginner 3372 3373 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3374 @*/ 3375 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3376 { 3377 DM_Plex *mesh = (DM_Plex *)dm->data; 3378 3379 PetscFunctionBegin; 3380 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3381 PetscValidIntPointer(size, 3); 3382 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3383 PetscFunctionReturn(PETSC_SUCCESS); 3384 } 3385 3386 /*@ 3387 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3388 3389 Not Collective 3390 3391 Input Parameters: 3392 + mesh - The `DMPLEX` 3393 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3394 - size - The support size for point `p` 3395 3396 Level: beginner 3397 3398 Note: 3399 This should be called after `DMPlexSetChart()`. 3400 3401 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3402 @*/ 3403 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3404 { 3405 DM_Plex *mesh = (DM_Plex *)dm->data; 3406 3407 PetscFunctionBegin; 3408 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3409 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3410 PetscFunctionReturn(PETSC_SUCCESS); 3411 } 3412 3413 /*@C 3414 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3415 3416 Not Collective 3417 3418 Input Parameters: 3419 + mesh - The `DMPLEX` 3420 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3421 3422 Output Parameter: 3423 . support - An array of points which are on the out-edges for point `p` 3424 3425 Level: beginner 3426 3427 Fortran Note: 3428 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3429 `DMPlexRestoreSupport()` is not needed/available in C. 3430 3431 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3432 @*/ 3433 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3434 { 3435 DM_Plex *mesh = (DM_Plex *)dm->data; 3436 PetscInt off; 3437 3438 PetscFunctionBegin; 3439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3440 PetscValidPointer(support, 3); 3441 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3442 *support = &mesh->supports[off]; 3443 PetscFunctionReturn(PETSC_SUCCESS); 3444 } 3445 3446 /*@ 3447 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3448 3449 Not Collective 3450 3451 Input Parameters: 3452 + mesh - The `DMPLEX` 3453 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3454 - support - An array of points which are on the out-edges for point `p` 3455 3456 Level: beginner 3457 3458 Note: 3459 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3460 3461 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3462 @*/ 3463 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3464 { 3465 DM_Plex *mesh = (DM_Plex *)dm->data; 3466 PetscInt pStart, pEnd; 3467 PetscInt dof, off, c; 3468 3469 PetscFunctionBegin; 3470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3471 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3472 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3473 if (dof) PetscValidIntPointer(support, 3); 3474 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3475 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3476 for (c = 0; c < dof; ++c) { 3477 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3478 mesh->supports[off + c] = support[c]; 3479 } 3480 PetscFunctionReturn(PETSC_SUCCESS); 3481 } 3482 3483 /*@ 3484 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3485 3486 Not Collective 3487 3488 Input Parameters: 3489 + mesh - The `DMPLEX` 3490 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3491 . supportPos - The local index in the cone where the point should be put 3492 - supportPoint - The mesh point to insert 3493 3494 Level: beginner 3495 3496 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3497 @*/ 3498 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3499 { 3500 DM_Plex *mesh = (DM_Plex *)dm->data; 3501 PetscInt pStart, pEnd; 3502 PetscInt dof, off; 3503 3504 PetscFunctionBegin; 3505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3506 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3507 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3508 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3509 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3510 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3511 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3512 mesh->supports[off + supportPos] = supportPoint; 3513 PetscFunctionReturn(PETSC_SUCCESS); 3514 } 3515 3516 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3517 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3518 { 3519 switch (ct) { 3520 case DM_POLYTOPE_SEGMENT: 3521 if (o == -1) return -2; 3522 break; 3523 case DM_POLYTOPE_TRIANGLE: 3524 if (o == -3) return -1; 3525 if (o == -2) return -3; 3526 if (o == -1) return -2; 3527 break; 3528 case DM_POLYTOPE_QUADRILATERAL: 3529 if (o == -4) return -2; 3530 if (o == -3) return -1; 3531 if (o == -2) return -4; 3532 if (o == -1) return -3; 3533 break; 3534 default: 3535 return o; 3536 } 3537 return o; 3538 } 3539 3540 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3541 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3542 { 3543 switch (ct) { 3544 case DM_POLYTOPE_SEGMENT: 3545 if ((o == -2) || (o == 1)) return -1; 3546 if (o == -1) return 0; 3547 break; 3548 case DM_POLYTOPE_TRIANGLE: 3549 if (o == -3) return -2; 3550 if (o == -2) return -1; 3551 if (o == -1) return -3; 3552 break; 3553 case DM_POLYTOPE_QUADRILATERAL: 3554 if (o == -4) return -2; 3555 if (o == -3) return -1; 3556 if (o == -2) return -4; 3557 if (o == -1) return -3; 3558 break; 3559 default: 3560 return o; 3561 } 3562 return o; 3563 } 3564 3565 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3566 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3567 { 3568 PetscInt pStart, pEnd, p; 3569 3570 PetscFunctionBegin; 3571 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3572 for (p = pStart; p < pEnd; ++p) { 3573 const PetscInt *cone, *ornt; 3574 PetscInt coneSize, c; 3575 3576 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3577 PetscCall(DMPlexGetCone(dm, p, &cone)); 3578 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3579 for (c = 0; c < coneSize; ++c) { 3580 DMPolytopeType ct; 3581 const PetscInt o = ornt[c]; 3582 3583 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3584 switch (ct) { 3585 case DM_POLYTOPE_SEGMENT: 3586 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3587 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3588 break; 3589 case DM_POLYTOPE_TRIANGLE: 3590 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3591 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3592 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3593 break; 3594 case DM_POLYTOPE_QUADRILATERAL: 3595 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3596 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3597 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3598 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3599 break; 3600 default: 3601 break; 3602 } 3603 } 3604 } 3605 PetscFunctionReturn(PETSC_SUCCESS); 3606 } 3607 3608 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3609 { 3610 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3611 PetscInt *closure; 3612 const PetscInt *tmp = NULL, *tmpO = NULL; 3613 PetscInt off = 0, tmpSize, t; 3614 3615 PetscFunctionBeginHot; 3616 if (ornt) { 3617 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3618 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3619 } 3620 if (*points) { 3621 closure = *points; 3622 } else { 3623 PetscInt maxConeSize, maxSupportSize; 3624 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3625 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3626 } 3627 if (useCone) { 3628 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3629 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3630 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3631 } else { 3632 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3633 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3634 } 3635 if (ct == DM_POLYTOPE_UNKNOWN) { 3636 closure[off++] = p; 3637 closure[off++] = 0; 3638 for (t = 0; t < tmpSize; ++t) { 3639 closure[off++] = tmp[t]; 3640 closure[off++] = tmpO ? tmpO[t] : 0; 3641 } 3642 } else { 3643 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3644 3645 /* We assume that cells with a valid type have faces with a valid type */ 3646 closure[off++] = p; 3647 closure[off++] = ornt; 3648 for (t = 0; t < tmpSize; ++t) { 3649 DMPolytopeType ft; 3650 3651 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3652 closure[off++] = tmp[arr[t]]; 3653 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3654 } 3655 } 3656 if (numPoints) *numPoints = tmpSize + 1; 3657 if (points) *points = closure; 3658 PetscFunctionReturn(PETSC_SUCCESS); 3659 } 3660 3661 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3662 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3663 { 3664 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3665 const PetscInt *cone, *ornt; 3666 PetscInt *pts, *closure = NULL; 3667 DMPolytopeType ft; 3668 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3669 PetscInt dim, coneSize, c, d, clSize, cl; 3670 3671 PetscFunctionBeginHot; 3672 PetscCall(DMGetDimension(dm, &dim)); 3673 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3674 PetscCall(DMPlexGetCone(dm, point, &cone)); 3675 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3676 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3677 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3678 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3679 maxSize = PetscMax(coneSeries, supportSeries); 3680 if (*points) { 3681 pts = *points; 3682 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3683 c = 0; 3684 pts[c++] = point; 3685 pts[c++] = o; 3686 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3687 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3688 for (cl = 0; cl < clSize * 2; cl += 2) { 3689 pts[c++] = closure[cl]; 3690 pts[c++] = closure[cl + 1]; 3691 } 3692 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3693 for (cl = 0; cl < clSize * 2; cl += 2) { 3694 pts[c++] = closure[cl]; 3695 pts[c++] = closure[cl + 1]; 3696 } 3697 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3698 for (d = 2; d < coneSize; ++d) { 3699 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3700 pts[c++] = cone[arr[d * 2 + 0]]; 3701 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3702 } 3703 if (dim >= 3) { 3704 for (d = 2; d < coneSize; ++d) { 3705 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3706 const PetscInt *fcone, *fornt; 3707 PetscInt fconeSize, fc, i; 3708 3709 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3710 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3711 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3712 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3713 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3714 for (fc = 0; fc < fconeSize; ++fc) { 3715 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3716 const PetscInt co = farr[fc * 2 + 1]; 3717 3718 for (i = 0; i < c; i += 2) 3719 if (pts[i] == cp) break; 3720 if (i == c) { 3721 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3722 pts[c++] = cp; 3723 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3724 } 3725 } 3726 } 3727 } 3728 *numPoints = c / 2; 3729 *points = pts; 3730 PetscFunctionReturn(PETSC_SUCCESS); 3731 } 3732 3733 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3734 { 3735 DMPolytopeType ct; 3736 PetscInt *closure, *fifo; 3737 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3738 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3739 PetscInt depth, maxSize; 3740 3741 PetscFunctionBeginHot; 3742 PetscCall(DMPlexGetDepth(dm, &depth)); 3743 if (depth == 1) { 3744 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3745 PetscFunctionReturn(PETSC_SUCCESS); 3746 } 3747 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3748 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3749 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3750 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3751 PetscFunctionReturn(PETSC_SUCCESS); 3752 } 3753 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3754 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3755 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3756 maxSize = PetscMax(coneSeries, supportSeries); 3757 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3758 if (*points) { 3759 closure = *points; 3760 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3761 closure[closureSize++] = p; 3762 closure[closureSize++] = ornt; 3763 fifo[fifoSize++] = p; 3764 fifo[fifoSize++] = ornt; 3765 fifo[fifoSize++] = ct; 3766 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3767 while (fifoSize - fifoStart) { 3768 const PetscInt q = fifo[fifoStart++]; 3769 const PetscInt o = fifo[fifoStart++]; 3770 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3771 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3772 const PetscInt *tmp, *tmpO; 3773 PetscInt tmpSize, t; 3774 3775 if (PetscDefined(USE_DEBUG)) { 3776 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3777 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); 3778 } 3779 if (useCone) { 3780 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3781 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3782 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3783 } else { 3784 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3785 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3786 tmpO = NULL; 3787 } 3788 for (t = 0; t < tmpSize; ++t) { 3789 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3790 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3791 const PetscInt cp = tmp[ip]; 3792 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3793 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3794 PetscInt c; 3795 3796 /* Check for duplicate */ 3797 for (c = 0; c < closureSize; c += 2) { 3798 if (closure[c] == cp) break; 3799 } 3800 if (c == closureSize) { 3801 closure[closureSize++] = cp; 3802 closure[closureSize++] = co; 3803 fifo[fifoSize++] = cp; 3804 fifo[fifoSize++] = co; 3805 fifo[fifoSize++] = ct; 3806 } 3807 } 3808 } 3809 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3810 if (numPoints) *numPoints = closureSize / 2; 3811 if (points) *points = closure; 3812 PetscFunctionReturn(PETSC_SUCCESS); 3813 } 3814 3815 /*@C 3816 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3817 3818 Not Collective 3819 3820 Input Parameters: 3821 + dm - The `DMPLEX` 3822 . p - The mesh point 3823 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3824 3825 Input/Output Parameter: 3826 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3827 if `NULL` on input, internal storage will be returned, otherwise the provided array is used 3828 3829 Output Parameter: 3830 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3831 3832 Level: beginner 3833 3834 Note: 3835 If using internal storage (points is `NULL` on input), each call overwrites the last output. 3836 3837 Fortran Note: 3838 The `numPoints` argument is not present in the Fortran binding since it is internal to the array. 3839 3840 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3841 @*/ 3842 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3843 { 3844 PetscFunctionBeginHot; 3845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3846 if (numPoints) PetscValidIntPointer(numPoints, 4); 3847 if (points) PetscValidPointer(points, 5); 3848 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3849 PetscFunctionReturn(PETSC_SUCCESS); 3850 } 3851 3852 /*@C 3853 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3854 3855 Not Collective 3856 3857 Input Parameters: 3858 + dm - The `DMPLEX` 3859 . p - The mesh point 3860 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3861 . numPoints - The number of points in the closure, so points[] is of size 2*`numPoints` 3862 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3863 3864 Level: beginner 3865 3866 Note: 3867 If not using internal storage (points is not `NULL` on input), this call is unnecessary 3868 3869 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3870 @*/ 3871 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3872 { 3873 PetscFunctionBeginHot; 3874 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3875 if (numPoints) *numPoints = 0; 3876 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3877 PetscFunctionReturn(PETSC_SUCCESS); 3878 } 3879 3880 /*@ 3881 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3882 3883 Not Collective 3884 3885 Input Parameter: 3886 . mesh - The `DMPLEX` 3887 3888 Output Parameters: 3889 + maxConeSize - The maximum number of in-edges 3890 - maxSupportSize - The maximum number of out-edges 3891 3892 Level: beginner 3893 3894 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3895 @*/ 3896 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3897 { 3898 DM_Plex *mesh = (DM_Plex *)dm->data; 3899 3900 PetscFunctionBegin; 3901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3902 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3903 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3904 PetscFunctionReturn(PETSC_SUCCESS); 3905 } 3906 3907 PetscErrorCode DMSetUp_Plex(DM dm) 3908 { 3909 DM_Plex *mesh = (DM_Plex *)dm->data; 3910 PetscInt size, maxSupportSize; 3911 3912 PetscFunctionBegin; 3913 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3914 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3915 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3916 PetscCall(PetscMalloc1(size, &mesh->cones)); 3917 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3918 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3919 if (maxSupportSize) { 3920 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3921 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3922 PetscCall(PetscMalloc1(size, &mesh->supports)); 3923 } 3924 PetscFunctionReturn(PETSC_SUCCESS); 3925 } 3926 3927 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3928 { 3929 PetscFunctionBegin; 3930 if (subdm) PetscCall(DMClone(dm, subdm)); 3931 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3932 if (subdm) (*subdm)->useNatural = dm->useNatural; 3933 if (dm->useNatural && dm->sfMigration) { 3934 PetscSF sfNatural; 3935 3936 (*subdm)->sfMigration = dm->sfMigration; 3937 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3938 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3939 (*subdm)->sfNatural = sfNatural; 3940 } 3941 PetscFunctionReturn(PETSC_SUCCESS); 3942 } 3943 3944 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3945 { 3946 PetscInt i = 0; 3947 3948 PetscFunctionBegin; 3949 PetscCall(DMClone(dms[0], superdm)); 3950 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3951 (*superdm)->useNatural = PETSC_FALSE; 3952 for (i = 0; i < len; i++) { 3953 if (dms[i]->useNatural && dms[i]->sfMigration) { 3954 PetscSF sfNatural; 3955 3956 (*superdm)->sfMigration = dms[i]->sfMigration; 3957 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3958 (*superdm)->useNatural = PETSC_TRUE; 3959 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3960 (*superdm)->sfNatural = sfNatural; 3961 break; 3962 } 3963 } 3964 PetscFunctionReturn(PETSC_SUCCESS); 3965 } 3966 3967 /*@ 3968 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3969 3970 Not Collective 3971 3972 Input Parameter: 3973 . mesh - The `DMPLEX` 3974 3975 Level: beginner 3976 3977 Note: 3978 This should be called after all calls to `DMPlexSetCone()` 3979 3980 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3981 @*/ 3982 PetscErrorCode DMPlexSymmetrize(DM dm) 3983 { 3984 DM_Plex *mesh = (DM_Plex *)dm->data; 3985 PetscInt *offsets; 3986 PetscInt supportSize; 3987 PetscInt pStart, pEnd, p; 3988 3989 PetscFunctionBegin; 3990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3991 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3992 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3993 /* Calculate support sizes */ 3994 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3995 for (p = pStart; p < pEnd; ++p) { 3996 PetscInt dof, off, c; 3997 3998 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3999 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4000 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 4001 } 4002 PetscCall(PetscSectionSetUp(mesh->supportSection)); 4003 /* Calculate supports */ 4004 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 4005 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 4006 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 4007 for (p = pStart; p < pEnd; ++p) { 4008 PetscInt dof, off, c; 4009 4010 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 4011 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 4012 for (c = off; c < off + dof; ++c) { 4013 const PetscInt q = mesh->cones[c]; 4014 PetscInt offS; 4015 4016 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 4017 4018 mesh->supports[offS + offsets[q]] = p; 4019 ++offsets[q]; 4020 } 4021 } 4022 PetscCall(PetscFree(offsets)); 4023 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4024 PetscFunctionReturn(PETSC_SUCCESS); 4025 } 4026 4027 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4028 { 4029 IS stratumIS; 4030 4031 PetscFunctionBegin; 4032 if (pStart >= pEnd) PetscFunctionReturn(PETSC_SUCCESS); 4033 if (PetscDefined(USE_DEBUG)) { 4034 PetscInt qStart, qEnd, numLevels, level; 4035 PetscBool overlap = PETSC_FALSE; 4036 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4037 for (level = 0; level < numLevels; level++) { 4038 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4039 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4040 overlap = PETSC_TRUE; 4041 break; 4042 } 4043 } 4044 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); 4045 } 4046 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4047 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4048 PetscCall(ISDestroy(&stratumIS)); 4049 PetscFunctionReturn(PETSC_SUCCESS); 4050 } 4051 4052 /*@ 4053 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4054 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 4055 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 4056 the DAG. 4057 4058 Collective 4059 4060 Input Parameter: 4061 . mesh - The `DMPLEX` 4062 4063 Level: beginner 4064 4065 Notes: 4066 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4067 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4068 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4069 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4070 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4071 4072 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4073 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4074 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 4075 to interpolate only that one (e0), so that 4076 .vb 4077 cone(c0) = {e0, v2} 4078 cone(e0) = {v0, v1} 4079 .ve 4080 If `DMPlexStratify()` is run on this mesh, it will give depths 4081 .vb 4082 depth 0 = {v0, v1, v2} 4083 depth 1 = {e0, c0} 4084 .ve 4085 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4086 4087 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4088 4089 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4090 @*/ 4091 PetscErrorCode DMPlexStratify(DM dm) 4092 { 4093 DM_Plex *mesh = (DM_Plex *)dm->data; 4094 DMLabel label; 4095 PetscInt pStart, pEnd, p; 4096 PetscInt numRoots = 0, numLeaves = 0; 4097 4098 PetscFunctionBegin; 4099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4100 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4101 4102 /* Create depth label */ 4103 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4104 PetscCall(DMCreateLabel(dm, "depth")); 4105 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4106 4107 { 4108 /* Initialize roots and count leaves */ 4109 PetscInt sMin = PETSC_MAX_INT; 4110 PetscInt sMax = PETSC_MIN_INT; 4111 PetscInt coneSize, supportSize; 4112 4113 for (p = pStart; p < pEnd; ++p) { 4114 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4115 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4116 if (!coneSize && supportSize) { 4117 sMin = PetscMin(p, sMin); 4118 sMax = PetscMax(p, sMax); 4119 ++numRoots; 4120 } else if (!supportSize && coneSize) { 4121 ++numLeaves; 4122 } else if (!supportSize && !coneSize) { 4123 /* Isolated points */ 4124 sMin = PetscMin(p, sMin); 4125 sMax = PetscMax(p, sMax); 4126 } 4127 } 4128 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4129 } 4130 4131 if (numRoots + numLeaves == (pEnd - pStart)) { 4132 PetscInt sMin = PETSC_MAX_INT; 4133 PetscInt sMax = PETSC_MIN_INT; 4134 PetscInt coneSize, supportSize; 4135 4136 for (p = pStart; p < pEnd; ++p) { 4137 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4138 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4139 if (!supportSize && coneSize) { 4140 sMin = PetscMin(p, sMin); 4141 sMax = PetscMax(p, sMax); 4142 } 4143 } 4144 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4145 } else { 4146 PetscInt level = 0; 4147 PetscInt qStart, qEnd, q; 4148 4149 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4150 while (qEnd > qStart) { 4151 PetscInt sMin = PETSC_MAX_INT; 4152 PetscInt sMax = PETSC_MIN_INT; 4153 4154 for (q = qStart; q < qEnd; ++q) { 4155 const PetscInt *support; 4156 PetscInt supportSize, s; 4157 4158 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4159 PetscCall(DMPlexGetSupport(dm, q, &support)); 4160 for (s = 0; s < supportSize; ++s) { 4161 sMin = PetscMin(support[s], sMin); 4162 sMax = PetscMax(support[s], sMax); 4163 } 4164 } 4165 PetscCall(DMLabelGetNumValues(label, &level)); 4166 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4167 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4168 } 4169 } 4170 { /* just in case there is an empty process */ 4171 PetscInt numValues, maxValues = 0, v; 4172 4173 PetscCall(DMLabelGetNumValues(label, &numValues)); 4174 PetscCall(MPIU_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4175 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4176 } 4177 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4178 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4179 PetscFunctionReturn(PETSC_SUCCESS); 4180 } 4181 4182 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4183 { 4184 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4185 PetscInt dim, depth, pheight, coneSize; 4186 4187 PetscFunctionBeginHot; 4188 PetscCall(DMGetDimension(dm, &dim)); 4189 PetscCall(DMPlexGetDepth(dm, &depth)); 4190 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4191 pheight = depth - pdepth; 4192 if (depth <= 1) { 4193 switch (pdepth) { 4194 case 0: 4195 ct = DM_POLYTOPE_POINT; 4196 break; 4197 case 1: 4198 switch (coneSize) { 4199 case 2: 4200 ct = DM_POLYTOPE_SEGMENT; 4201 break; 4202 case 3: 4203 ct = DM_POLYTOPE_TRIANGLE; 4204 break; 4205 case 4: 4206 switch (dim) { 4207 case 2: 4208 ct = DM_POLYTOPE_QUADRILATERAL; 4209 break; 4210 case 3: 4211 ct = DM_POLYTOPE_TETRAHEDRON; 4212 break; 4213 default: 4214 break; 4215 } 4216 break; 4217 case 5: 4218 ct = DM_POLYTOPE_PYRAMID; 4219 break; 4220 case 6: 4221 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4222 break; 4223 case 8: 4224 ct = DM_POLYTOPE_HEXAHEDRON; 4225 break; 4226 default: 4227 break; 4228 } 4229 } 4230 } else { 4231 if (pdepth == 0) { 4232 ct = DM_POLYTOPE_POINT; 4233 } else if (pheight == 0) { 4234 switch (dim) { 4235 case 1: 4236 switch (coneSize) { 4237 case 2: 4238 ct = DM_POLYTOPE_SEGMENT; 4239 break; 4240 default: 4241 break; 4242 } 4243 break; 4244 case 2: 4245 switch (coneSize) { 4246 case 3: 4247 ct = DM_POLYTOPE_TRIANGLE; 4248 break; 4249 case 4: 4250 ct = DM_POLYTOPE_QUADRILATERAL; 4251 break; 4252 default: 4253 break; 4254 } 4255 break; 4256 case 3: 4257 switch (coneSize) { 4258 case 4: 4259 ct = DM_POLYTOPE_TETRAHEDRON; 4260 break; 4261 case 5: { 4262 const PetscInt *cone; 4263 PetscInt faceConeSize; 4264 4265 PetscCall(DMPlexGetCone(dm, p, &cone)); 4266 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4267 switch (faceConeSize) { 4268 case 3: 4269 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4270 break; 4271 case 4: 4272 ct = DM_POLYTOPE_PYRAMID; 4273 break; 4274 } 4275 } break; 4276 case 6: 4277 ct = DM_POLYTOPE_HEXAHEDRON; 4278 break; 4279 default: 4280 break; 4281 } 4282 break; 4283 default: 4284 break; 4285 } 4286 } else if (pheight > 0) { 4287 switch (coneSize) { 4288 case 2: 4289 ct = DM_POLYTOPE_SEGMENT; 4290 break; 4291 case 3: 4292 ct = DM_POLYTOPE_TRIANGLE; 4293 break; 4294 case 4: 4295 ct = DM_POLYTOPE_QUADRILATERAL; 4296 break; 4297 default: 4298 break; 4299 } 4300 } 4301 } 4302 *pt = ct; 4303 PetscFunctionReturn(PETSC_SUCCESS); 4304 } 4305 4306 /*@ 4307 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4308 4309 Collective 4310 4311 Input Parameter: 4312 . mesh - The `DMPLEX` 4313 4314 Level: developer 4315 4316 Note: 4317 This function is normally called automatically when a cell type is requested. It creates an 4318 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4319 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4320 4321 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4322 4323 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4324 @*/ 4325 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4326 { 4327 DM_Plex *mesh; 4328 DMLabel ctLabel; 4329 PetscInt pStart, pEnd, p; 4330 4331 PetscFunctionBegin; 4332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4333 mesh = (DM_Plex *)dm->data; 4334 PetscCall(DMCreateLabel(dm, "celltype")); 4335 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4336 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4337 PetscCall(PetscFree(mesh->cellTypes)); 4338 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 4339 for (p = pStart; p < pEnd; ++p) { 4340 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4341 PetscInt pdepth; 4342 4343 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4344 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4345 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4346 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4347 mesh->cellTypes[p - pStart].value_as_uint8 = 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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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 Parameter: 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: [](ch_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 Parameter: 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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_unstructured), `DM`, `DMPLEX`, `DMPolytopeType`, `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 PetscInt pStart, pEnd; 5186 5187 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, NULL)); 5188 if (!mesh->cellTypes) { /* XXX remove? optimize? */ 5189 PetscCall(PetscSectionGetChart(mesh->coneSection, NULL, &pEnd)); 5190 PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5191 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5192 for (PetscInt p = pStart; p < pEnd; p++) { 5193 PetscCall(DMLabelGetValue(label, p, &ct)); 5194 mesh->cellTypes[p - pStart].value_as_uint8 = (DMPolytopeType)ct; 5195 } 5196 } 5197 *celltype = (DMPolytopeType)mesh->cellTypes[cell - pStart].value_as_uint8; 5198 if (PetscDefined(USE_DEBUG)) { 5199 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5200 PetscCall(DMLabelGetValue(label, cell, &ct)); 5201 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5202 PetscCheck(ct == *celltype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid cellType for %" PetscInt_FMT ": %d != %" PetscInt_FMT, cell, (int)*celltype, ct); 5203 } 5204 } 5205 PetscFunctionReturn(PETSC_SUCCESS); 5206 } 5207 5208 /*@ 5209 DMPlexSetCellType - Set the polytope type of a given cell 5210 5211 Not Collective 5212 5213 Input Parameters: 5214 + dm - The `DMPLEX` object 5215 . cell - The cell 5216 - celltype - The polytope type of the cell 5217 5218 Level: advanced 5219 5220 Note: 5221 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5222 is executed. This function will override the computed type. However, if automatic classification will not succeed 5223 and a user wants to manually specify all types, the classification must be disabled by calling 5224 DMCreateLabel(dm, "celltype") before getting or setting any cell types. 5225 5226 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5227 @*/ 5228 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5229 { 5230 DM_Plex *mesh = (DM_Plex *)dm->data; 5231 DMLabel label; 5232 PetscInt pStart, pEnd; 5233 5234 PetscFunctionBegin; 5235 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5236 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 5237 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5238 PetscCall(DMLabelSetValue(label, cell, celltype)); 5239 if (!mesh->cellTypes) PetscCall(PetscMalloc1(pEnd - pStart, &mesh->cellTypes)); 5240 mesh->cellTypes[cell - pStart].value_as_uint8 = celltype; 5241 PetscFunctionReturn(PETSC_SUCCESS); 5242 } 5243 5244 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5245 { 5246 PetscSection section, s; 5247 Mat m; 5248 PetscInt maxHeight; 5249 const char *prefix; 5250 5251 PetscFunctionBegin; 5252 PetscCall(DMClone(dm, cdm)); 5253 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5254 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5255 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5256 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5257 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5258 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5259 PetscCall(DMSetLocalSection(*cdm, section)); 5260 PetscCall(PetscSectionDestroy(§ion)); 5261 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5262 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5263 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5264 PetscCall(PetscSectionDestroy(&s)); 5265 PetscCall(MatDestroy(&m)); 5266 5267 PetscCall(DMSetNumFields(*cdm, 1)); 5268 PetscCall(DMCreateDS(*cdm)); 5269 (*cdm)->cloneOpts = PETSC_TRUE; 5270 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5271 PetscFunctionReturn(PETSC_SUCCESS); 5272 } 5273 5274 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5275 { 5276 Vec coordsLocal, cellCoordsLocal; 5277 DM coordsDM, cellCoordsDM; 5278 5279 PetscFunctionBegin; 5280 *field = NULL; 5281 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5282 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5283 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5284 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5285 if (coordsLocal && coordsDM) { 5286 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5287 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5288 } 5289 PetscFunctionReturn(PETSC_SUCCESS); 5290 } 5291 5292 /*@C 5293 DMPlexGetConeSection - Return a section which describes the layout of cone data 5294 5295 Not Collective 5296 5297 Input Parameter: 5298 . dm - The `DMPLEX` object 5299 5300 Output Parameter: 5301 . section - The `PetscSection` object 5302 5303 Level: developer 5304 5305 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5306 @*/ 5307 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5308 { 5309 DM_Plex *mesh = (DM_Plex *)dm->data; 5310 5311 PetscFunctionBegin; 5312 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5313 if (section) *section = mesh->coneSection; 5314 PetscFunctionReturn(PETSC_SUCCESS); 5315 } 5316 5317 /*@C 5318 DMPlexGetSupportSection - Return a section which describes the layout of support data 5319 5320 Not Collective 5321 5322 Input Parameter: 5323 . dm - The `DMPLEX` object 5324 5325 Output Parameter: 5326 . section - The `PetscSection` object 5327 5328 Level: developer 5329 5330 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5331 @*/ 5332 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5333 { 5334 DM_Plex *mesh = (DM_Plex *)dm->data; 5335 5336 PetscFunctionBegin; 5337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5338 if (section) *section = mesh->supportSection; 5339 PetscFunctionReturn(PETSC_SUCCESS); 5340 } 5341 5342 /*@C 5343 DMPlexGetCones - Return cone data 5344 5345 Not Collective 5346 5347 Input Parameter: 5348 . dm - The `DMPLEX` object 5349 5350 Output Parameter: 5351 . cones - The cone for each point 5352 5353 Level: developer 5354 5355 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5356 @*/ 5357 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5358 { 5359 DM_Plex *mesh = (DM_Plex *)dm->data; 5360 5361 PetscFunctionBegin; 5362 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5363 if (cones) *cones = mesh->cones; 5364 PetscFunctionReturn(PETSC_SUCCESS); 5365 } 5366 5367 /*@C 5368 DMPlexGetConeOrientations - Return cone orientation data 5369 5370 Not Collective 5371 5372 Input Parameter: 5373 . dm - The `DMPLEX` object 5374 5375 Output Parameter: 5376 . coneOrientations - The array of cone orientations for all points 5377 5378 Level: developer 5379 5380 Notes: 5381 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5382 5383 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5384 5385 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5386 @*/ 5387 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5388 { 5389 DM_Plex *mesh = (DM_Plex *)dm->data; 5390 5391 PetscFunctionBegin; 5392 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5393 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5394 PetscFunctionReturn(PETSC_SUCCESS); 5395 } 5396 5397 /******************************** FEM Support **********************************/ 5398 5399 /* 5400 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5401 representing a line in the section. 5402 */ 5403 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5404 { 5405 PetscFunctionBeginHot; 5406 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5407 if (line < 0) { 5408 *k = 0; 5409 *Nc = 0; 5410 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5411 *k = 1; 5412 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5413 /* An order k SEM disc has k-1 dofs on an edge */ 5414 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5415 *k = *k / *Nc + 1; 5416 } 5417 PetscFunctionReturn(PETSC_SUCCESS); 5418 } 5419 5420 /*@ 5421 5422 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5423 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5424 section provided (or the section of the `DM`). 5425 5426 Input Parameters: 5427 + dm - The `DM` 5428 . point - Either a cell (highest dim point) or an edge (dim 1 point), or `PETSC_DETERMINE` 5429 - section - The `PetscSection` to reorder, or `NULL` for the default section 5430 5431 Example: 5432 A typical interpolated single-quad mesh might order points as 5433 .vb 5434 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5435 5436 v4 -- e6 -- v3 5437 | | 5438 e7 c0 e8 5439 | | 5440 v1 -- e5 -- v2 5441 .ve 5442 5443 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5444 dofs in the order of points, e.g., 5445 .vb 5446 c0 -> [0,1,2,3] 5447 v1 -> [4] 5448 ... 5449 e5 -> [8, 9] 5450 .ve 5451 5452 which corresponds to the dofs 5453 .vb 5454 6 10 11 7 5455 13 2 3 15 5456 12 0 1 14 5457 4 8 9 5 5458 .ve 5459 5460 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5461 .vb 5462 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5463 .ve 5464 5465 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5466 .vb 5467 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5468 .ve 5469 5470 Level: developer 5471 5472 Note: 5473 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5474 degree of the basis. 5475 5476 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5477 @*/ 5478 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5479 { 5480 DMLabel label; 5481 PetscInt dim, depth = -1, eStart = -1, Nf; 5482 PetscBool vertexchart; 5483 5484 PetscFunctionBegin; 5485 PetscCall(DMGetDimension(dm, &dim)); 5486 if (dim < 1) PetscFunctionReturn(PETSC_SUCCESS); 5487 if (point < 0) { 5488 PetscInt sStart, sEnd; 5489 5490 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5491 point = sEnd - sStart ? sStart : point; 5492 } 5493 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5494 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5495 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5496 if (depth == 1) { 5497 eStart = point; 5498 } else if (depth == dim) { 5499 const PetscInt *cone; 5500 5501 PetscCall(DMPlexGetCone(dm, point, &cone)); 5502 if (dim == 2) eStart = cone[0]; 5503 else if (dim == 3) { 5504 const PetscInt *cone2; 5505 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5506 eStart = cone2[0]; 5507 } 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); 5508 } 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); 5509 { /* Determine whether the chart covers all points or just vertices. */ 5510 PetscInt pStart, pEnd, cStart, cEnd; 5511 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5512 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5513 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5514 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5515 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5516 } 5517 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5518 for (PetscInt d = 1; d <= dim; d++) { 5519 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5520 PetscInt *perm; 5521 5522 for (f = 0; f < Nf; ++f) { 5523 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5524 size += PetscPowInt(k + 1, d) * Nc; 5525 } 5526 PetscCall(PetscMalloc1(size, &perm)); 5527 for (f = 0; f < Nf; ++f) { 5528 switch (d) { 5529 case 1: 5530 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5531 /* 5532 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5533 We want [ vtx0; edge of length k-1; vtx1 ] 5534 */ 5535 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5536 for (i = 0; i < k - 1; i++) 5537 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5538 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5539 foffset = offset; 5540 break; 5541 case 2: 5542 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5543 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5544 /* The SEM order is 5545 5546 v_lb, {e_b}, v_rb, 5547 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5548 v_lt, reverse {e_t}, v_rt 5549 */ 5550 { 5551 const PetscInt of = 0; 5552 const PetscInt oeb = of + PetscSqr(k - 1); 5553 const PetscInt oer = oeb + (k - 1); 5554 const PetscInt oet = oer + (k - 1); 5555 const PetscInt oel = oet + (k - 1); 5556 const PetscInt ovlb = oel + (k - 1); 5557 const PetscInt ovrb = ovlb + 1; 5558 const PetscInt ovrt = ovrb + 1; 5559 const PetscInt ovlt = ovrt + 1; 5560 PetscInt o; 5561 5562 /* bottom */ 5563 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5564 for (o = oeb; o < oer; ++o) 5565 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5566 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5567 /* middle */ 5568 for (i = 0; i < k - 1; ++i) { 5569 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5570 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5571 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5572 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5573 } 5574 /* top */ 5575 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5576 for (o = oel - 1; o >= oet; --o) 5577 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5578 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5579 foffset = offset; 5580 } 5581 break; 5582 case 3: 5583 /* The original hex closure is 5584 5585 {c, 5586 f_b, f_t, f_f, f_b, f_r, f_l, 5587 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5588 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5589 */ 5590 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5591 /* The SEM order is 5592 Bottom Slice 5593 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5594 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5595 v_blb, {e_bb}, v_brb, 5596 5597 Middle Slice (j) 5598 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5599 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5600 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5601 5602 Top Slice 5603 v_tlf, {e_tf}, v_trf, 5604 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5605 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5606 */ 5607 { 5608 const PetscInt oc = 0; 5609 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5610 const PetscInt oft = ofb + PetscSqr(k - 1); 5611 const PetscInt off = oft + PetscSqr(k - 1); 5612 const PetscInt ofk = off + PetscSqr(k - 1); 5613 const PetscInt ofr = ofk + PetscSqr(k - 1); 5614 const PetscInt ofl = ofr + PetscSqr(k - 1); 5615 const PetscInt oebl = ofl + PetscSqr(k - 1); 5616 const PetscInt oebb = oebl + (k - 1); 5617 const PetscInt oebr = oebb + (k - 1); 5618 const PetscInt oebf = oebr + (k - 1); 5619 const PetscInt oetf = oebf + (k - 1); 5620 const PetscInt oetr = oetf + (k - 1); 5621 const PetscInt oetb = oetr + (k - 1); 5622 const PetscInt oetl = oetb + (k - 1); 5623 const PetscInt oerf = oetl + (k - 1); 5624 const PetscInt oelf = oerf + (k - 1); 5625 const PetscInt oelb = oelf + (k - 1); 5626 const PetscInt oerb = oelb + (k - 1); 5627 const PetscInt ovblf = oerb + (k - 1); 5628 const PetscInt ovblb = ovblf + 1; 5629 const PetscInt ovbrb = ovblb + 1; 5630 const PetscInt ovbrf = ovbrb + 1; 5631 const PetscInt ovtlf = ovbrf + 1; 5632 const PetscInt ovtrf = ovtlf + 1; 5633 const PetscInt ovtrb = ovtrf + 1; 5634 const PetscInt ovtlb = ovtrb + 1; 5635 PetscInt o, n; 5636 5637 /* Bottom Slice */ 5638 /* bottom */ 5639 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5640 for (o = oetf - 1; o >= oebf; --o) 5641 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5642 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5643 /* middle */ 5644 for (i = 0; i < k - 1; ++i) { 5645 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5646 for (n = 0; n < k - 1; ++n) { 5647 o = ofb + n * (k - 1) + i; 5648 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5649 } 5650 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5651 } 5652 /* top */ 5653 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5654 for (o = oebb; o < oebr; ++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] = ovbrb * Nc + c + foffset; 5657 5658 /* Middle Slice */ 5659 for (j = 0; j < k - 1; ++j) { 5660 /* bottom */ 5661 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5662 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++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] = (oerf + j) * Nc + c + foffset; 5665 /* middle */ 5666 for (i = 0; i < k - 1; ++i) { 5667 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5668 for (n = 0; n < k - 1; ++n) 5669 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5670 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5671 } 5672 /* top */ 5673 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5674 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --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] = (oerb + (k - 2) - j) * Nc + c + foffset; 5677 } 5678 5679 /* Top Slice */ 5680 /* bottom */ 5681 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5682 for (o = oetf; o < oetr; ++o) 5683 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5684 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5685 /* middle */ 5686 for (i = 0; i < k - 1; ++i) { 5687 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5688 for (n = 0; n < k - 1; ++n) 5689 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5690 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5691 } 5692 /* top */ 5693 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5694 for (o = oetl - 1; o >= oetb; --o) 5695 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5696 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5697 5698 foffset = offset; 5699 } 5700 break; 5701 default: 5702 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5703 } 5704 } 5705 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5706 /* Check permutation */ 5707 { 5708 PetscInt *check; 5709 5710 PetscCall(PetscMalloc1(size, &check)); 5711 for (i = 0; i < size; ++i) { 5712 check[i] = -1; 5713 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5714 } 5715 for (i = 0; i < size; ++i) check[perm[i]] = i; 5716 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5717 PetscCall(PetscFree(check)); 5718 } 5719 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5720 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5721 PetscInt *loc_perm; 5722 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5723 for (PetscInt i = 0; i < size; i++) { 5724 loc_perm[i] = perm[i]; 5725 loc_perm[size + i] = size + perm[i]; 5726 } 5727 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5728 } 5729 } 5730 PetscFunctionReturn(PETSC_SUCCESS); 5731 } 5732 5733 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5734 { 5735 PetscDS prob; 5736 PetscInt depth, Nf, h; 5737 DMLabel label; 5738 5739 PetscFunctionBeginHot; 5740 PetscCall(DMGetDS(dm, &prob)); 5741 Nf = prob->Nf; 5742 label = dm->depthLabel; 5743 *dspace = NULL; 5744 if (field < Nf) { 5745 PetscObject disc = prob->disc[field]; 5746 5747 if (disc->classid == PETSCFE_CLASSID) { 5748 PetscDualSpace dsp; 5749 5750 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5751 PetscCall(DMLabelGetNumValues(label, &depth)); 5752 PetscCall(DMLabelGetValue(label, point, &h)); 5753 h = depth - 1 - h; 5754 if (h) { 5755 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5756 } else { 5757 *dspace = dsp; 5758 } 5759 } 5760 } 5761 PetscFunctionReturn(PETSC_SUCCESS); 5762 } 5763 5764 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5765 { 5766 PetscScalar *array; 5767 const PetscScalar *vArray; 5768 const PetscInt *cone, *coneO; 5769 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5770 5771 PetscFunctionBeginHot; 5772 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5773 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5774 PetscCall(DMPlexGetCone(dm, point, &cone)); 5775 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5776 if (!values || !*values) { 5777 if ((point >= pStart) && (point < pEnd)) { 5778 PetscInt dof; 5779 5780 PetscCall(PetscSectionGetDof(section, point, &dof)); 5781 size += dof; 5782 } 5783 for (p = 0; p < numPoints; ++p) { 5784 const PetscInt cp = cone[p]; 5785 PetscInt dof; 5786 5787 if ((cp < pStart) || (cp >= pEnd)) continue; 5788 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5789 size += dof; 5790 } 5791 if (!values) { 5792 if (csize) *csize = size; 5793 PetscFunctionReturn(PETSC_SUCCESS); 5794 } 5795 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5796 } else { 5797 array = *values; 5798 } 5799 size = 0; 5800 PetscCall(VecGetArrayRead(v, &vArray)); 5801 if ((point >= pStart) && (point < pEnd)) { 5802 PetscInt dof, off, d; 5803 const PetscScalar *varr; 5804 5805 PetscCall(PetscSectionGetDof(section, point, &dof)); 5806 PetscCall(PetscSectionGetOffset(section, point, &off)); 5807 varr = &vArray[off]; 5808 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5809 size += dof; 5810 } 5811 for (p = 0; p < numPoints; ++p) { 5812 const PetscInt cp = cone[p]; 5813 PetscInt o = coneO[p]; 5814 PetscInt dof, off, d; 5815 const PetscScalar *varr; 5816 5817 if ((cp < pStart) || (cp >= pEnd)) continue; 5818 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5819 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5820 varr = &vArray[off]; 5821 if (o >= 0) { 5822 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5823 } else { 5824 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5825 } 5826 size += dof; 5827 } 5828 PetscCall(VecRestoreArrayRead(v, &vArray)); 5829 if (!*values) { 5830 if (csize) *csize = size; 5831 *values = array; 5832 } else { 5833 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5834 *csize = size; 5835 } 5836 PetscFunctionReturn(PETSC_SUCCESS); 5837 } 5838 5839 /* Compress out points not in the section */ 5840 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5841 { 5842 const PetscInt np = *numPoints; 5843 PetscInt pStart, pEnd, p, q; 5844 5845 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5846 for (p = 0, q = 0; p < np; ++p) { 5847 const PetscInt r = points[p * 2]; 5848 if ((r >= pStart) && (r < pEnd)) { 5849 points[q * 2] = r; 5850 points[q * 2 + 1] = points[p * 2 + 1]; 5851 ++q; 5852 } 5853 } 5854 *numPoints = q; 5855 return PETSC_SUCCESS; 5856 } 5857 5858 /* Compressed closure does not apply closure permutation */ 5859 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt ornt, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5860 { 5861 const PetscInt *cla = NULL; 5862 PetscInt np, *pts = NULL; 5863 5864 PetscFunctionBeginHot; 5865 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5866 if (!ornt && *clPoints) { 5867 PetscInt dof, off; 5868 5869 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5870 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5871 PetscCall(ISGetIndices(*clPoints, &cla)); 5872 np = dof / 2; 5873 pts = (PetscInt *)&cla[off]; 5874 } else { 5875 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, point, ornt, PETSC_TRUE, &np, &pts)); 5876 PetscCall(CompressPoints_Private(section, &np, pts)); 5877 } 5878 *numPoints = np; 5879 *points = pts; 5880 *clp = cla; 5881 PetscFunctionReturn(PETSC_SUCCESS); 5882 } 5883 5884 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5885 { 5886 PetscFunctionBeginHot; 5887 if (!*clPoints) { 5888 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5889 } else { 5890 PetscCall(ISRestoreIndices(*clPoints, clp)); 5891 } 5892 *numPoints = 0; 5893 *points = NULL; 5894 *clSec = NULL; 5895 *clPoints = NULL; 5896 *clp = NULL; 5897 PetscFunctionReturn(PETSC_SUCCESS); 5898 } 5899 5900 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5901 { 5902 PetscInt offset = 0, p; 5903 const PetscInt **perms = NULL; 5904 const PetscScalar **flips = NULL; 5905 5906 PetscFunctionBeginHot; 5907 *size = 0; 5908 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5909 for (p = 0; p < numPoints; p++) { 5910 const PetscInt point = points[2 * p]; 5911 const PetscInt *perm = perms ? perms[p] : NULL; 5912 const PetscScalar *flip = flips ? flips[p] : NULL; 5913 PetscInt dof, off, d; 5914 const PetscScalar *varr; 5915 5916 PetscCall(PetscSectionGetDof(section, point, &dof)); 5917 PetscCall(PetscSectionGetOffset(section, point, &off)); 5918 varr = &vArray[off]; 5919 if (clperm) { 5920 if (perm) { 5921 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5922 } else { 5923 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5924 } 5925 if (flip) { 5926 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5927 } 5928 } else { 5929 if (perm) { 5930 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5931 } else { 5932 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5933 } 5934 if (flip) { 5935 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5936 } 5937 } 5938 offset += dof; 5939 } 5940 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5941 *size = offset; 5942 PetscFunctionReturn(PETSC_SUCCESS); 5943 } 5944 5945 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[]) 5946 { 5947 PetscInt offset = 0, f; 5948 5949 PetscFunctionBeginHot; 5950 *size = 0; 5951 for (f = 0; f < numFields; ++f) { 5952 PetscInt p; 5953 const PetscInt **perms = NULL; 5954 const PetscScalar **flips = NULL; 5955 5956 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5957 for (p = 0; p < numPoints; p++) { 5958 const PetscInt point = points[2 * p]; 5959 PetscInt fdof, foff, b; 5960 const PetscScalar *varr; 5961 const PetscInt *perm = perms ? perms[p] : NULL; 5962 const PetscScalar *flip = flips ? flips[p] : NULL; 5963 5964 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5965 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5966 varr = &vArray[foff]; 5967 if (clperm) { 5968 if (perm) { 5969 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5970 } else { 5971 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5972 } 5973 if (flip) { 5974 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5975 } 5976 } else { 5977 if (perm) { 5978 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5979 } else { 5980 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5981 } 5982 if (flip) { 5983 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5984 } 5985 } 5986 offset += fdof; 5987 } 5988 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5989 } 5990 *size = offset; 5991 PetscFunctionReturn(PETSC_SUCCESS); 5992 } 5993 5994 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 5995 { 5996 PetscSection clSection; 5997 IS clPoints; 5998 PetscInt *points = NULL; 5999 const PetscInt *clp, *perm; 6000 PetscInt depth, numFields, numPoints, asize; 6001 6002 PetscFunctionBeginHot; 6003 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6004 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6005 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6006 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6007 PetscCall(DMPlexGetDepth(dm, &depth)); 6008 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6009 if (depth == 1 && numFields < 2) { 6010 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6011 PetscFunctionReturn(PETSC_SUCCESS); 6012 } 6013 /* Get points */ 6014 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 6015 /* Get sizes */ 6016 asize = 0; 6017 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6018 PetscInt dof; 6019 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6020 asize += dof; 6021 } 6022 if (values) { 6023 const PetscScalar *vArray; 6024 PetscInt size; 6025 6026 if (*values) { 6027 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); 6028 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6029 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6030 PetscCall(VecGetArrayRead(v, &vArray)); 6031 /* Get values */ 6032 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6033 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6034 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6035 /* Cleanup array */ 6036 PetscCall(VecRestoreArrayRead(v, &vArray)); 6037 } 6038 if (csize) *csize = asize; 6039 /* Cleanup points */ 6040 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6041 PetscFunctionReturn(PETSC_SUCCESS); 6042 } 6043 6044 /*@C 6045 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6046 6047 Not collective 6048 6049 Input Parameters: 6050 + dm - The `DM` 6051 . section - The section describing the layout in `v`, or `NULL` to use the default section 6052 . v - The local vector 6053 - point - The point in the `DM` 6054 6055 Input/Output Parameters: 6056 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6057 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6058 if the user provided `NULL`, it is a borrowed array and should not be freed 6059 6060 Level: intermediate 6061 6062 Notes: 6063 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6064 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6065 assembly function, and a user may already have allocated storage for this operation. 6066 6067 A typical use could be 6068 .vb 6069 values = NULL; 6070 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6071 for (cl = 0; cl < clSize; ++cl) { 6072 <Compute on closure> 6073 } 6074 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6075 .ve 6076 or 6077 .vb 6078 PetscMalloc1(clMaxSize, &values); 6079 for (p = pStart; p < pEnd; ++p) { 6080 clSize = clMaxSize; 6081 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6082 for (cl = 0; cl < clSize; ++cl) { 6083 <Compute on closure> 6084 } 6085 } 6086 PetscFree(values); 6087 .ve 6088 6089 Fortran Note: 6090 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6091 6092 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6093 @*/ 6094 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6095 { 6096 PetscFunctionBeginHot; 6097 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, v, point, 0, csize, values)); 6098 PetscFunctionReturn(PETSC_SUCCESS); 6099 } 6100 6101 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6102 { 6103 DMLabel depthLabel; 6104 PetscSection clSection; 6105 IS clPoints; 6106 PetscScalar *array; 6107 const PetscScalar *vArray; 6108 PetscInt *points = NULL; 6109 const PetscInt *clp, *perm = NULL; 6110 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6111 6112 PetscFunctionBeginHot; 6113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6114 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6115 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6116 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6117 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6118 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6119 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6120 if (mdepth == 1 && numFields < 2) { 6121 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6122 PetscFunctionReturn(PETSC_SUCCESS); 6123 } 6124 /* Get points */ 6125 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6126 for (clsize = 0, p = 0; p < Np; p++) { 6127 PetscInt dof; 6128 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6129 clsize += dof; 6130 } 6131 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6132 /* Filter points */ 6133 for (p = 0; p < numPoints * 2; p += 2) { 6134 PetscInt dep; 6135 6136 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6137 if (dep != depth) continue; 6138 points[Np * 2 + 0] = points[p]; 6139 points[Np * 2 + 1] = points[p + 1]; 6140 ++Np; 6141 } 6142 /* Get array */ 6143 if (!values || !*values) { 6144 PetscInt asize = 0, dof; 6145 6146 for (p = 0; p < Np * 2; p += 2) { 6147 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6148 asize += dof; 6149 } 6150 if (!values) { 6151 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6152 if (csize) *csize = asize; 6153 PetscFunctionReturn(PETSC_SUCCESS); 6154 } 6155 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6156 } else { 6157 array = *values; 6158 } 6159 PetscCall(VecGetArrayRead(v, &vArray)); 6160 /* Get values */ 6161 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6162 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6163 /* Cleanup points */ 6164 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6165 /* Cleanup array */ 6166 PetscCall(VecRestoreArrayRead(v, &vArray)); 6167 if (!*values) { 6168 if (csize) *csize = size; 6169 *values = array; 6170 } else { 6171 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6172 *csize = size; 6173 } 6174 PetscFunctionReturn(PETSC_SUCCESS); 6175 } 6176 6177 /*@C 6178 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6179 6180 Not collective 6181 6182 Input Parameters: 6183 + dm - The `DM` 6184 . section - The section describing the layout in `v`, or `NULL` to use the default section 6185 . v - The local vector 6186 . point - The point in the `DM` 6187 . csize - The number of values in the closure, or `NULL` 6188 - values - The array of values, which is a borrowed array and should not be freed 6189 6190 Level: intermediate 6191 6192 Note: 6193 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6194 6195 Fortran Note: 6196 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6197 6198 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6199 @*/ 6200 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6201 { 6202 PetscInt size = 0; 6203 6204 PetscFunctionBegin; 6205 /* Should work without recalculating size */ 6206 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6207 *values = NULL; 6208 PetscFunctionReturn(PETSC_SUCCESS); 6209 } 6210 6211 static inline void add(PetscScalar *x, PetscScalar y) 6212 { 6213 *x += y; 6214 } 6215 static inline void insert(PetscScalar *x, PetscScalar y) 6216 { 6217 *x = y; 6218 } 6219 6220 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[]) 6221 { 6222 PetscInt cdof; /* The number of constraints on this point */ 6223 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6224 PetscScalar *a; 6225 PetscInt off, cind = 0, k; 6226 6227 PetscFunctionBegin; 6228 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6229 PetscCall(PetscSectionGetOffset(section, point, &off)); 6230 a = &array[off]; 6231 if (!cdof || setBC) { 6232 if (clperm) { 6233 if (perm) { 6234 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6235 } else { 6236 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6237 } 6238 } else { 6239 if (perm) { 6240 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6241 } else { 6242 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6243 } 6244 } 6245 } else { 6246 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6247 if (clperm) { 6248 if (perm) { 6249 for (k = 0; k < dof; ++k) { 6250 if ((cind < cdof) && (k == cdofs[cind])) { 6251 ++cind; 6252 continue; 6253 } 6254 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6255 } 6256 } else { 6257 for (k = 0; k < dof; ++k) { 6258 if ((cind < cdof) && (k == cdofs[cind])) { 6259 ++cind; 6260 continue; 6261 } 6262 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6263 } 6264 } 6265 } else { 6266 if (perm) { 6267 for (k = 0; k < dof; ++k) { 6268 if ((cind < cdof) && (k == cdofs[cind])) { 6269 ++cind; 6270 continue; 6271 } 6272 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6273 } 6274 } else { 6275 for (k = 0; k < dof; ++k) { 6276 if ((cind < cdof) && (k == cdofs[cind])) { 6277 ++cind; 6278 continue; 6279 } 6280 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6281 } 6282 } 6283 } 6284 } 6285 PetscFunctionReturn(PETSC_SUCCESS); 6286 } 6287 6288 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[]) 6289 { 6290 PetscInt cdof; /* The number of constraints on this point */ 6291 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6292 PetscScalar *a; 6293 PetscInt off, cind = 0, k; 6294 6295 PetscFunctionBegin; 6296 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6297 PetscCall(PetscSectionGetOffset(section, point, &off)); 6298 a = &array[off]; 6299 if (cdof) { 6300 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6301 if (clperm) { 6302 if (perm) { 6303 for (k = 0; k < dof; ++k) { 6304 if ((cind < cdof) && (k == cdofs[cind])) { 6305 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6306 cind++; 6307 } 6308 } 6309 } else { 6310 for (k = 0; k < dof; ++k) { 6311 if ((cind < cdof) && (k == cdofs[cind])) { 6312 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6313 cind++; 6314 } 6315 } 6316 } 6317 } else { 6318 if (perm) { 6319 for (k = 0; k < dof; ++k) { 6320 if ((cind < cdof) && (k == cdofs[cind])) { 6321 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6322 cind++; 6323 } 6324 } 6325 } else { 6326 for (k = 0; k < dof; ++k) { 6327 if ((cind < cdof) && (k == cdofs[cind])) { 6328 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6329 cind++; 6330 } 6331 } 6332 } 6333 } 6334 } 6335 PetscFunctionReturn(PETSC_SUCCESS); 6336 } 6337 6338 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[]) 6339 { 6340 PetscScalar *a; 6341 PetscInt fdof, foff, fcdof, foffset = *offset; 6342 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6343 PetscInt cind = 0, b; 6344 6345 PetscFunctionBegin; 6346 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6347 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6348 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6349 a = &array[foff]; 6350 if (!fcdof || setBC) { 6351 if (clperm) { 6352 if (perm) { 6353 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6354 } else { 6355 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6356 } 6357 } else { 6358 if (perm) { 6359 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6360 } else { 6361 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6362 } 6363 } 6364 } else { 6365 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6366 if (clperm) { 6367 if (perm) { 6368 for (b = 0; b < fdof; b++) { 6369 if ((cind < fcdof) && (b == fcdofs[cind])) { 6370 ++cind; 6371 continue; 6372 } 6373 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6374 } 6375 } else { 6376 for (b = 0; b < fdof; b++) { 6377 if ((cind < fcdof) && (b == fcdofs[cind])) { 6378 ++cind; 6379 continue; 6380 } 6381 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6382 } 6383 } 6384 } else { 6385 if (perm) { 6386 for (b = 0; b < fdof; b++) { 6387 if ((cind < fcdof) && (b == fcdofs[cind])) { 6388 ++cind; 6389 continue; 6390 } 6391 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6392 } 6393 } else { 6394 for (b = 0; b < fdof; b++) { 6395 if ((cind < fcdof) && (b == fcdofs[cind])) { 6396 ++cind; 6397 continue; 6398 } 6399 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6400 } 6401 } 6402 } 6403 } 6404 *offset += fdof; 6405 PetscFunctionReturn(PETSC_SUCCESS); 6406 } 6407 6408 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[]) 6409 { 6410 PetscScalar *a; 6411 PetscInt fdof, foff, fcdof, foffset = *offset; 6412 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6413 PetscInt Nc, cind = 0, ncind = 0, b; 6414 PetscBool ncSet, fcSet; 6415 6416 PetscFunctionBegin; 6417 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6418 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6419 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6420 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6421 a = &array[foff]; 6422 if (fcdof) { 6423 /* We just override fcdof and fcdofs with Ncc and comps */ 6424 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6425 if (clperm) { 6426 if (perm) { 6427 if (comps) { 6428 for (b = 0; b < fdof; b++) { 6429 ncSet = fcSet = PETSC_FALSE; 6430 if (b % Nc == comps[ncind]) { 6431 ncind = (ncind + 1) % Ncc; 6432 ncSet = PETSC_TRUE; 6433 } 6434 if ((cind < fcdof) && (b == fcdofs[cind])) { 6435 ++cind; 6436 fcSet = PETSC_TRUE; 6437 } 6438 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6439 } 6440 } else { 6441 for (b = 0; b < fdof; b++) { 6442 if ((cind < fcdof) && (b == fcdofs[cind])) { 6443 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6444 ++cind; 6445 } 6446 } 6447 } 6448 } else { 6449 if (comps) { 6450 for (b = 0; b < fdof; b++) { 6451 ncSet = fcSet = PETSC_FALSE; 6452 if (b % Nc == comps[ncind]) { 6453 ncind = (ncind + 1) % Ncc; 6454 ncSet = PETSC_TRUE; 6455 } 6456 if ((cind < fcdof) && (b == fcdofs[cind])) { 6457 ++cind; 6458 fcSet = PETSC_TRUE; 6459 } 6460 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6461 } 6462 } else { 6463 for (b = 0; b < fdof; b++) { 6464 if ((cind < fcdof) && (b == fcdofs[cind])) { 6465 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6466 ++cind; 6467 } 6468 } 6469 } 6470 } 6471 } else { 6472 if (perm) { 6473 if (comps) { 6474 for (b = 0; b < fdof; b++) { 6475 ncSet = fcSet = PETSC_FALSE; 6476 if (b % Nc == comps[ncind]) { 6477 ncind = (ncind + 1) % Ncc; 6478 ncSet = PETSC_TRUE; 6479 } 6480 if ((cind < fcdof) && (b == fcdofs[cind])) { 6481 ++cind; 6482 fcSet = PETSC_TRUE; 6483 } 6484 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6485 } 6486 } else { 6487 for (b = 0; b < fdof; b++) { 6488 if ((cind < fcdof) && (b == fcdofs[cind])) { 6489 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6490 ++cind; 6491 } 6492 } 6493 } 6494 } else { 6495 if (comps) { 6496 for (b = 0; b < fdof; b++) { 6497 ncSet = fcSet = PETSC_FALSE; 6498 if (b % Nc == comps[ncind]) { 6499 ncind = (ncind + 1) % Ncc; 6500 ncSet = PETSC_TRUE; 6501 } 6502 if ((cind < fcdof) && (b == fcdofs[cind])) { 6503 ++cind; 6504 fcSet = PETSC_TRUE; 6505 } 6506 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6507 } 6508 } else { 6509 for (b = 0; b < fdof; b++) { 6510 if ((cind < fcdof) && (b == fcdofs[cind])) { 6511 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6512 ++cind; 6513 } 6514 } 6515 } 6516 } 6517 } 6518 } 6519 *offset += fdof; 6520 PetscFunctionReturn(PETSC_SUCCESS); 6521 } 6522 6523 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6524 { 6525 PetscScalar *array; 6526 const PetscInt *cone, *coneO; 6527 PetscInt pStart, pEnd, p, numPoints, off, dof; 6528 6529 PetscFunctionBeginHot; 6530 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6531 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6532 PetscCall(DMPlexGetCone(dm, point, &cone)); 6533 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6534 PetscCall(VecGetArray(v, &array)); 6535 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6536 const PetscInt cp = !p ? point : cone[p - 1]; 6537 const PetscInt o = !p ? 0 : coneO[p - 1]; 6538 6539 if ((cp < pStart) || (cp >= pEnd)) { 6540 dof = 0; 6541 continue; 6542 } 6543 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6544 /* ADD_VALUES */ 6545 { 6546 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6547 PetscScalar *a; 6548 PetscInt cdof, coff, cind = 0, k; 6549 6550 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6551 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6552 a = &array[coff]; 6553 if (!cdof) { 6554 if (o >= 0) { 6555 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6556 } else { 6557 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6558 } 6559 } else { 6560 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6561 if (o >= 0) { 6562 for (k = 0; k < dof; ++k) { 6563 if ((cind < cdof) && (k == cdofs[cind])) { 6564 ++cind; 6565 continue; 6566 } 6567 a[k] += values[off + k]; 6568 } 6569 } else { 6570 for (k = 0; k < dof; ++k) { 6571 if ((cind < cdof) && (k == cdofs[cind])) { 6572 ++cind; 6573 continue; 6574 } 6575 a[k] += values[off + dof - k - 1]; 6576 } 6577 } 6578 } 6579 } 6580 } 6581 PetscCall(VecRestoreArray(v, &array)); 6582 PetscFunctionReturn(PETSC_SUCCESS); 6583 } 6584 6585 /*@C 6586 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6587 6588 Not collective 6589 6590 Input Parameters: 6591 + dm - The `DM` 6592 . section - The section describing the layout in `v`, or `NULL` to use the default section 6593 . v - The local vector 6594 . point - The point in the `DM` 6595 . values - The array of values 6596 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6597 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6598 6599 Level: intermediate 6600 6601 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6602 @*/ 6603 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6604 { 6605 PetscSection clSection; 6606 IS clPoints; 6607 PetscScalar *array; 6608 PetscInt *points = NULL; 6609 const PetscInt *clp, *clperm = NULL; 6610 PetscInt depth, numFields, numPoints, p, clsize; 6611 6612 PetscFunctionBeginHot; 6613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6614 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6615 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6616 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6617 PetscCall(DMPlexGetDepth(dm, &depth)); 6618 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6619 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6620 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6621 PetscFunctionReturn(PETSC_SUCCESS); 6622 } 6623 /* Get points */ 6624 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6625 for (clsize = 0, p = 0; p < numPoints; p++) { 6626 PetscInt dof; 6627 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6628 clsize += dof; 6629 } 6630 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6631 /* Get array */ 6632 PetscCall(VecGetArray(v, &array)); 6633 /* Get values */ 6634 if (numFields > 0) { 6635 PetscInt offset = 0, f; 6636 for (f = 0; f < numFields; ++f) { 6637 const PetscInt **perms = NULL; 6638 const PetscScalar **flips = NULL; 6639 6640 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6641 switch (mode) { 6642 case INSERT_VALUES: 6643 for (p = 0; p < numPoints; p++) { 6644 const PetscInt point = points[2 * p]; 6645 const PetscInt *perm = perms ? perms[p] : NULL; 6646 const PetscScalar *flip = flips ? flips[p] : NULL; 6647 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6648 } 6649 break; 6650 case INSERT_ALL_VALUES: 6651 for (p = 0; p < numPoints; p++) { 6652 const PetscInt point = points[2 * p]; 6653 const PetscInt *perm = perms ? perms[p] : NULL; 6654 const PetscScalar *flip = flips ? flips[p] : NULL; 6655 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6656 } 6657 break; 6658 case INSERT_BC_VALUES: 6659 for (p = 0; p < numPoints; p++) { 6660 const PetscInt point = points[2 * p]; 6661 const PetscInt *perm = perms ? perms[p] : NULL; 6662 const PetscScalar *flip = flips ? flips[p] : NULL; 6663 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6664 } 6665 break; 6666 case ADD_VALUES: 6667 for (p = 0; p < numPoints; p++) { 6668 const PetscInt point = points[2 * p]; 6669 const PetscInt *perm = perms ? perms[p] : NULL; 6670 const PetscScalar *flip = flips ? flips[p] : NULL; 6671 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6672 } 6673 break; 6674 case ADD_ALL_VALUES: 6675 for (p = 0; p < numPoints; p++) { 6676 const PetscInt point = points[2 * p]; 6677 const PetscInt *perm = perms ? perms[p] : NULL; 6678 const PetscScalar *flip = flips ? flips[p] : NULL; 6679 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6680 } 6681 break; 6682 case ADD_BC_VALUES: 6683 for (p = 0; p < numPoints; p++) { 6684 const PetscInt point = points[2 * p]; 6685 const PetscInt *perm = perms ? perms[p] : NULL; 6686 const PetscScalar *flip = flips ? flips[p] : NULL; 6687 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6688 } 6689 break; 6690 default: 6691 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6692 } 6693 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6694 } 6695 } else { 6696 PetscInt dof, off; 6697 const PetscInt **perms = NULL; 6698 const PetscScalar **flips = NULL; 6699 6700 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6701 switch (mode) { 6702 case INSERT_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, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6709 } 6710 break; 6711 case INSERT_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, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6718 } 6719 break; 6720 case INSERT_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, insert, perm, flip, clperm, values, off, array)); 6727 } 6728 break; 6729 case ADD_VALUES: 6730 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6731 const PetscInt point = points[2 * p]; 6732 const PetscInt *perm = perms ? perms[p] : NULL; 6733 const PetscScalar *flip = flips ? flips[p] : NULL; 6734 PetscCall(PetscSectionGetDof(section, point, &dof)); 6735 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6736 } 6737 break; 6738 case ADD_ALL_VALUES: 6739 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6740 const PetscInt point = points[2 * p]; 6741 const PetscInt *perm = perms ? perms[p] : NULL; 6742 const PetscScalar *flip = flips ? flips[p] : NULL; 6743 PetscCall(PetscSectionGetDof(section, point, &dof)); 6744 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6745 } 6746 break; 6747 case ADD_BC_VALUES: 6748 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6749 const PetscInt point = points[2 * p]; 6750 const PetscInt *perm = perms ? perms[p] : NULL; 6751 const PetscScalar *flip = flips ? flips[p] : NULL; 6752 PetscCall(PetscSectionGetDof(section, point, &dof)); 6753 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6754 } 6755 break; 6756 default: 6757 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6758 } 6759 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6760 } 6761 /* Cleanup points */ 6762 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6763 /* Cleanup array */ 6764 PetscCall(VecRestoreArray(v, &array)); 6765 PetscFunctionReturn(PETSC_SUCCESS); 6766 } 6767 6768 PetscErrorCode DMPlexVecSetStar(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6769 { 6770 const PetscInt *supp, *cone; 6771 PetscScalar *a; 6772 PetscInt dim, Ns, dof, off, n = 0; 6773 6774 PetscFunctionBegin; 6775 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6776 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6777 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6778 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6779 if (PetscDefined(USE_DEBUG)) { 6780 PetscInt vStart, vEnd; 6781 6782 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6783 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); 6784 } 6785 PetscValidScalarPointer(values, 5); 6786 6787 PetscCall(DMGetDimension(dm, &dim)); 6788 PetscCall(DMPlexGetSupportSize(dm, point, &Ns)); 6789 PetscCall(DMPlexGetSupport(dm, point, &supp)); 6790 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); 6791 PetscCall(VecGetArray(v, &a)); 6792 PetscCall(PetscSectionGetDof(section, point, &dof)); 6793 PetscCall(PetscSectionGetOffset(section, point, &off)); 6794 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6795 for (PetscInt d = 0; d < dim; ++d) { 6796 // Left edge 6797 PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone)); 6798 PetscCall(PetscSectionGetDof(section, cone[0], &dof)); 6799 PetscCall(PetscSectionGetOffset(section, cone[0], &off)); 6800 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6801 // Right edge 6802 PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone)); 6803 PetscCall(PetscSectionGetDof(section, cone[1], &dof)); 6804 PetscCall(PetscSectionGetOffset(section, cone[1], &off)); 6805 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6806 } 6807 PetscCall(VecRestoreArray(v, &a)); 6808 PetscFunctionReturn(PETSC_SUCCESS); 6809 } 6810 6811 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6812 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6813 { 6814 PetscFunctionBegin; 6815 *contains = PETSC_TRUE; 6816 if (label) { 6817 PetscInt fdof; 6818 6819 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6820 if (!*contains) { 6821 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6822 *offset += fdof; 6823 PetscFunctionReturn(PETSC_SUCCESS); 6824 } 6825 } 6826 PetscFunctionReturn(PETSC_SUCCESS); 6827 } 6828 6829 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6830 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) 6831 { 6832 PetscSection clSection; 6833 IS clPoints; 6834 PetscScalar *array; 6835 PetscInt *points = NULL; 6836 const PetscInt *clp; 6837 PetscInt numFields, numPoints, p; 6838 PetscInt offset = 0, f; 6839 6840 PetscFunctionBeginHot; 6841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6842 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6843 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6844 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6845 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6846 /* Get points */ 6847 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6848 /* Get array */ 6849 PetscCall(VecGetArray(v, &array)); 6850 /* Get values */ 6851 for (f = 0; f < numFields; ++f) { 6852 const PetscInt **perms = NULL; 6853 const PetscScalar **flips = NULL; 6854 PetscBool contains; 6855 6856 if (!fieldActive[f]) { 6857 for (p = 0; p < numPoints * 2; p += 2) { 6858 PetscInt fdof; 6859 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6860 offset += fdof; 6861 } 6862 continue; 6863 } 6864 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6865 switch (mode) { 6866 case INSERT_VALUES: 6867 for (p = 0; p < numPoints; p++) { 6868 const PetscInt point = points[2 * p]; 6869 const PetscInt *perm = perms ? perms[p] : NULL; 6870 const PetscScalar *flip = flips ? flips[p] : NULL; 6871 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6872 if (!contains) continue; 6873 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6874 } 6875 break; 6876 case INSERT_ALL_VALUES: 6877 for (p = 0; p < numPoints; p++) { 6878 const PetscInt point = points[2 * p]; 6879 const PetscInt *perm = perms ? perms[p] : NULL; 6880 const PetscScalar *flip = flips ? flips[p] : NULL; 6881 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6882 if (!contains) continue; 6883 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6884 } 6885 break; 6886 case INSERT_BC_VALUES: 6887 for (p = 0; p < numPoints; p++) { 6888 const PetscInt point = points[2 * p]; 6889 const PetscInt *perm = perms ? perms[p] : NULL; 6890 const PetscScalar *flip = flips ? flips[p] : NULL; 6891 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6892 if (!contains) continue; 6893 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6894 } 6895 break; 6896 case ADD_VALUES: 6897 for (p = 0; p < numPoints; p++) { 6898 const PetscInt point = points[2 * p]; 6899 const PetscInt *perm = perms ? perms[p] : NULL; 6900 const PetscScalar *flip = flips ? flips[p] : NULL; 6901 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6902 if (!contains) continue; 6903 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6904 } 6905 break; 6906 case ADD_ALL_VALUES: 6907 for (p = 0; p < numPoints; p++) { 6908 const PetscInt point = points[2 * p]; 6909 const PetscInt *perm = perms ? perms[p] : NULL; 6910 const PetscScalar *flip = flips ? flips[p] : NULL; 6911 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6912 if (!contains) continue; 6913 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6914 } 6915 break; 6916 default: 6917 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6918 } 6919 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6920 } 6921 /* Cleanup points */ 6922 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6923 /* Cleanup array */ 6924 PetscCall(VecRestoreArray(v, &array)); 6925 PetscFunctionReturn(PETSC_SUCCESS); 6926 } 6927 6928 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6929 { 6930 PetscMPIInt rank; 6931 PetscInt i, j; 6932 6933 PetscFunctionBegin; 6934 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6935 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6936 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6937 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6938 numCIndices = numCIndices ? numCIndices : numRIndices; 6939 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6940 for (i = 0; i < numRIndices; i++) { 6941 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6942 for (j = 0; j < numCIndices; j++) { 6943 #if defined(PETSC_USE_COMPLEX) 6944 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6945 #else 6946 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6947 #endif 6948 } 6949 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6950 } 6951 PetscFunctionReturn(PETSC_SUCCESS); 6952 } 6953 6954 /* 6955 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6956 6957 Input Parameters: 6958 + section - The section for this data layout 6959 . islocal - Is the section (and thus indices being requested) local or global? 6960 . point - The point contributing dofs with these indices 6961 . off - The global offset of this point 6962 . loff - The local offset of each field 6963 . setBC - The flag determining whether to include indices of boundary values 6964 . perm - A permutation of the dofs on this point, or NULL 6965 - indperm - A permutation of the entire indices array, or NULL 6966 6967 Output Parameter: 6968 . indices - Indices for dofs on this point 6969 6970 Level: developer 6971 6972 Note: The indices could be local or global, depending on the value of 'off'. 6973 */ 6974 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6975 { 6976 PetscInt dof; /* The number of unknowns on this point */ 6977 PetscInt cdof; /* The number of constraints on this point */ 6978 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6979 PetscInt cind = 0, k; 6980 6981 PetscFunctionBegin; 6982 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6983 PetscCall(PetscSectionGetDof(section, point, &dof)); 6984 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6985 if (!cdof || setBC) { 6986 for (k = 0; k < dof; ++k) { 6987 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6988 const PetscInt ind = indperm ? indperm[preind] : preind; 6989 6990 indices[ind] = off + k; 6991 } 6992 } else { 6993 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6994 for (k = 0; k < dof; ++k) { 6995 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6996 const PetscInt ind = indperm ? indperm[preind] : preind; 6997 6998 if ((cind < cdof) && (k == cdofs[cind])) { 6999 /* Insert check for returning constrained indices */ 7000 indices[ind] = -(off + k + 1); 7001 ++cind; 7002 } else { 7003 indices[ind] = off + k - (islocal ? 0 : cind); 7004 } 7005 } 7006 } 7007 *loff += dof; 7008 PetscFunctionReturn(PETSC_SUCCESS); 7009 } 7010 7011 /* 7012 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 7013 7014 Input Parameters: 7015 + section - a section (global or local) 7016 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 7017 . point - point within section 7018 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 7019 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 7020 . setBC - identify constrained (boundary condition) points via involution. 7021 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 7022 . permsoff - offset 7023 - indperm - index permutation 7024 7025 Output Parameter: 7026 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 7027 . indices - array to hold indices (as defined by section) of each dof associated with point 7028 7029 Notes: 7030 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 7031 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 7032 in the local vector. 7033 7034 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 7035 significant). It is invalid to call with a global section and setBC=true. 7036 7037 Developer Note: 7038 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7039 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7040 offset could be obtained from the section instead of passing it explicitly as we do now. 7041 7042 Example: 7043 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7044 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7045 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7046 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. 7047 7048 Level: developer 7049 */ 7050 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[]) 7051 { 7052 PetscInt numFields, foff, f; 7053 7054 PetscFunctionBegin; 7055 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7056 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7057 for (f = 0, foff = 0; f < numFields; ++f) { 7058 PetscInt fdof, cfdof; 7059 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7060 PetscInt cind = 0, b; 7061 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7062 7063 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7064 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7065 if (!cfdof || setBC) { 7066 for (b = 0; b < fdof; ++b) { 7067 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7068 const PetscInt ind = indperm ? indperm[preind] : preind; 7069 7070 indices[ind] = off + foff + b; 7071 } 7072 } else { 7073 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7074 for (b = 0; b < fdof; ++b) { 7075 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7076 const PetscInt ind = indperm ? indperm[preind] : preind; 7077 7078 if ((cind < cfdof) && (b == fcdofs[cind])) { 7079 indices[ind] = -(off + foff + b + 1); 7080 ++cind; 7081 } else { 7082 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7083 } 7084 } 7085 } 7086 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7087 foffs[f] += fdof; 7088 } 7089 PetscFunctionReturn(PETSC_SUCCESS); 7090 } 7091 7092 /* 7093 This version believes the globalSection offsets for each field, rather than just the point offset 7094 7095 . foffs - The offset into 'indices' for each field, since it is segregated by field 7096 7097 Notes: 7098 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7099 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7100 */ 7101 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7102 { 7103 PetscInt numFields, foff, f; 7104 7105 PetscFunctionBegin; 7106 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7107 for (f = 0; f < numFields; ++f) { 7108 PetscInt fdof, cfdof; 7109 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7110 PetscInt cind = 0, b; 7111 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7112 7113 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7114 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7115 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7116 if (!cfdof) { 7117 for (b = 0; b < fdof; ++b) { 7118 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7119 const PetscInt ind = indperm ? indperm[preind] : preind; 7120 7121 indices[ind] = foff + b; 7122 } 7123 } else { 7124 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7125 for (b = 0; b < fdof; ++b) { 7126 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7127 const PetscInt ind = indperm ? indperm[preind] : preind; 7128 7129 if ((cind < cfdof) && (b == fcdofs[cind])) { 7130 indices[ind] = -(foff + b + 1); 7131 ++cind; 7132 } else { 7133 indices[ind] = foff + b - cind; 7134 } 7135 } 7136 } 7137 foffs[f] += fdof; 7138 } 7139 PetscFunctionReturn(PETSC_SUCCESS); 7140 } 7141 7142 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) 7143 { 7144 Mat cMat; 7145 PetscSection aSec, cSec; 7146 IS aIS; 7147 PetscInt aStart = -1, aEnd = -1; 7148 const PetscInt *anchors; 7149 PetscInt numFields, f, p, q, newP = 0; 7150 PetscInt newNumPoints = 0, newNumIndices = 0; 7151 PetscInt *newPoints, *indices, *newIndices; 7152 PetscInt maxAnchor, maxDof; 7153 PetscInt newOffsets[32]; 7154 PetscInt *pointMatOffsets[32]; 7155 PetscInt *newPointOffsets[32]; 7156 PetscScalar *pointMat[32]; 7157 PetscScalar *newValues = NULL, *tmpValues; 7158 PetscBool anyConstrained = PETSC_FALSE; 7159 7160 PetscFunctionBegin; 7161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7162 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7163 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7164 7165 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7166 /* if there are point-to-point constraints */ 7167 if (aSec) { 7168 PetscCall(PetscArrayzero(newOffsets, 32)); 7169 PetscCall(ISGetIndices(aIS, &anchors)); 7170 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7171 /* figure out how many points are going to be in the new element matrix 7172 * (we allow double counting, because it's all just going to be summed 7173 * into the global matrix anyway) */ 7174 for (p = 0; p < 2 * numPoints; p += 2) { 7175 PetscInt b = points[p]; 7176 PetscInt bDof = 0, bSecDof; 7177 7178 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7179 if (!bSecDof) continue; 7180 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7181 if (bDof) { 7182 /* this point is constrained */ 7183 /* it is going to be replaced by its anchors */ 7184 PetscInt bOff, q; 7185 7186 anyConstrained = PETSC_TRUE; 7187 newNumPoints += bDof; 7188 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7189 for (q = 0; q < bDof; q++) { 7190 PetscInt a = anchors[bOff + q]; 7191 PetscInt aDof; 7192 7193 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7194 newNumIndices += aDof; 7195 for (f = 0; f < numFields; ++f) { 7196 PetscInt fDof; 7197 7198 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7199 newOffsets[f + 1] += fDof; 7200 } 7201 } 7202 } else { 7203 /* this point is not constrained */ 7204 newNumPoints++; 7205 newNumIndices += bSecDof; 7206 for (f = 0; f < numFields; ++f) { 7207 PetscInt fDof; 7208 7209 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7210 newOffsets[f + 1] += fDof; 7211 } 7212 } 7213 } 7214 } 7215 if (!anyConstrained) { 7216 if (outNumPoints) *outNumPoints = 0; 7217 if (outNumIndices) *outNumIndices = 0; 7218 if (outPoints) *outPoints = NULL; 7219 if (outValues) *outValues = NULL; 7220 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7221 PetscFunctionReturn(PETSC_SUCCESS); 7222 } 7223 7224 if (outNumPoints) *outNumPoints = newNumPoints; 7225 if (outNumIndices) *outNumIndices = newNumIndices; 7226 7227 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7228 7229 if (!outPoints && !outValues) { 7230 if (offsets) { 7231 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7232 } 7233 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7234 PetscFunctionReturn(PETSC_SUCCESS); 7235 } 7236 7237 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7238 7239 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7240 7241 /* workspaces */ 7242 if (numFields) { 7243 for (f = 0; f < numFields; f++) { 7244 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7245 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7246 } 7247 } else { 7248 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7249 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7250 } 7251 7252 /* get workspaces for the point-to-point matrices */ 7253 if (numFields) { 7254 PetscInt totalOffset, totalMatOffset; 7255 7256 for (p = 0; p < numPoints; p++) { 7257 PetscInt b = points[2 * p]; 7258 PetscInt bDof = 0, bSecDof; 7259 7260 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7261 if (!bSecDof) { 7262 for (f = 0; f < numFields; f++) { 7263 newPointOffsets[f][p + 1] = 0; 7264 pointMatOffsets[f][p + 1] = 0; 7265 } 7266 continue; 7267 } 7268 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7269 if (bDof) { 7270 for (f = 0; f < numFields; f++) { 7271 PetscInt fDof, q, bOff, allFDof = 0; 7272 7273 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7274 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7275 for (q = 0; q < bDof; q++) { 7276 PetscInt a = anchors[bOff + q]; 7277 PetscInt aFDof; 7278 7279 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7280 allFDof += aFDof; 7281 } 7282 newPointOffsets[f][p + 1] = allFDof; 7283 pointMatOffsets[f][p + 1] = fDof * allFDof; 7284 } 7285 } else { 7286 for (f = 0; f < numFields; f++) { 7287 PetscInt fDof; 7288 7289 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7290 newPointOffsets[f][p + 1] = fDof; 7291 pointMatOffsets[f][p + 1] = 0; 7292 } 7293 } 7294 } 7295 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7296 newPointOffsets[f][0] = totalOffset; 7297 pointMatOffsets[f][0] = totalMatOffset; 7298 for (p = 0; p < numPoints; p++) { 7299 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7300 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7301 } 7302 totalOffset = newPointOffsets[f][numPoints]; 7303 totalMatOffset = pointMatOffsets[f][numPoints]; 7304 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7305 } 7306 } else { 7307 for (p = 0; p < numPoints; p++) { 7308 PetscInt b = points[2 * p]; 7309 PetscInt bDof = 0, bSecDof; 7310 7311 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7312 if (!bSecDof) { 7313 newPointOffsets[0][p + 1] = 0; 7314 pointMatOffsets[0][p + 1] = 0; 7315 continue; 7316 } 7317 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7318 if (bDof) { 7319 PetscInt bOff, q, allDof = 0; 7320 7321 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7322 for (q = 0; q < bDof; q++) { 7323 PetscInt a = anchors[bOff + q], aDof; 7324 7325 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7326 allDof += aDof; 7327 } 7328 newPointOffsets[0][p + 1] = allDof; 7329 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7330 } else { 7331 newPointOffsets[0][p + 1] = bSecDof; 7332 pointMatOffsets[0][p + 1] = 0; 7333 } 7334 } 7335 newPointOffsets[0][0] = 0; 7336 pointMatOffsets[0][0] = 0; 7337 for (p = 0; p < numPoints; p++) { 7338 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7339 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7340 } 7341 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7342 } 7343 7344 /* output arrays */ 7345 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7346 7347 /* get the point-to-point matrices; construct newPoints */ 7348 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7349 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7350 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7351 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7352 if (numFields) { 7353 for (p = 0, newP = 0; p < numPoints; p++) { 7354 PetscInt b = points[2 * p]; 7355 PetscInt o = points[2 * p + 1]; 7356 PetscInt bDof = 0, bSecDof; 7357 7358 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7359 if (!bSecDof) continue; 7360 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7361 if (bDof) { 7362 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7363 7364 fStart[0] = 0; 7365 fEnd[0] = 0; 7366 for (f = 0; f < numFields; f++) { 7367 PetscInt fDof; 7368 7369 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7370 fStart[f + 1] = fStart[f] + fDof; 7371 fEnd[f + 1] = fStart[f + 1]; 7372 } 7373 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7374 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7375 7376 fAnchorStart[0] = 0; 7377 fAnchorEnd[0] = 0; 7378 for (f = 0; f < numFields; f++) { 7379 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7380 7381 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7382 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7383 } 7384 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7385 for (q = 0; q < bDof; q++) { 7386 PetscInt a = anchors[bOff + q], aOff; 7387 7388 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7389 newPoints[2 * (newP + q)] = a; 7390 newPoints[2 * (newP + q) + 1] = 0; 7391 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7392 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7393 } 7394 newP += bDof; 7395 7396 if (outValues) { 7397 /* get the point-to-point submatrix */ 7398 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])); 7399 } 7400 } else { 7401 newPoints[2 * newP] = b; 7402 newPoints[2 * newP + 1] = o; 7403 newP++; 7404 } 7405 } 7406 } else { 7407 for (p = 0; p < numPoints; p++) { 7408 PetscInt b = points[2 * p]; 7409 PetscInt o = points[2 * p + 1]; 7410 PetscInt bDof = 0, bSecDof; 7411 7412 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7413 if (!bSecDof) continue; 7414 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7415 if (bDof) { 7416 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7417 7418 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7419 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7420 7421 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7422 for (q = 0; q < bDof; q++) { 7423 PetscInt a = anchors[bOff + q], aOff; 7424 7425 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7426 7427 newPoints[2 * (newP + q)] = a; 7428 newPoints[2 * (newP + q) + 1] = 0; 7429 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7430 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7431 } 7432 newP += bDof; 7433 7434 /* get the point-to-point submatrix */ 7435 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7436 } else { 7437 newPoints[2 * newP] = b; 7438 newPoints[2 * newP + 1] = o; 7439 newP++; 7440 } 7441 } 7442 } 7443 7444 if (outValues) { 7445 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7446 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7447 /* multiply constraints on the right */ 7448 if (numFields) { 7449 for (f = 0; f < numFields; f++) { 7450 PetscInt oldOff = offsets[f]; 7451 7452 for (p = 0; p < numPoints; p++) { 7453 PetscInt cStart = newPointOffsets[f][p]; 7454 PetscInt b = points[2 * p]; 7455 PetscInt c, r, k; 7456 PetscInt dof; 7457 7458 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7459 if (!dof) continue; 7460 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7461 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7462 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7463 7464 for (r = 0; r < numIndices; r++) { 7465 for (c = 0; c < nCols; c++) { 7466 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7467 } 7468 } 7469 } else { 7470 /* copy this column as is */ 7471 for (r = 0; r < numIndices; r++) { 7472 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7473 } 7474 } 7475 oldOff += dof; 7476 } 7477 } 7478 } else { 7479 PetscInt oldOff = 0; 7480 for (p = 0; p < numPoints; p++) { 7481 PetscInt cStart = newPointOffsets[0][p]; 7482 PetscInt b = points[2 * p]; 7483 PetscInt c, r, k; 7484 PetscInt dof; 7485 7486 PetscCall(PetscSectionGetDof(section, b, &dof)); 7487 if (!dof) continue; 7488 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7489 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7490 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7491 7492 for (r = 0; r < numIndices; r++) { 7493 for (c = 0; c < nCols; c++) { 7494 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7495 } 7496 } 7497 } else { 7498 /* copy this column as is */ 7499 for (r = 0; r < numIndices; r++) { 7500 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7501 } 7502 } 7503 oldOff += dof; 7504 } 7505 } 7506 7507 if (multiplyLeft) { 7508 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7509 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7510 /* multiply constraints transpose on the left */ 7511 if (numFields) { 7512 for (f = 0; f < numFields; f++) { 7513 PetscInt oldOff = offsets[f]; 7514 7515 for (p = 0; p < numPoints; p++) { 7516 PetscInt rStart = newPointOffsets[f][p]; 7517 PetscInt b = points[2 * p]; 7518 PetscInt c, r, k; 7519 PetscInt dof; 7520 7521 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7522 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7523 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7524 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7525 7526 for (r = 0; r < nRows; r++) { 7527 for (c = 0; c < newNumIndices; c++) { 7528 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7529 } 7530 } 7531 } else { 7532 /* copy this row as is */ 7533 for (r = 0; r < dof; r++) { 7534 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7535 } 7536 } 7537 oldOff += dof; 7538 } 7539 } 7540 } else { 7541 PetscInt oldOff = 0; 7542 7543 for (p = 0; p < numPoints; p++) { 7544 PetscInt rStart = newPointOffsets[0][p]; 7545 PetscInt b = points[2 * p]; 7546 PetscInt c, r, k; 7547 PetscInt dof; 7548 7549 PetscCall(PetscSectionGetDof(section, b, &dof)); 7550 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7551 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7552 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7553 7554 for (r = 0; r < nRows; r++) { 7555 for (c = 0; c < newNumIndices; c++) { 7556 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7557 } 7558 } 7559 } else { 7560 /* copy this row as is */ 7561 for (r = 0; r < dof; r++) { 7562 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7563 } 7564 } 7565 oldOff += dof; 7566 } 7567 } 7568 7569 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7570 } else { 7571 newValues = tmpValues; 7572 } 7573 } 7574 7575 /* clean up */ 7576 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7577 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7578 7579 if (numFields) { 7580 for (f = 0; f < numFields; f++) { 7581 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7582 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7583 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7584 } 7585 } else { 7586 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7587 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7588 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7589 } 7590 PetscCall(ISRestoreIndices(aIS, &anchors)); 7591 7592 /* output */ 7593 if (outPoints) { 7594 *outPoints = newPoints; 7595 } else { 7596 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7597 } 7598 if (outValues) *outValues = newValues; 7599 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7600 PetscFunctionReturn(PETSC_SUCCESS); 7601 } 7602 7603 /*@C 7604 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7605 7606 Not collective 7607 7608 Input Parameters: 7609 + dm - The `DM` 7610 . section - The `PetscSection` describing the points (a local section) 7611 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7612 . point - The point defining the closure 7613 - useClPerm - Use the closure point permutation if available 7614 7615 Output Parameters: 7616 + numIndices - The number of dof indices in the closure of point with the input sections 7617 . indices - The dof indices 7618 . outOffsets - Array to write the field offsets into, or `NULL` 7619 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7620 7621 Level: advanced 7622 7623 Notes: 7624 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7625 7626 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7627 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7628 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7629 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7630 indices (with the above semantics) are implied. 7631 7632 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7633 `PetscSection`, `DMGetGlobalSection()` 7634 @*/ 7635 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7636 { 7637 /* Closure ordering */ 7638 PetscSection clSection; 7639 IS clPoints; 7640 const PetscInt *clp; 7641 PetscInt *points; 7642 const PetscInt *clperm = NULL; 7643 /* Dof permutation and sign flips */ 7644 const PetscInt **perms[32] = {NULL}; 7645 const PetscScalar **flips[32] = {NULL}; 7646 PetscScalar *valCopy = NULL; 7647 /* Hanging node constraints */ 7648 PetscInt *pointsC = NULL; 7649 PetscScalar *valuesC = NULL; 7650 PetscInt NclC, NiC; 7651 7652 PetscInt *idx; 7653 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7654 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7655 7656 PetscFunctionBeginHot; 7657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7658 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7659 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7660 if (numIndices) PetscValidIntPointer(numIndices, 6); 7661 if (indices) PetscValidPointer(indices, 7); 7662 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7663 if (values) PetscValidPointer(values, 9); 7664 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7665 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7666 PetscCall(PetscArrayzero(offsets, 32)); 7667 /* 1) Get points in closure */ 7668 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7669 if (useClPerm) { 7670 PetscInt depth, clsize; 7671 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7672 for (clsize = 0, p = 0; p < Ncl; p++) { 7673 PetscInt dof; 7674 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7675 clsize += dof; 7676 } 7677 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7678 } 7679 /* 2) Get number of indices on these points and field offsets from section */ 7680 for (p = 0; p < Ncl * 2; p += 2) { 7681 PetscInt dof, fdof; 7682 7683 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7684 for (f = 0; f < Nf; ++f) { 7685 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7686 offsets[f + 1] += fdof; 7687 } 7688 Ni += dof; 7689 } 7690 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7691 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7692 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7693 for (f = 0; f < PetscMax(1, Nf); ++f) { 7694 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7695 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7696 /* may need to apply sign changes to the element matrix */ 7697 if (values && flips[f]) { 7698 PetscInt foffset = offsets[f]; 7699 7700 for (p = 0; p < Ncl; ++p) { 7701 PetscInt pnt = points[2 * p], fdof; 7702 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7703 7704 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7705 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7706 if (flip) { 7707 PetscInt i, j, k; 7708 7709 if (!valCopy) { 7710 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7711 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7712 *values = valCopy; 7713 } 7714 for (i = 0; i < fdof; ++i) { 7715 PetscScalar fval = flip[i]; 7716 7717 for (k = 0; k < Ni; ++k) { 7718 valCopy[Ni * (foffset + i) + k] *= fval; 7719 valCopy[Ni * k + (foffset + i)] *= fval; 7720 } 7721 } 7722 } 7723 foffset += fdof; 7724 } 7725 } 7726 } 7727 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7728 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7729 if (NclC) { 7730 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7731 for (f = 0; f < PetscMax(1, Nf); ++f) { 7732 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7733 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7734 } 7735 for (f = 0; f < PetscMax(1, Nf); ++f) { 7736 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7737 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7738 } 7739 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7740 Ncl = NclC; 7741 Ni = NiC; 7742 points = pointsC; 7743 if (values) *values = valuesC; 7744 } 7745 /* 5) Calculate indices */ 7746 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7747 if (Nf) { 7748 PetscInt idxOff; 7749 PetscBool useFieldOffsets; 7750 7751 if (outOffsets) { 7752 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7753 } 7754 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7755 if (useFieldOffsets) { 7756 for (p = 0; p < Ncl; ++p) { 7757 const PetscInt pnt = points[p * 2]; 7758 7759 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7760 } 7761 } else { 7762 for (p = 0; p < Ncl; ++p) { 7763 const PetscInt pnt = points[p * 2]; 7764 7765 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7766 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7767 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7768 * global section. */ 7769 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7770 } 7771 } 7772 } else { 7773 PetscInt off = 0, idxOff; 7774 7775 for (p = 0; p < Ncl; ++p) { 7776 const PetscInt pnt = points[p * 2]; 7777 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7778 7779 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7780 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7781 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7782 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7783 } 7784 } 7785 /* 6) Cleanup */ 7786 for (f = 0; f < PetscMax(1, Nf); ++f) { 7787 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7788 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7789 } 7790 if (NclC) { 7791 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7792 } else { 7793 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7794 } 7795 7796 if (numIndices) *numIndices = Ni; 7797 if (indices) *indices = idx; 7798 PetscFunctionReturn(PETSC_SUCCESS); 7799 } 7800 7801 /*@C 7802 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7803 7804 Not collective 7805 7806 Input Parameters: 7807 + dm - The `DM` 7808 . section - The `PetscSection` describing the points (a local section) 7809 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7810 . point - The point defining the closure 7811 - useClPerm - Use the closure point permutation if available 7812 7813 Output Parameters: 7814 + numIndices - The number of dof indices in the closure of point with the input sections 7815 . indices - The dof indices 7816 . outOffsets - Array to write the field offsets into, or `NULL` 7817 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7818 7819 Level: advanced 7820 7821 Notes: 7822 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7823 7824 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7825 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7826 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7827 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7828 indices (with the above semantics) are implied. 7829 7830 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7831 @*/ 7832 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7833 { 7834 PetscFunctionBegin; 7835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7836 PetscValidPointer(indices, 7); 7837 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7838 PetscFunctionReturn(PETSC_SUCCESS); 7839 } 7840 7841 /*@C 7842 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7843 7844 Not collective 7845 7846 Input Parameters: 7847 + dm - The `DM` 7848 . section - The section describing the layout in `v`, or `NULL` to use the default section 7849 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 7850 . A - The matrix 7851 . point - The point in the `DM` 7852 . values - The array of values 7853 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7854 7855 Level: intermediate 7856 7857 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7858 @*/ 7859 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7860 { 7861 DM_Plex *mesh = (DM_Plex *)dm->data; 7862 PetscInt *indices; 7863 PetscInt numIndices; 7864 const PetscScalar *valuesOrig = values; 7865 PetscErrorCode ierr; 7866 7867 PetscFunctionBegin; 7868 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7869 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7870 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7871 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7872 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7873 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7874 7875 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7876 7877 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7878 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7879 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7880 if (ierr) { 7881 PetscMPIInt rank; 7882 7883 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7884 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7885 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7886 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7887 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7888 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7889 } 7890 if (mesh->printFEM > 1) { 7891 PetscInt i; 7892 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7893 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7894 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7895 } 7896 7897 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7898 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7899 PetscFunctionReturn(PETSC_SUCCESS); 7900 } 7901 7902 /*@C 7903 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7904 7905 Not collective 7906 7907 Input Parameters: 7908 + dmRow - The `DM` for the row fields 7909 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 7910 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 7911 . dmCol - The `DM` for the column fields 7912 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 7913 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 7914 . A - The matrix 7915 . point - The point in the `DM` 7916 . values - The array of values 7917 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7918 7919 Level: intermediate 7920 7921 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7922 @*/ 7923 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7924 { 7925 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7926 PetscInt *indicesRow, *indicesCol; 7927 PetscInt numIndicesRow, numIndicesCol; 7928 const PetscScalar *valuesOrig = values; 7929 PetscErrorCode ierr; 7930 7931 PetscFunctionBegin; 7932 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7933 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7934 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7935 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7936 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7937 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7938 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7939 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7940 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7941 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7942 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7943 7944 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7945 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7946 7947 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7948 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7949 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7950 if (ierr) { 7951 PetscMPIInt rank; 7952 7953 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7954 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7955 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7956 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7957 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7958 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7959 } 7960 7961 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7962 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7963 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7964 PetscFunctionReturn(PETSC_SUCCESS); 7965 } 7966 7967 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7968 { 7969 DM_Plex *mesh = (DM_Plex *)dmf->data; 7970 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7971 PetscInt *cpoints = NULL; 7972 PetscInt *findices, *cindices; 7973 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7974 PetscInt foffsets[32], coffsets[32]; 7975 DMPolytopeType ct; 7976 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7977 PetscErrorCode ierr; 7978 7979 PetscFunctionBegin; 7980 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7981 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7982 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7983 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7984 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7985 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7986 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7987 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7988 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7989 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7990 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7991 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7992 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7993 PetscCall(PetscArrayzero(foffsets, 32)); 7994 PetscCall(PetscArrayzero(coffsets, 32)); 7995 /* Column indices */ 7996 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7997 maxFPoints = numCPoints; 7998 /* Compress out points not in the section */ 7999 /* TODO: Squeeze out points with 0 dof as well */ 8000 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8001 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8002 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8003 cpoints[q * 2] = cpoints[p]; 8004 cpoints[q * 2 + 1] = cpoints[p + 1]; 8005 ++q; 8006 } 8007 } 8008 numCPoints = q; 8009 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8010 PetscInt fdof; 8011 8012 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8013 if (!dof) continue; 8014 for (f = 0; f < numFields; ++f) { 8015 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8016 coffsets[f + 1] += fdof; 8017 } 8018 numCIndices += dof; 8019 } 8020 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8021 /* Row indices */ 8022 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8023 { 8024 DMPlexTransform tr; 8025 DMPolytopeType *rct; 8026 PetscInt *rsize, *rcone, *rornt, Nt; 8027 8028 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8029 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8030 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8031 numSubcells = rsize[Nt - 1]; 8032 PetscCall(DMPlexTransformDestroy(&tr)); 8033 } 8034 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8035 for (r = 0, q = 0; r < numSubcells; ++r) { 8036 /* TODO Map from coarse to fine cells */ 8037 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8038 /* Compress out points not in the section */ 8039 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8040 for (p = 0; p < numFPoints * 2; p += 2) { 8041 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8042 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8043 if (!dof) continue; 8044 for (s = 0; s < q; ++s) 8045 if (fpoints[p] == ftotpoints[s * 2]) break; 8046 if (s < q) continue; 8047 ftotpoints[q * 2] = fpoints[p]; 8048 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8049 ++q; 8050 } 8051 } 8052 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8053 } 8054 numFPoints = q; 8055 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8056 PetscInt fdof; 8057 8058 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8059 if (!dof) continue; 8060 for (f = 0; f < numFields; ++f) { 8061 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8062 foffsets[f + 1] += fdof; 8063 } 8064 numFIndices += dof; 8065 } 8066 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8067 8068 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8069 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8070 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8071 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8072 if (numFields) { 8073 const PetscInt **permsF[32] = {NULL}; 8074 const PetscInt **permsC[32] = {NULL}; 8075 8076 for (f = 0; f < numFields; f++) { 8077 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8078 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8079 } 8080 for (p = 0; p < numFPoints; p++) { 8081 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8082 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8083 } 8084 for (p = 0; p < numCPoints; p++) { 8085 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8086 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8087 } 8088 for (f = 0; f < numFields; f++) { 8089 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8090 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8091 } 8092 } else { 8093 const PetscInt **permsF = NULL; 8094 const PetscInt **permsC = NULL; 8095 8096 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8097 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8098 for (p = 0, off = 0; p < numFPoints; p++) { 8099 const PetscInt *perm = permsF ? permsF[p] : NULL; 8100 8101 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8102 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8103 } 8104 for (p = 0, off = 0; p < numCPoints; p++) { 8105 const PetscInt *perm = permsC ? permsC[p] : NULL; 8106 8107 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8108 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8109 } 8110 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8111 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8112 } 8113 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8114 /* TODO: flips */ 8115 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8116 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8117 if (ierr) { 8118 PetscMPIInt rank; 8119 8120 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8121 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8122 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8123 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8124 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8125 } 8126 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8127 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8128 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8129 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8130 PetscFunctionReturn(PETSC_SUCCESS); 8131 } 8132 8133 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8134 { 8135 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8136 PetscInt *cpoints = NULL; 8137 PetscInt foffsets[32], coffsets[32]; 8138 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8139 DMPolytopeType ct; 8140 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8141 8142 PetscFunctionBegin; 8143 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8144 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8145 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8146 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8147 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8148 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8149 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8150 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8151 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8152 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8153 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8154 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8155 PetscCall(PetscArrayzero(foffsets, 32)); 8156 PetscCall(PetscArrayzero(coffsets, 32)); 8157 /* Column indices */ 8158 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8159 maxFPoints = numCPoints; 8160 /* Compress out points not in the section */ 8161 /* TODO: Squeeze out points with 0 dof as well */ 8162 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8163 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8164 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8165 cpoints[q * 2] = cpoints[p]; 8166 cpoints[q * 2 + 1] = cpoints[p + 1]; 8167 ++q; 8168 } 8169 } 8170 numCPoints = q; 8171 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8172 PetscInt fdof; 8173 8174 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8175 if (!dof) continue; 8176 for (f = 0; f < numFields; ++f) { 8177 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8178 coffsets[f + 1] += fdof; 8179 } 8180 numCIndices += dof; 8181 } 8182 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8183 /* Row indices */ 8184 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8185 { 8186 DMPlexTransform tr; 8187 DMPolytopeType *rct; 8188 PetscInt *rsize, *rcone, *rornt, Nt; 8189 8190 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8191 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8192 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8193 numSubcells = rsize[Nt - 1]; 8194 PetscCall(DMPlexTransformDestroy(&tr)); 8195 } 8196 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8197 for (r = 0, q = 0; r < numSubcells; ++r) { 8198 /* TODO Map from coarse to fine cells */ 8199 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8200 /* Compress out points not in the section */ 8201 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8202 for (p = 0; p < numFPoints * 2; p += 2) { 8203 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8204 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8205 if (!dof) continue; 8206 for (s = 0; s < q; ++s) 8207 if (fpoints[p] == ftotpoints[s * 2]) break; 8208 if (s < q) continue; 8209 ftotpoints[q * 2] = fpoints[p]; 8210 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8211 ++q; 8212 } 8213 } 8214 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8215 } 8216 numFPoints = q; 8217 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8218 PetscInt fdof; 8219 8220 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8221 if (!dof) continue; 8222 for (f = 0; f < numFields; ++f) { 8223 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8224 foffsets[f + 1] += fdof; 8225 } 8226 numFIndices += dof; 8227 } 8228 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8229 8230 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8231 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8232 if (numFields) { 8233 const PetscInt **permsF[32] = {NULL}; 8234 const PetscInt **permsC[32] = {NULL}; 8235 8236 for (f = 0; f < numFields; f++) { 8237 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8238 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8239 } 8240 for (p = 0; p < numFPoints; p++) { 8241 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8242 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8243 } 8244 for (p = 0; p < numCPoints; p++) { 8245 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8246 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8247 } 8248 for (f = 0; f < numFields; f++) { 8249 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8250 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8251 } 8252 } else { 8253 const PetscInt **permsF = NULL; 8254 const PetscInt **permsC = NULL; 8255 8256 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8257 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8258 for (p = 0, off = 0; p < numFPoints; p++) { 8259 const PetscInt *perm = permsF ? permsF[p] : NULL; 8260 8261 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8262 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8263 } 8264 for (p = 0, off = 0; p < numCPoints; p++) { 8265 const PetscInt *perm = permsC ? permsC[p] : NULL; 8266 8267 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8268 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8269 } 8270 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8271 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8272 } 8273 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8274 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8275 PetscFunctionReturn(PETSC_SUCCESS); 8276 } 8277 8278 /*@C 8279 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8280 8281 Input Parameter: 8282 . dm - The `DMPLEX` object 8283 8284 Output Parameter: 8285 . cellHeight - The height of a cell 8286 8287 Level: developer 8288 8289 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8290 @*/ 8291 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8292 { 8293 DM_Plex *mesh = (DM_Plex *)dm->data; 8294 8295 PetscFunctionBegin; 8296 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8297 PetscValidIntPointer(cellHeight, 2); 8298 *cellHeight = mesh->vtkCellHeight; 8299 PetscFunctionReturn(PETSC_SUCCESS); 8300 } 8301 8302 /*@C 8303 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8304 8305 Input Parameters: 8306 + dm - The `DMPLEX` object 8307 - cellHeight - The height of a cell 8308 8309 Level: developer 8310 8311 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8312 @*/ 8313 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8314 { 8315 DM_Plex *mesh = (DM_Plex *)dm->data; 8316 8317 PetscFunctionBegin; 8318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8319 mesh->vtkCellHeight = cellHeight; 8320 PetscFunctionReturn(PETSC_SUCCESS); 8321 } 8322 8323 /*@ 8324 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8325 8326 Input Parameter: 8327 . dm - The `DMPLEX` object 8328 8329 Output Parameters: 8330 + gcStart - The first ghost cell, or `NULL` 8331 - gcEnd - The upper bound on ghost cells, or `NULL` 8332 8333 Level: advanced 8334 8335 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8336 @*/ 8337 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8338 { 8339 DMLabel ctLabel; 8340 8341 PetscFunctionBegin; 8342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8343 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8344 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8345 // Reset label for fast lookup 8346 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8347 PetscFunctionReturn(PETSC_SUCCESS); 8348 } 8349 8350 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8351 { 8352 PetscSection section, globalSection; 8353 PetscInt *numbers, p; 8354 8355 PetscFunctionBegin; 8356 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8357 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8358 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8359 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8360 PetscCall(PetscSectionSetUp(section)); 8361 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8362 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8363 for (p = pStart; p < pEnd; ++p) { 8364 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8365 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8366 else numbers[p - pStart] += shift; 8367 } 8368 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8369 if (globalSize) { 8370 PetscLayout layout; 8371 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8372 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8373 PetscCall(PetscLayoutDestroy(&layout)); 8374 } 8375 PetscCall(PetscSectionDestroy(§ion)); 8376 PetscCall(PetscSectionDestroy(&globalSection)); 8377 PetscFunctionReturn(PETSC_SUCCESS); 8378 } 8379 8380 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8381 { 8382 PetscInt cellHeight, cStart, cEnd; 8383 8384 PetscFunctionBegin; 8385 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8386 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8387 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8388 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8389 PetscFunctionReturn(PETSC_SUCCESS); 8390 } 8391 8392 /*@ 8393 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8394 8395 Input Parameter: 8396 . dm - The `DMPLEX` object 8397 8398 Output Parameter: 8399 . globalCellNumbers - Global cell numbers for all cells on this process 8400 8401 Level: developer 8402 8403 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8404 @*/ 8405 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8406 { 8407 DM_Plex *mesh = (DM_Plex *)dm->data; 8408 8409 PetscFunctionBegin; 8410 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8411 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8412 *globalCellNumbers = mesh->globalCellNumbers; 8413 PetscFunctionReturn(PETSC_SUCCESS); 8414 } 8415 8416 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8417 { 8418 PetscInt vStart, vEnd; 8419 8420 PetscFunctionBegin; 8421 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8422 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8423 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8424 PetscFunctionReturn(PETSC_SUCCESS); 8425 } 8426 8427 /*@ 8428 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8429 8430 Input Parameter: 8431 . dm - The `DMPLEX` object 8432 8433 Output Parameter: 8434 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8435 8436 Level: developer 8437 8438 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8439 @*/ 8440 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8441 { 8442 DM_Plex *mesh = (DM_Plex *)dm->data; 8443 8444 PetscFunctionBegin; 8445 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8446 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8447 *globalVertexNumbers = mesh->globalVertexNumbers; 8448 PetscFunctionReturn(PETSC_SUCCESS); 8449 } 8450 8451 /*@ 8452 DMPlexCreatePointNumbering - Create a global numbering for all points. 8453 8454 Collective 8455 8456 Input Parameter: 8457 . dm - The `DMPLEX` object 8458 8459 Output Parameter: 8460 . globalPointNumbers - Global numbers for all points on this process 8461 8462 Level: developer 8463 8464 Notes: 8465 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8466 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8467 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8468 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8469 8470 The partitioned mesh is 8471 ``` 8472 (2)--0--(3)--1--(4) (1)--0--(2) 8473 ``` 8474 and its global numbering is 8475 ``` 8476 (3)--0--(4)--1--(5)--2--(6) 8477 ``` 8478 Then the global numbering is provided as 8479 ``` 8480 [0] Number of indices in set 5 8481 [0] 0 0 8482 [0] 1 1 8483 [0] 2 3 8484 [0] 3 4 8485 [0] 4 -6 8486 [1] Number of indices in set 3 8487 [1] 0 2 8488 [1] 1 5 8489 [1] 2 6 8490 ``` 8491 8492 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8493 @*/ 8494 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8495 { 8496 IS nums[4]; 8497 PetscInt depths[4], gdepths[4], starts[4]; 8498 PetscInt depth, d, shift = 0; 8499 PetscBool empty = PETSC_FALSE; 8500 8501 PetscFunctionBegin; 8502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8503 PetscCall(DMPlexGetDepth(dm, &depth)); 8504 // For unstratified meshes use dim instead of depth 8505 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8506 // If any stratum is empty, we must mark all empty 8507 for (d = 0; d <= depth; ++d) { 8508 PetscInt end; 8509 8510 depths[d] = depth - d; 8511 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8512 if (!(starts[d] - end)) empty = PETSC_TRUE; 8513 } 8514 if (empty) 8515 for (d = 0; d <= depth; ++d) { 8516 depths[d] = -1; 8517 starts[d] = -1; 8518 } 8519 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8520 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8521 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]); 8522 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8523 for (d = 0; d <= depth; ++d) { 8524 PetscInt pStart, pEnd, gsize; 8525 8526 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8527 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8528 shift += gsize; 8529 } 8530 PetscCall(ISConcatenate(PETSC_COMM_SELF, depth + 1, nums, globalPointNumbers)); 8531 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8532 PetscFunctionReturn(PETSC_SUCCESS); 8533 } 8534 8535 /*@ 8536 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8537 8538 Input Parameter: 8539 . dm - The `DMPLEX` object 8540 8541 Output Parameter: 8542 . ranks - The rank field 8543 8544 Options Database Key: 8545 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8546 8547 Level: intermediate 8548 8549 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8550 @*/ 8551 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8552 { 8553 DM rdm; 8554 PetscFE fe; 8555 PetscScalar *r; 8556 PetscMPIInt rank; 8557 DMPolytopeType ct; 8558 PetscInt dim, cStart, cEnd, c; 8559 PetscBool simplex; 8560 8561 PetscFunctionBeginUser; 8562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8563 PetscValidPointer(ranks, 2); 8564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8565 PetscCall(DMClone(dm, &rdm)); 8566 PetscCall(DMGetDimension(rdm, &dim)); 8567 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8568 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8569 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8570 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8571 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8572 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8573 PetscCall(PetscFEDestroy(&fe)); 8574 PetscCall(DMCreateDS(rdm)); 8575 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8576 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8577 PetscCall(VecGetArray(*ranks, &r)); 8578 for (c = cStart; c < cEnd; ++c) { 8579 PetscScalar *lr; 8580 8581 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8582 if (lr) *lr = rank; 8583 } 8584 PetscCall(VecRestoreArray(*ranks, &r)); 8585 PetscCall(DMDestroy(&rdm)); 8586 PetscFunctionReturn(PETSC_SUCCESS); 8587 } 8588 8589 /*@ 8590 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8591 8592 Input Parameters: 8593 + dm - The `DMPLEX` 8594 - label - The `DMLabel` 8595 8596 Output Parameter: 8597 . val - The label value field 8598 8599 Options Database Key: 8600 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8601 8602 Level: intermediate 8603 8604 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8605 @*/ 8606 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8607 { 8608 DM rdm; 8609 PetscFE fe; 8610 PetscScalar *v; 8611 PetscInt dim, cStart, cEnd, c; 8612 8613 PetscFunctionBeginUser; 8614 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8615 PetscValidPointer(label, 2); 8616 PetscValidPointer(val, 3); 8617 PetscCall(DMClone(dm, &rdm)); 8618 PetscCall(DMGetDimension(rdm, &dim)); 8619 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8620 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8621 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8622 PetscCall(PetscFEDestroy(&fe)); 8623 PetscCall(DMCreateDS(rdm)); 8624 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8625 PetscCall(DMCreateGlobalVector(rdm, val)); 8626 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8627 PetscCall(VecGetArray(*val, &v)); 8628 for (c = cStart; c < cEnd; ++c) { 8629 PetscScalar *lv; 8630 PetscInt cval; 8631 8632 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8633 PetscCall(DMLabelGetValue(label, c, &cval)); 8634 *lv = cval; 8635 } 8636 PetscCall(VecRestoreArray(*val, &v)); 8637 PetscCall(DMDestroy(&rdm)); 8638 PetscFunctionReturn(PETSC_SUCCESS); 8639 } 8640 8641 /*@ 8642 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8643 8644 Input Parameter: 8645 . dm - The `DMPLEX` object 8646 8647 Level: developer 8648 8649 Notes: 8650 This is a useful diagnostic when creating meshes programmatically. 8651 8652 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8653 8654 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8655 @*/ 8656 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8657 { 8658 PetscSection coneSection, supportSection; 8659 const PetscInt *cone, *support; 8660 PetscInt coneSize, c, supportSize, s; 8661 PetscInt pStart, pEnd, p, pp, csize, ssize; 8662 PetscBool storagecheck = PETSC_TRUE; 8663 8664 PetscFunctionBegin; 8665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8666 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8667 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8668 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8669 /* Check that point p is found in the support of its cone points, and vice versa */ 8670 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8671 for (p = pStart; p < pEnd; ++p) { 8672 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8673 PetscCall(DMPlexGetCone(dm, p, &cone)); 8674 for (c = 0; c < coneSize; ++c) { 8675 PetscBool dup = PETSC_FALSE; 8676 PetscInt d; 8677 for (d = c - 1; d >= 0; --d) { 8678 if (cone[c] == cone[d]) { 8679 dup = PETSC_TRUE; 8680 break; 8681 } 8682 } 8683 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8684 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8685 for (s = 0; s < supportSize; ++s) { 8686 if (support[s] == p) break; 8687 } 8688 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8689 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8690 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8691 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8692 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8693 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8694 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8695 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]); 8696 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8697 } 8698 } 8699 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8700 if (p != pp) { 8701 storagecheck = PETSC_FALSE; 8702 continue; 8703 } 8704 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8705 PetscCall(DMPlexGetSupport(dm, p, &support)); 8706 for (s = 0; s < supportSize; ++s) { 8707 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8708 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8709 for (c = 0; c < coneSize; ++c) { 8710 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8711 if (cone[c] != pp) { 8712 c = 0; 8713 break; 8714 } 8715 if (cone[c] == p) break; 8716 } 8717 if (c >= coneSize) { 8718 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8719 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8720 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8721 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8722 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8723 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8724 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8725 } 8726 } 8727 } 8728 if (storagecheck) { 8729 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8730 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8731 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8732 } 8733 PetscFunctionReturn(PETSC_SUCCESS); 8734 } 8735 8736 /* 8737 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. 8738 */ 8739 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8740 { 8741 DMPolytopeType cct; 8742 PetscInt ptpoints[4]; 8743 const PetscInt *cone, *ccone, *ptcone; 8744 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8745 8746 PetscFunctionBegin; 8747 *unsplit = 0; 8748 switch (ct) { 8749 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8750 ptpoints[npt++] = c; 8751 break; 8752 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8753 PetscCall(DMPlexGetCone(dm, c, &cone)); 8754 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8755 for (cp = 0; cp < coneSize; ++cp) { 8756 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8757 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8758 } 8759 break; 8760 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8761 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8762 PetscCall(DMPlexGetCone(dm, c, &cone)); 8763 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8764 for (cp = 0; cp < coneSize; ++cp) { 8765 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8766 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8767 for (ccp = 0; ccp < cconeSize; ++ccp) { 8768 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8769 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8770 PetscInt p; 8771 for (p = 0; p < npt; ++p) 8772 if (ptpoints[p] == ccone[ccp]) break; 8773 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8774 } 8775 } 8776 } 8777 break; 8778 default: 8779 break; 8780 } 8781 for (pt = 0; pt < npt; ++pt) { 8782 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8783 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8784 } 8785 PetscFunctionReturn(PETSC_SUCCESS); 8786 } 8787 8788 /*@ 8789 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8790 8791 Input Parameters: 8792 + dm - The `DMPLEX` object 8793 - cellHeight - Normally 0 8794 8795 Level: developer 8796 8797 Notes: 8798 This is a useful diagnostic when creating meshes programmatically. 8799 Currently applicable only to homogeneous simplex or tensor meshes. 8800 8801 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8802 8803 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8804 @*/ 8805 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8806 { 8807 DMPlexInterpolatedFlag interp; 8808 DMPolytopeType ct; 8809 PetscInt vStart, vEnd, cStart, cEnd, c; 8810 8811 PetscFunctionBegin; 8812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8813 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8814 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8815 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8816 for (c = cStart; c < cEnd; ++c) { 8817 PetscInt *closure = NULL; 8818 PetscInt coneSize, closureSize, cl, Nv = 0; 8819 8820 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8821 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8822 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8823 if (interp == DMPLEX_INTERPOLATED_FULL) { 8824 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8825 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)); 8826 } 8827 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8828 for (cl = 0; cl < closureSize * 2; cl += 2) { 8829 const PetscInt p = closure[cl]; 8830 if ((p >= vStart) && (p < vEnd)) ++Nv; 8831 } 8832 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8833 /* Special Case: Tensor faces with identified vertices */ 8834 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8835 PetscInt unsplit; 8836 8837 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8838 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8839 } 8840 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)); 8841 } 8842 PetscFunctionReturn(PETSC_SUCCESS); 8843 } 8844 8845 /*@ 8846 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8847 8848 Collective 8849 8850 Input Parameters: 8851 + dm - The `DMPLEX` object 8852 - cellHeight - Normally 0 8853 8854 Level: developer 8855 8856 Notes: 8857 This is a useful diagnostic when creating meshes programmatically. 8858 This routine is only relevant for meshes that are fully interpolated across all ranks. 8859 It will error out if a partially interpolated mesh is given on some rank. 8860 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8861 8862 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8863 8864 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8865 @*/ 8866 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8867 { 8868 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8869 DMPlexInterpolatedFlag interpEnum; 8870 8871 PetscFunctionBegin; 8872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8873 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8874 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8875 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8876 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8877 PetscFunctionReturn(PETSC_SUCCESS); 8878 } 8879 8880 PetscCall(DMGetDimension(dm, &dim)); 8881 PetscCall(DMPlexGetDepth(dm, &depth)); 8882 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8883 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8884 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8885 for (c = cStart; c < cEnd; ++c) { 8886 const PetscInt *cone, *ornt, *faceSizes, *faces; 8887 const DMPolytopeType *faceTypes; 8888 DMPolytopeType ct; 8889 PetscInt numFaces, coneSize, f; 8890 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8891 8892 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8893 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8894 if (unsplit) continue; 8895 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8896 PetscCall(DMPlexGetCone(dm, c, &cone)); 8897 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8898 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8899 for (cl = 0; cl < closureSize * 2; cl += 2) { 8900 const PetscInt p = closure[cl]; 8901 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8902 } 8903 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8904 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); 8905 for (f = 0; f < numFaces; ++f) { 8906 DMPolytopeType fct; 8907 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8908 8909 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8910 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8911 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8912 const PetscInt p = fclosure[cl]; 8913 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8914 } 8915 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]); 8916 for (v = 0; v < fnumCorners; ++v) { 8917 if (fclosure[v] != faces[fOff + v]) { 8918 PetscInt v1; 8919 8920 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8921 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8922 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8923 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8924 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8925 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]); 8926 } 8927 } 8928 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8929 fOff += faceSizes[f]; 8930 } 8931 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8932 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8933 } 8934 } 8935 PetscFunctionReturn(PETSC_SUCCESS); 8936 } 8937 8938 /*@ 8939 DMPlexCheckGeometry - Check the geometry of mesh cells 8940 8941 Input Parameter: 8942 . dm - The `DMPLEX` object 8943 8944 Level: developer 8945 8946 Notes: 8947 This is a useful diagnostic when creating meshes programmatically. 8948 8949 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8950 8951 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8952 @*/ 8953 PetscErrorCode DMPlexCheckGeometry(DM dm) 8954 { 8955 Vec coordinates; 8956 PetscReal detJ, J[9], refVol = 1.0; 8957 PetscReal vol; 8958 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8959 8960 PetscFunctionBegin; 8961 PetscCall(DMGetDimension(dm, &dim)); 8962 PetscCall(DMGetCoordinateDim(dm, &dE)); 8963 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 8964 PetscCall(DMPlexGetDepth(dm, &depth)); 8965 for (d = 0; d < dim; ++d) refVol *= 2.0; 8966 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8967 /* Make sure local coordinates are created, because that step is collective */ 8968 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8969 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 8970 for (c = cStart; c < cEnd; ++c) { 8971 DMPolytopeType ct; 8972 PetscInt unsplit; 8973 PetscBool ignoreZeroVol = PETSC_FALSE; 8974 8975 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8976 switch (ct) { 8977 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8978 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8979 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8980 ignoreZeroVol = PETSC_TRUE; 8981 break; 8982 default: 8983 break; 8984 } 8985 switch (ct) { 8986 case DM_POLYTOPE_TRI_PRISM: 8987 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8988 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8989 case DM_POLYTOPE_PYRAMID: 8990 continue; 8991 default: 8992 break; 8993 } 8994 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8995 if (unsplit) continue; 8996 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8997 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); 8998 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8999 /* This should work with periodicity since DG coordinates should be used */ 9000 if (depth > 1) { 9001 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 9002 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); 9003 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 9004 } 9005 } 9006 PetscFunctionReturn(PETSC_SUCCESS); 9007 } 9008 9009 /*@ 9010 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 9011 9012 Collective 9013 9014 Input Parameters: 9015 + dm - The `DMPLEX` object 9016 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 9017 - allowExtraRoots - Flag to allow extra points not present in the `DM` 9018 9019 Level: developer 9020 9021 Notes: 9022 This is mainly intended for debugging/testing purposes. 9023 9024 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9025 9026 Extra roots can come from priodic cuts, where additional points appear on the boundary 9027 9028 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 9029 @*/ 9030 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 9031 { 9032 PetscInt l, nleaves, nroots, overlap; 9033 const PetscInt *locals; 9034 const PetscSFNode *remotes; 9035 PetscBool distributed; 9036 MPI_Comm comm; 9037 PetscMPIInt rank; 9038 9039 PetscFunctionBegin; 9040 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9041 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9042 else pointSF = dm->sf; 9043 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9044 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9045 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9046 { 9047 PetscMPIInt mpiFlag; 9048 9049 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9050 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9051 } 9052 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9053 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9054 if (!distributed) { 9055 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); 9056 PetscFunctionReturn(PETSC_SUCCESS); 9057 } 9058 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); 9059 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9060 9061 /* Check SF graph is compatible with DMPlex chart */ 9062 { 9063 PetscInt pStart, pEnd, maxLeaf; 9064 9065 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9066 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9067 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9068 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9069 } 9070 9071 /* Check Point SF has no local points referenced */ 9072 for (l = 0; l < nleaves; l++) { 9073 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); 9074 } 9075 9076 /* Check there are no cells in interface */ 9077 if (!overlap) { 9078 PetscInt cellHeight, cStart, cEnd; 9079 9080 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9081 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9082 for (l = 0; l < nleaves; ++l) { 9083 const PetscInt point = locals ? locals[l] : l; 9084 9085 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9086 } 9087 } 9088 9089 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9090 { 9091 const PetscInt *rootdegree; 9092 9093 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9094 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9095 for (l = 0; l < nleaves; ++l) { 9096 const PetscInt point = locals ? locals[l] : l; 9097 const PetscInt *cone; 9098 PetscInt coneSize, c, idx; 9099 9100 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9101 PetscCall(DMPlexGetCone(dm, point, &cone)); 9102 for (c = 0; c < coneSize; ++c) { 9103 if (!rootdegree[cone[c]]) { 9104 if (locals) { 9105 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9106 } else { 9107 idx = (cone[c] < nleaves) ? cone[c] : -1; 9108 } 9109 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9110 } 9111 } 9112 } 9113 } 9114 PetscFunctionReturn(PETSC_SUCCESS); 9115 } 9116 9117 /*@ 9118 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9119 9120 Input Parameter: 9121 . dm - The `DMPLEX` object 9122 9123 Level: developer 9124 9125 Notes: 9126 This is a useful diagnostic when creating meshes programmatically. 9127 9128 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9129 9130 Currently does not include `DMPlexCheckCellShape()`. 9131 9132 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9133 @*/ 9134 PetscErrorCode DMPlexCheck(DM dm) 9135 { 9136 PetscInt cellHeight; 9137 9138 PetscFunctionBegin; 9139 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9140 PetscCall(DMPlexCheckSymmetry(dm)); 9141 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9142 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9143 PetscCall(DMPlexCheckGeometry(dm)); 9144 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9145 PetscCall(DMPlexCheckInterfaceCones(dm)); 9146 PetscFunctionReturn(PETSC_SUCCESS); 9147 } 9148 9149 typedef struct cell_stats { 9150 PetscReal min, max, sum, squaresum; 9151 PetscInt count; 9152 } cell_stats_t; 9153 9154 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9155 { 9156 PetscInt i, N = *len; 9157 9158 for (i = 0; i < N; i++) { 9159 cell_stats_t *A = (cell_stats_t *)a; 9160 cell_stats_t *B = (cell_stats_t *)b; 9161 9162 B->min = PetscMin(A->min, B->min); 9163 B->max = PetscMax(A->max, B->max); 9164 B->sum += A->sum; 9165 B->squaresum += A->squaresum; 9166 B->count += A->count; 9167 } 9168 } 9169 9170 /*@ 9171 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9172 9173 Collective 9174 9175 Input Parameters: 9176 + dm - The `DMPLEX` object 9177 . output - If true, statistics will be displayed on `stdout` 9178 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9179 9180 Level: developer 9181 9182 Notes: 9183 This is mainly intended for debugging/testing purposes. 9184 9185 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9186 9187 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9188 @*/ 9189 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9190 { 9191 DM dmCoarse; 9192 cell_stats_t stats, globalStats; 9193 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9194 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9195 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9196 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9197 PetscMPIInt rank, size; 9198 9199 PetscFunctionBegin; 9200 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9201 stats.min = PETSC_MAX_REAL; 9202 stats.max = PETSC_MIN_REAL; 9203 stats.sum = stats.squaresum = 0.; 9204 stats.count = 0; 9205 9206 PetscCallMPI(MPI_Comm_size(comm, &size)); 9207 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9208 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9209 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9210 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9211 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9212 for (c = cStart; c < cEnd; c++) { 9213 PetscInt i; 9214 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9215 9216 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9217 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9218 for (i = 0; i < PetscSqr(cdim); ++i) { 9219 frobJ += J[i] * J[i]; 9220 frobInvJ += invJ[i] * invJ[i]; 9221 } 9222 cond2 = frobJ * frobInvJ; 9223 cond = PetscSqrtReal(cond2); 9224 9225 stats.min = PetscMin(stats.min, cond); 9226 stats.max = PetscMax(stats.max, cond); 9227 stats.sum += cond; 9228 stats.squaresum += cond2; 9229 stats.count++; 9230 if (output && cond > limit) { 9231 PetscSection coordSection; 9232 Vec coordsLocal; 9233 PetscScalar *coords = NULL; 9234 PetscInt Nv, d, clSize, cl, *closure = NULL; 9235 9236 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9237 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9238 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9239 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9240 for (i = 0; i < Nv / cdim; ++i) { 9241 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9242 for (d = 0; d < cdim; ++d) { 9243 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9244 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9245 } 9246 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9247 } 9248 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9249 for (cl = 0; cl < clSize * 2; cl += 2) { 9250 const PetscInt edge = closure[cl]; 9251 9252 if ((edge >= eStart) && (edge < eEnd)) { 9253 PetscReal len; 9254 9255 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9256 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9257 } 9258 } 9259 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9260 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9261 } 9262 } 9263 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9264 9265 if (size > 1) { 9266 PetscMPIInt blockLengths[2] = {4, 1}; 9267 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9268 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9269 MPI_Op statReduce; 9270 9271 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9272 PetscCallMPI(MPI_Type_commit(&statType)); 9273 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9274 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9275 PetscCallMPI(MPI_Op_free(&statReduce)); 9276 PetscCallMPI(MPI_Type_free(&statType)); 9277 } else { 9278 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9279 } 9280 if (rank == 0) { 9281 count = globalStats.count; 9282 min = globalStats.min; 9283 max = globalStats.max; 9284 mean = globalStats.sum / globalStats.count; 9285 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9286 } 9287 9288 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)); 9289 PetscCall(PetscFree2(J, invJ)); 9290 9291 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9292 if (dmCoarse) { 9293 PetscBool isplex; 9294 9295 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9296 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9297 } 9298 PetscFunctionReturn(PETSC_SUCCESS); 9299 } 9300 9301 /*@ 9302 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9303 orthogonal quality below given tolerance. 9304 9305 Collective 9306 9307 Input Parameters: 9308 + dm - The `DMPLEX` object 9309 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9310 - atol - [0, 1] Absolute tolerance for tagging cells. 9311 9312 Output Parameters: 9313 + OrthQual - `Vec` containing orthogonal quality per cell 9314 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9315 9316 Options Database Keys: 9317 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9318 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9319 9320 Level: intermediate 9321 9322 Notes: 9323 Orthogonal quality is given by the following formula: 9324 9325 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9326 9327 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 9328 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9329 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9330 calculating the cosine of the angle between these vectors. 9331 9332 Orthogonal quality ranges from 1 (best) to 0 (worst). 9333 9334 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9335 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9336 9337 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9338 9339 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9340 @*/ 9341 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9342 { 9343 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9344 PetscInt *idx; 9345 PetscScalar *oqVals; 9346 const PetscScalar *cellGeomArr, *faceGeomArr; 9347 PetscReal *ci, *fi, *Ai; 9348 MPI_Comm comm; 9349 Vec cellgeom, facegeom; 9350 DM dmFace, dmCell; 9351 IS glob; 9352 ISLocalToGlobalMapping ltog; 9353 PetscViewer vwr; 9354 9355 PetscFunctionBegin; 9356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9357 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9358 PetscValidPointer(OrthQual, 4); 9359 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9360 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9361 PetscCall(DMGetDimension(dm, &nc)); 9362 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9363 { 9364 DMPlexInterpolatedFlag interpFlag; 9365 9366 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9367 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9368 PetscMPIInt rank; 9369 9370 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9371 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9372 } 9373 } 9374 if (OrthQualLabel) { 9375 PetscValidPointer(OrthQualLabel, 5); 9376 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9377 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9378 } else { 9379 *OrthQualLabel = NULL; 9380 } 9381 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9382 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9383 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9384 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9385 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9386 PetscCall(VecCreate(comm, OrthQual)); 9387 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9388 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9389 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9390 PetscCall(VecSetUp(*OrthQual)); 9391 PetscCall(ISDestroy(&glob)); 9392 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9393 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9394 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9395 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9396 PetscCall(VecGetDM(cellgeom, &dmCell)); 9397 PetscCall(VecGetDM(facegeom, &dmFace)); 9398 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9399 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9400 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9401 PetscInt cellarr[2], *adj = NULL; 9402 PetscScalar *cArr, *fArr; 9403 PetscReal minvalc = 1.0, minvalf = 1.0; 9404 PetscFVCellGeom *cg; 9405 9406 idx[cellIter] = cell - cStart; 9407 cellarr[0] = cell; 9408 /* Make indexing into cellGeom easier */ 9409 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9410 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9411 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9412 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9413 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9414 PetscInt i; 9415 const PetscInt neigh = adj[cellneigh]; 9416 PetscReal normci = 0, normfi = 0, normai = 0; 9417 PetscFVCellGeom *cgneigh; 9418 PetscFVFaceGeom *fg; 9419 9420 /* Don't count ourselves in the neighbor list */ 9421 if (neigh == cell) continue; 9422 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9423 cellarr[1] = neigh; 9424 { 9425 PetscInt numcovpts; 9426 const PetscInt *covpts; 9427 9428 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9429 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9430 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9431 } 9432 9433 /* Compute c_i, f_i and their norms */ 9434 for (i = 0; i < nc; i++) { 9435 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9436 fi[i] = fg->centroid[i] - cg->centroid[i]; 9437 Ai[i] = fg->normal[i]; 9438 normci += PetscPowReal(ci[i], 2); 9439 normfi += PetscPowReal(fi[i], 2); 9440 normai += PetscPowReal(Ai[i], 2); 9441 } 9442 normci = PetscSqrtReal(normci); 9443 normfi = PetscSqrtReal(normfi); 9444 normai = PetscSqrtReal(normai); 9445 9446 /* Normalize and compute for each face-cell-normal pair */ 9447 for (i = 0; i < nc; i++) { 9448 ci[i] = ci[i] / normci; 9449 fi[i] = fi[i] / normfi; 9450 Ai[i] = Ai[i] / normai; 9451 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9452 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9453 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9454 } 9455 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9456 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9457 } 9458 PetscCall(PetscFree(adj)); 9459 PetscCall(PetscFree2(cArr, fArr)); 9460 /* Defer to cell if they're equal */ 9461 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9462 if (OrthQualLabel) { 9463 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9464 } 9465 } 9466 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9467 PetscCall(VecAssemblyBegin(*OrthQual)); 9468 PetscCall(VecAssemblyEnd(*OrthQual)); 9469 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9470 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9471 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9472 if (OrthQualLabel) { 9473 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9474 } 9475 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9476 PetscCall(PetscViewerDestroy(&vwr)); 9477 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9478 PetscFunctionReturn(PETSC_SUCCESS); 9479 } 9480 9481 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9482 * interpolator construction */ 9483 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9484 { 9485 PetscSection section, newSection, gsection; 9486 PetscSF sf; 9487 PetscBool hasConstraints, ghasConstraints; 9488 9489 PetscFunctionBegin; 9490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9491 PetscValidPointer(odm, 2); 9492 PetscCall(DMGetLocalSection(dm, §ion)); 9493 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9494 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9495 if (!ghasConstraints) { 9496 PetscCall(PetscObjectReference((PetscObject)dm)); 9497 *odm = dm; 9498 PetscFunctionReturn(PETSC_SUCCESS); 9499 } 9500 PetscCall(DMClone(dm, odm)); 9501 PetscCall(DMCopyFields(dm, *odm)); 9502 PetscCall(DMGetLocalSection(*odm, &newSection)); 9503 PetscCall(DMGetPointSF(*odm, &sf)); 9504 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9505 PetscCall(DMSetGlobalSection(*odm, gsection)); 9506 PetscCall(PetscSectionDestroy(&gsection)); 9507 PetscFunctionReturn(PETSC_SUCCESS); 9508 } 9509 9510 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9511 { 9512 DM dmco, dmfo; 9513 Mat interpo; 9514 Vec rscale; 9515 Vec cglobalo, clocal; 9516 Vec fglobal, fglobalo, flocal; 9517 PetscBool regular; 9518 9519 PetscFunctionBegin; 9520 PetscCall(DMGetFullDM(dmc, &dmco)); 9521 PetscCall(DMGetFullDM(dmf, &dmfo)); 9522 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9523 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9524 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9525 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9526 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9527 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9528 PetscCall(VecSet(cglobalo, 0.)); 9529 PetscCall(VecSet(clocal, 0.)); 9530 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9531 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9532 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9533 PetscCall(VecSet(fglobal, 0.)); 9534 PetscCall(VecSet(fglobalo, 0.)); 9535 PetscCall(VecSet(flocal, 0.)); 9536 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9537 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9538 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9539 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9540 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9541 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9542 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9543 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9544 *shift = fglobal; 9545 PetscCall(VecDestroy(&flocal)); 9546 PetscCall(VecDestroy(&fglobalo)); 9547 PetscCall(VecDestroy(&clocal)); 9548 PetscCall(VecDestroy(&cglobalo)); 9549 PetscCall(VecDestroy(&rscale)); 9550 PetscCall(MatDestroy(&interpo)); 9551 PetscCall(DMDestroy(&dmfo)); 9552 PetscCall(DMDestroy(&dmco)); 9553 PetscFunctionReturn(PETSC_SUCCESS); 9554 } 9555 9556 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9557 { 9558 PetscObject shifto; 9559 Vec shift; 9560 9561 PetscFunctionBegin; 9562 if (!interp) { 9563 Vec rscale; 9564 9565 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9566 PetscCall(VecDestroy(&rscale)); 9567 } else { 9568 PetscCall(PetscObjectReference((PetscObject)interp)); 9569 } 9570 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9571 if (!shifto) { 9572 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9573 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9574 shifto = (PetscObject)shift; 9575 PetscCall(VecDestroy(&shift)); 9576 } 9577 shift = (Vec)shifto; 9578 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9579 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9580 PetscCall(MatDestroy(&interp)); 9581 PetscFunctionReturn(PETSC_SUCCESS); 9582 } 9583 9584 /* Pointwise interpolation 9585 Just code FEM for now 9586 u^f = I u^c 9587 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9588 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9589 I_{ij} = psi^f_i phi^c_j 9590 */ 9591 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9592 { 9593 PetscSection gsc, gsf; 9594 PetscInt m, n; 9595 void *ctx; 9596 DM cdm; 9597 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9598 9599 PetscFunctionBegin; 9600 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9601 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9602 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9603 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9604 9605 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9606 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9607 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9608 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9609 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9610 9611 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9612 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9613 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9614 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9615 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9616 if (scaling) { 9617 /* Use naive scaling */ 9618 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9619 } 9620 PetscFunctionReturn(PETSC_SUCCESS); 9621 } 9622 9623 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9624 { 9625 VecScatter ctx; 9626 9627 PetscFunctionBegin; 9628 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9629 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9630 PetscCall(VecScatterDestroy(&ctx)); 9631 PetscFunctionReturn(PETSC_SUCCESS); 9632 } 9633 9634 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[]) 9635 { 9636 const PetscInt Nc = uOff[1] - uOff[0]; 9637 PetscInt c; 9638 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9639 } 9640 9641 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9642 { 9643 DM dmc; 9644 PetscDS ds; 9645 Vec ones, locmass; 9646 IS cellIS; 9647 PetscFormKey key; 9648 PetscInt depth; 9649 9650 PetscFunctionBegin; 9651 PetscCall(DMClone(dm, &dmc)); 9652 PetscCall(DMCopyDisc(dm, dmc)); 9653 PetscCall(DMGetDS(dmc, &ds)); 9654 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9655 PetscCall(DMCreateGlobalVector(dmc, mass)); 9656 PetscCall(DMGetLocalVector(dmc, &ones)); 9657 PetscCall(DMGetLocalVector(dmc, &locmass)); 9658 PetscCall(DMPlexGetDepth(dmc, &depth)); 9659 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9660 PetscCall(VecSet(locmass, 0.0)); 9661 PetscCall(VecSet(ones, 1.0)); 9662 key.label = NULL; 9663 key.value = 0; 9664 key.field = 0; 9665 key.part = 0; 9666 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9667 PetscCall(ISDestroy(&cellIS)); 9668 PetscCall(VecSet(*mass, 0.0)); 9669 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9670 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9671 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9672 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9673 PetscCall(DMDestroy(&dmc)); 9674 PetscFunctionReturn(PETSC_SUCCESS); 9675 } 9676 9677 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9678 { 9679 PetscSection gsc, gsf; 9680 PetscInt m, n; 9681 void *ctx; 9682 DM cdm; 9683 PetscBool regular; 9684 9685 PetscFunctionBegin; 9686 if (dmFine == dmCoarse) { 9687 DM dmc; 9688 PetscDS ds; 9689 PetscWeakForm wf; 9690 Vec u; 9691 IS cellIS; 9692 PetscFormKey key; 9693 PetscInt depth; 9694 9695 PetscCall(DMClone(dmFine, &dmc)); 9696 PetscCall(DMCopyDisc(dmFine, dmc)); 9697 PetscCall(DMGetDS(dmc, &ds)); 9698 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9699 PetscCall(PetscWeakFormClear(wf)); 9700 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9701 PetscCall(DMCreateMatrix(dmc, mass)); 9702 PetscCall(DMGetLocalVector(dmc, &u)); 9703 PetscCall(DMPlexGetDepth(dmc, &depth)); 9704 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9705 PetscCall(MatZeroEntries(*mass)); 9706 key.label = NULL; 9707 key.value = 0; 9708 key.field = 0; 9709 key.part = 0; 9710 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9711 PetscCall(ISDestroy(&cellIS)); 9712 PetscCall(DMRestoreLocalVector(dmc, &u)); 9713 PetscCall(DMDestroy(&dmc)); 9714 } else { 9715 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9716 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9717 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9718 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9719 9720 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9721 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9722 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9723 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9724 9725 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9726 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9727 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9728 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9729 } 9730 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9731 PetscFunctionReturn(PETSC_SUCCESS); 9732 } 9733 9734 /*@ 9735 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9736 9737 Input Parameter: 9738 . dm - The `DMPLEX` object 9739 9740 Output Parameter: 9741 . regular - The flag 9742 9743 Level: intermediate 9744 9745 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9746 @*/ 9747 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9748 { 9749 PetscFunctionBegin; 9750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9751 PetscValidBoolPointer(regular, 2); 9752 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9753 PetscFunctionReturn(PETSC_SUCCESS); 9754 } 9755 9756 /*@ 9757 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9758 9759 Input Parameters: 9760 + dm - The `DMPLEX` object 9761 - regular - The flag 9762 9763 Level: intermediate 9764 9765 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9766 @*/ 9767 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9768 { 9769 PetscFunctionBegin; 9770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9771 ((DM_Plex *)dm->data)->regularRefinement = regular; 9772 PetscFunctionReturn(PETSC_SUCCESS); 9773 } 9774 9775 /*@ 9776 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9777 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9778 9779 Not Collective 9780 9781 Input Parameter: 9782 . dm - The `DMPLEX` object 9783 9784 Output Parameters: 9785 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9786 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9787 9788 Level: intermediate 9789 9790 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9791 @*/ 9792 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9793 { 9794 DM_Plex *plex = (DM_Plex *)dm->data; 9795 9796 PetscFunctionBegin; 9797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9798 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9799 if (anchorSection) *anchorSection = plex->anchorSection; 9800 if (anchorIS) *anchorIS = plex->anchorIS; 9801 PetscFunctionReturn(PETSC_SUCCESS); 9802 } 9803 9804 /*@ 9805 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9806 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9807 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9808 9809 Collective 9810 9811 Input Parameters: 9812 + dm - The `DMPLEX` object 9813 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9814 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9815 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9816 9817 Level: intermediate 9818 9819 Notes: 9820 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9821 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9822 9823 The reference counts of `anchorSection` and `anchorIS` are incremented. 9824 9825 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9826 @*/ 9827 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9828 { 9829 DM_Plex *plex = (DM_Plex *)dm->data; 9830 PetscMPIInt result; 9831 9832 PetscFunctionBegin; 9833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9834 if (anchorSection) { 9835 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9836 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9837 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9838 } 9839 if (anchorIS) { 9840 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9841 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9842 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9843 } 9844 9845 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9846 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9847 plex->anchorSection = anchorSection; 9848 9849 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9850 PetscCall(ISDestroy(&plex->anchorIS)); 9851 plex->anchorIS = anchorIS; 9852 9853 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9854 PetscInt size, a, pStart, pEnd; 9855 const PetscInt *anchors; 9856 9857 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9858 PetscCall(ISGetLocalSize(anchorIS, &size)); 9859 PetscCall(ISGetIndices(anchorIS, &anchors)); 9860 for (a = 0; a < size; a++) { 9861 PetscInt p; 9862 9863 p = anchors[a]; 9864 if (p >= pStart && p < pEnd) { 9865 PetscInt dof; 9866 9867 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9868 if (dof) { 9869 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9870 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9871 } 9872 } 9873 } 9874 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9875 } 9876 /* reset the generic constraints */ 9877 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9878 PetscFunctionReturn(PETSC_SUCCESS); 9879 } 9880 9881 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9882 { 9883 PetscSection anchorSection; 9884 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9885 9886 PetscFunctionBegin; 9887 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9888 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9889 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9890 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9891 if (numFields) { 9892 PetscInt f; 9893 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9894 9895 for (f = 0; f < numFields; f++) { 9896 PetscInt numComp; 9897 9898 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9899 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9900 } 9901 } 9902 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9903 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9904 pStart = PetscMax(pStart, sStart); 9905 pEnd = PetscMin(pEnd, sEnd); 9906 pEnd = PetscMax(pStart, pEnd); 9907 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9908 for (p = pStart; p < pEnd; p++) { 9909 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9910 if (dof) { 9911 PetscCall(PetscSectionGetDof(section, p, &dof)); 9912 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9913 for (f = 0; f < numFields; f++) { 9914 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9915 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9916 } 9917 } 9918 } 9919 PetscCall(PetscSectionSetUp(*cSec)); 9920 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9921 PetscFunctionReturn(PETSC_SUCCESS); 9922 } 9923 9924 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9925 { 9926 PetscSection aSec; 9927 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9928 const PetscInt *anchors; 9929 PetscInt numFields, f; 9930 IS aIS; 9931 MatType mtype; 9932 PetscBool iscuda, iskokkos; 9933 9934 PetscFunctionBegin; 9935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9936 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9937 PetscCall(PetscSectionGetStorageSize(section, &n)); 9938 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9939 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9940 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9941 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9942 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9943 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9944 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9945 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9946 else mtype = MATSEQAIJ; 9947 PetscCall(MatSetType(*cMat, mtype)); 9948 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9949 PetscCall(ISGetIndices(aIS, &anchors)); 9950 /* cSec will be a subset of aSec and section */ 9951 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9952 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9953 PetscCall(PetscMalloc1(m + 1, &i)); 9954 i[0] = 0; 9955 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9956 for (p = pStart; p < pEnd; p++) { 9957 PetscInt rDof, rOff, r; 9958 9959 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9960 if (!rDof) continue; 9961 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9962 if (numFields) { 9963 for (f = 0; f < numFields; f++) { 9964 annz = 0; 9965 for (r = 0; r < rDof; r++) { 9966 a = anchors[rOff + r]; 9967 if (a < sStart || a >= sEnd) continue; 9968 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9969 annz += aDof; 9970 } 9971 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9972 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9973 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9974 } 9975 } else { 9976 annz = 0; 9977 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9978 for (q = 0; q < dof; q++) { 9979 a = anchors[rOff + q]; 9980 if (a < sStart || a >= sEnd) continue; 9981 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9982 annz += aDof; 9983 } 9984 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9985 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9986 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9987 } 9988 } 9989 nnz = i[m]; 9990 PetscCall(PetscMalloc1(nnz, &j)); 9991 offset = 0; 9992 for (p = pStart; p < pEnd; p++) { 9993 if (numFields) { 9994 for (f = 0; f < numFields; f++) { 9995 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9996 for (q = 0; q < dof; q++) { 9997 PetscInt rDof, rOff, r; 9998 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9999 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10000 for (r = 0; r < rDof; r++) { 10001 PetscInt s; 10002 10003 a = anchors[rOff + r]; 10004 if (a < sStart || a >= sEnd) continue; 10005 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 10006 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 10007 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10008 } 10009 } 10010 } 10011 } else { 10012 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 10013 for (q = 0; q < dof; q++) { 10014 PetscInt rDof, rOff, r; 10015 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 10016 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 10017 for (r = 0; r < rDof; r++) { 10018 PetscInt s; 10019 10020 a = anchors[rOff + r]; 10021 if (a < sStart || a >= sEnd) continue; 10022 PetscCall(PetscSectionGetDof(section, a, &aDof)); 10023 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 10024 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 10025 } 10026 } 10027 } 10028 } 10029 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 10030 PetscCall(PetscFree(i)); 10031 PetscCall(PetscFree(j)); 10032 PetscCall(ISRestoreIndices(aIS, &anchors)); 10033 PetscFunctionReturn(PETSC_SUCCESS); 10034 } 10035 10036 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 10037 { 10038 DM_Plex *plex = (DM_Plex *)dm->data; 10039 PetscSection anchorSection, section, cSec; 10040 Mat cMat; 10041 10042 PetscFunctionBegin; 10043 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10044 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10045 if (anchorSection) { 10046 PetscInt Nf; 10047 10048 PetscCall(DMGetLocalSection(dm, §ion)); 10049 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10050 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10051 PetscCall(DMGetNumFields(dm, &Nf)); 10052 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10053 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10054 PetscCall(PetscSectionDestroy(&cSec)); 10055 PetscCall(MatDestroy(&cMat)); 10056 } 10057 PetscFunctionReturn(PETSC_SUCCESS); 10058 } 10059 10060 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10061 { 10062 IS subis; 10063 PetscSection section, subsection; 10064 10065 PetscFunctionBegin; 10066 PetscCall(DMGetLocalSection(dm, §ion)); 10067 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10068 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10069 /* Create subdomain */ 10070 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10071 /* Create submodel */ 10072 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10073 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10074 PetscCall(DMSetLocalSection(*subdm, subsection)); 10075 PetscCall(PetscSectionDestroy(&subsection)); 10076 PetscCall(DMCopyDisc(dm, *subdm)); 10077 /* Create map from submodel to global model */ 10078 if (is) { 10079 PetscSection sectionGlobal, subsectionGlobal; 10080 IS spIS; 10081 const PetscInt *spmap; 10082 PetscInt *subIndices; 10083 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10084 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10085 10086 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10087 PetscCall(ISGetIndices(spIS, &spmap)); 10088 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10089 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10090 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10091 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10092 for (p = pStart; p < pEnd; ++p) { 10093 PetscInt gdof, pSubSize = 0; 10094 10095 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10096 if (gdof > 0) { 10097 for (f = 0; f < Nf; ++f) { 10098 PetscInt fdof, fcdof; 10099 10100 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10101 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10102 pSubSize += fdof - fcdof; 10103 } 10104 subSize += pSubSize; 10105 if (pSubSize) { 10106 if (bs < 0) { 10107 bs = pSubSize; 10108 } else if (bs != pSubSize) { 10109 /* Layout does not admit a pointwise block size */ 10110 bs = 1; 10111 } 10112 } 10113 } 10114 } 10115 /* Must have same blocksize on all procs (some might have no points) */ 10116 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10117 bsLocal[1] = bs; 10118 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10119 if (bsMinMax[0] != bsMinMax[1]) { 10120 bs = 1; 10121 } else { 10122 bs = bsMinMax[0]; 10123 } 10124 PetscCall(PetscMalloc1(subSize, &subIndices)); 10125 for (p = pStart; p < pEnd; ++p) { 10126 PetscInt gdof, goff; 10127 10128 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10129 if (gdof > 0) { 10130 const PetscInt point = spmap[p]; 10131 10132 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10133 for (f = 0; f < Nf; ++f) { 10134 PetscInt fdof, fcdof, fc, f2, poff = 0; 10135 10136 /* Can get rid of this loop by storing field information in the global section */ 10137 for (f2 = 0; f2 < f; ++f2) { 10138 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10139 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10140 poff += fdof - fcdof; 10141 } 10142 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10143 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10144 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10145 } 10146 } 10147 } 10148 PetscCall(ISRestoreIndices(spIS, &spmap)); 10149 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10150 if (bs > 1) { 10151 /* We need to check that the block size does not come from non-contiguous fields */ 10152 PetscInt i, j, set = 1; 10153 for (i = 0; i < subSize; i += bs) { 10154 for (j = 0; j < bs; ++j) { 10155 if (subIndices[i + j] != subIndices[i] + j) { 10156 set = 0; 10157 break; 10158 } 10159 } 10160 } 10161 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10162 } 10163 /* Attach nullspace */ 10164 for (f = 0; f < Nf; ++f) { 10165 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10166 if ((*subdm)->nullspaceConstructors[f]) break; 10167 } 10168 if (f < Nf) { 10169 MatNullSpace nullSpace; 10170 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10171 10172 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10173 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10174 } 10175 } 10176 PetscFunctionReturn(PETSC_SUCCESS); 10177 } 10178 10179 /*@ 10180 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10181 10182 Input Parameters: 10183 + dm - The `DM` 10184 - dummy - unused argument 10185 10186 Options Database Key: 10187 . -dm_plex_monitor_throughput - Activate the monitor 10188 10189 Level: developer 10190 10191 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10192 @*/ 10193 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10194 { 10195 #if defined(PETSC_USE_LOG) 10196 PetscStageLog stageLog; 10197 PetscLogEvent event; 10198 PetscLogStage stage; 10199 PetscEventPerfInfo eventInfo; 10200 PetscReal cellRate, flopRate; 10201 PetscInt cStart, cEnd, Nf, N; 10202 const char *name; 10203 #endif 10204 10205 PetscFunctionBegin; 10206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10207 #if defined(PETSC_USE_LOG) 10208 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10209 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10210 PetscCall(DMGetNumFields(dm, &Nf)); 10211 PetscCall(PetscLogGetStageLog(&stageLog)); 10212 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10213 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10214 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10215 N = (cEnd - cStart) * Nf * eventInfo.count; 10216 flopRate = eventInfo.flops / eventInfo.time; 10217 cellRate = N / eventInfo.time; 10218 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))); 10219 #else 10220 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10221 #endif 10222 PetscFunctionReturn(PETSC_SUCCESS); 10223 } 10224