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