1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate, DMPLEX_Transform, DMPLEX_GetLocalOffsets; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The `DMPLEX` object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Level: intermediate 28 29 Note: 30 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 31 If the mesh has no cells, this returns `PETSC_FALSE`. 32 33 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 34 @*/ 35 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 36 { 37 DMPolytopeType ct; 38 PetscInt cStart, cEnd; 39 40 PetscFunctionBegin; 41 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 42 if (cEnd <= cStart) { 43 *simplex = PETSC_FALSE; 44 PetscFunctionReturn(PETSC_SUCCESS); 45 } 46 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 47 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 48 PetscFunctionReturn(PETSC_SUCCESS); 49 } 50 51 /*@ 52 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 53 54 Input Parameters: 55 + dm - The `DMPLEX` object 56 - height - The cell height in the Plex, 0 is the default 57 58 Output Parameters: 59 + cStart - The first "normal" cell 60 - cEnd - The upper bound on "normal"" cells 61 62 Level: developer 63 64 Note: 65 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 66 67 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 68 @*/ 69 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 70 { 71 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 72 PetscInt cS, cE, c; 73 74 PetscFunctionBegin; 75 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 76 for (c = cS; c < cE; ++c) { 77 DMPolytopeType cct; 78 79 PetscCall(DMPlexGetCellType(dm, c, &cct)); 80 if ((PetscInt)cct < 0) break; 81 switch (cct) { 82 case DM_POLYTOPE_POINT: 83 case DM_POLYTOPE_SEGMENT: 84 case DM_POLYTOPE_TRIANGLE: 85 case DM_POLYTOPE_QUADRILATERAL: 86 case DM_POLYTOPE_TETRAHEDRON: 87 case DM_POLYTOPE_HEXAHEDRON: 88 ct = cct; 89 break; 90 default: 91 break; 92 } 93 if (ct != DM_POLYTOPE_UNKNOWN) break; 94 } 95 if (ct != DM_POLYTOPE_UNKNOWN) { 96 DMLabel ctLabel; 97 98 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 99 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 100 // Reset label for fast lookup 101 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 102 } 103 if (cStart) *cStart = cS; 104 if (cEnd) *cEnd = cE; 105 PetscFunctionReturn(PETSC_SUCCESS); 106 } 107 108 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 109 { 110 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 111 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 112 113 PetscFunctionBegin; 114 *ft = PETSC_VTK_INVALID; 115 PetscCall(DMGetCoordinateDim(dm, &cdim)); 116 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 117 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 118 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 119 if (field >= 0) { 120 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 121 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 122 } else { 123 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 124 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 125 } 126 PetscCall(MPIU_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 127 if (globalvcdof[0]) { 128 *sStart = vStart; 129 *sEnd = vEnd; 130 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 131 else *ft = PETSC_VTK_POINT_FIELD; 132 } else if (globalvcdof[1]) { 133 *sStart = cStart; 134 *sEnd = cEnd; 135 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 136 else *ft = PETSC_VTK_CELL_FIELD; 137 } else { 138 if (field >= 0) { 139 const char *fieldname; 140 141 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 143 } else { 144 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 145 } 146 } 147 PetscFunctionReturn(PETSC_SUCCESS); 148 } 149 150 /*@ 151 DMPlexVecView1D - Plot many 1D solutions on the same line graph 152 153 Collective 154 155 Input Parameters: 156 + dm - The `DMPLEX` object 157 . n - The number of vectors 158 . u - The array of local vectors 159 - viewer - The `PetscViewer` 160 161 Level: advanced 162 163 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 164 @*/ 165 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 166 { 167 PetscDS ds; 168 PetscDraw draw = NULL; 169 PetscDrawLG lg; 170 Vec coordinates; 171 const PetscScalar *coords, **sol; 172 PetscReal *vals; 173 PetscInt *Nc; 174 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 175 char **names; 176 177 PetscFunctionBegin; 178 PetscCall(DMGetDS(dm, &ds)); 179 PetscCall(PetscDSGetNumFields(ds, &Nf)); 180 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 181 PetscCall(PetscDSGetComponents(ds, &Nc)); 182 183 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 184 if (!draw) PetscFunctionReturn(PETSC_SUCCESS); 185 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 186 187 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 188 for (i = 0, l = 0; i < n; ++i) { 189 const char *vname; 190 191 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 192 for (f = 0; f < Nf; ++f) { 193 PetscObject disc; 194 const char *fname; 195 char tmpname[PETSC_MAX_PATH_LEN]; 196 197 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 198 /* TODO Create names for components */ 199 for (c = 0; c < Nc[f]; ++c, ++l) { 200 PetscCall(PetscObjectGetName(disc, &fname)); 201 PetscCall(PetscStrncpy(tmpname, vname, sizeof(tmpname))); 202 PetscCall(PetscStrlcat(tmpname, ":", sizeof(tmpname))); 203 PetscCall(PetscStrlcat(tmpname, fname, sizeof(tmpname))); 204 PetscCall(PetscStrallocpy(tmpname, &names[l])); 205 } 206 } 207 } 208 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 209 /* Just add P_1 support for now */ 210 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 211 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 212 PetscCall(VecGetArrayRead(coordinates, &coords)); 213 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 214 for (v = vStart; v < vEnd; ++v) { 215 PetscScalar *x, *svals; 216 217 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 218 for (i = 0; i < n; ++i) { 219 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 220 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 221 } 222 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 223 } 224 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 225 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 226 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 227 PetscCall(PetscFree3(sol, names, vals)); 228 229 PetscCall(PetscDrawLGDraw(lg)); 230 PetscCall(PetscDrawLGDestroy(&lg)); 231 PetscFunctionReturn(PETSC_SUCCESS); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 235 { 236 DM dm; 237 238 PetscFunctionBegin; 239 PetscCall(VecGetDM(u, &dm)); 240 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 241 PetscFunctionReturn(PETSC_SUCCESS); 242 } 243 244 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 245 { 246 DM dm; 247 PetscSection s; 248 PetscDraw draw, popup; 249 DM cdm; 250 PetscSection coordSection; 251 Vec coordinates; 252 const PetscScalar *array; 253 PetscReal lbound[3], ubound[3]; 254 PetscReal vbound[2], time; 255 PetscBool flg; 256 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 257 const char *name; 258 char title[PETSC_MAX_PATH_LEN]; 259 260 PetscFunctionBegin; 261 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 262 PetscCall(VecGetDM(v, &dm)); 263 PetscCall(DMGetCoordinateDim(dm, &dim)); 264 PetscCall(DMGetLocalSection(dm, &s)); 265 PetscCall(PetscSectionGetNumFields(s, &Nf)); 266 PetscCall(DMGetCoarsenLevel(dm, &level)); 267 PetscCall(DMGetCoordinateDM(dm, &cdm)); 268 PetscCall(DMGetLocalSection(cdm, &coordSection)); 269 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 270 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 271 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 272 273 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 274 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 275 276 PetscCall(VecGetLocalSize(coordinates, &N)); 277 PetscCall(DMGetBoundingBox(dm, lbound, ubound)); 278 PetscCall(PetscDrawClear(draw)); 279 280 /* Could implement something like DMDASelectFields() */ 281 for (f = 0; f < Nf; ++f) { 282 DM fdm = dm; 283 Vec fv = v; 284 IS fis; 285 char prefix[PETSC_MAX_PATH_LEN]; 286 const char *fname; 287 288 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 289 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 290 291 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 292 else prefix[0] = '\0'; 293 if (Nf > 1) { 294 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 295 PetscCall(VecGetSubVector(v, fis, &fv)); 296 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 297 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 298 } 299 for (comp = 0; comp < Nc; ++comp, ++w) { 300 PetscInt nmax = 2; 301 302 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 303 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 304 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 305 PetscCall(PetscDrawSetTitle(draw, title)); 306 307 /* TODO Get max and min only for this component */ 308 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 309 if (!flg) { 310 PetscCall(VecMin(fv, NULL, &vbound[0])); 311 PetscCall(VecMax(fv, NULL, &vbound[1])); 312 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 313 } 314 315 PetscCall(PetscDrawGetPopup(draw, &popup)); 316 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 317 PetscCall(PetscDrawSetCoordinates(draw, lbound[0], lbound[1], ubound[0], ubound[1])); 318 PetscCall(VecGetArrayRead(fv, &array)); 319 for (c = cStart; c < cEnd; ++c) { 320 PetscScalar *coords = NULL, *a = NULL; 321 const PetscScalar *coords_arr; 322 PetscBool isDG; 323 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 324 325 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 326 if (a) { 327 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 328 color[1] = color[2] = color[3] = color[0]; 329 } else { 330 PetscScalar *vals = NULL; 331 PetscInt numVals, va; 332 333 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 334 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 335 switch (numVals / Nc) { 336 case 3: /* P1 Triangle */ 337 case 4: /* P1 Quadrangle */ 338 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 339 break; 340 case 6: /* P2 Triangle */ 341 case 8: /* P2 Quadrangle */ 342 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 343 break; 344 default: 345 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 346 } 347 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 348 } 349 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 350 switch (numCoords) { 351 case 6: 352 case 12: /* Localized triangle */ 353 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 354 break; 355 case 8: 356 case 16: /* Localized quadrilateral */ 357 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 358 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 359 break; 360 default: 361 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 362 } 363 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 364 } 365 PetscCall(VecRestoreArrayRead(fv, &array)); 366 PetscCall(PetscDrawFlush(draw)); 367 PetscCall(PetscDrawPause(draw)); 368 PetscCall(PetscDrawSave(draw)); 369 } 370 if (Nf > 1) { 371 PetscCall(VecRestoreSubVector(v, fis, &fv)); 372 PetscCall(ISDestroy(&fis)); 373 PetscCall(DMDestroy(&fdm)); 374 } 375 } 376 PetscFunctionReturn(PETSC_SUCCESS); 377 } 378 379 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 380 { 381 DM dm; 382 PetscDraw draw; 383 PetscInt dim; 384 PetscBool isnull; 385 386 PetscFunctionBegin; 387 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 388 PetscCall(PetscDrawIsNull(draw, &isnull)); 389 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 390 391 PetscCall(VecGetDM(v, &dm)); 392 PetscCall(DMGetCoordinateDim(dm, &dim)); 393 switch (dim) { 394 case 1: 395 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 396 break; 397 case 2: 398 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 399 break; 400 default: 401 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 402 } 403 PetscFunctionReturn(PETSC_SUCCESS); 404 } 405 406 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 407 { 408 DM dm; 409 Vec locv; 410 const char *name; 411 PetscSection section; 412 PetscInt pStart, pEnd; 413 PetscInt numFields; 414 PetscViewerVTKFieldType ft; 415 416 PetscFunctionBegin; 417 PetscCall(VecGetDM(v, &dm)); 418 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 419 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 420 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 421 PetscCall(VecCopy(v, locv)); 422 PetscCall(DMGetLocalSection(dm, §ion)); 423 PetscCall(PetscSectionGetNumFields(section, &numFields)); 424 if (!numFields) { 425 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 426 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 427 } else { 428 PetscInt f; 429 430 for (f = 0; f < numFields; f++) { 431 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 432 if (ft == PETSC_VTK_INVALID) continue; 433 PetscCall(PetscObjectReference((PetscObject)locv)); 434 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 435 } 436 PetscCall(VecDestroy(&locv)); 437 } 438 PetscFunctionReturn(PETSC_SUCCESS); 439 } 440 441 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 442 { 443 DM dm; 444 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 445 446 PetscFunctionBegin; 447 PetscCall(VecGetDM(v, &dm)); 448 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 449 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 450 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 451 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 453 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 454 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 455 PetscInt i, numFields; 456 PetscObject fe; 457 PetscBool fem = PETSC_FALSE; 458 Vec locv = v; 459 const char *name; 460 PetscInt step; 461 PetscReal time; 462 463 PetscCall(DMGetNumFields(dm, &numFields)); 464 for (i = 0; i < numFields; i++) { 465 PetscCall(DMGetField(dm, i, NULL, &fe)); 466 if (fe->classid == PETSCFE_CLASSID) { 467 fem = PETSC_TRUE; 468 break; 469 } 470 } 471 if (fem) { 472 PetscObject isZero; 473 474 PetscCall(DMGetLocalVector(dm, &locv)); 475 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 476 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 477 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 478 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 479 PetscCall(VecCopy(v, locv)); 480 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 481 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 482 } 483 if (isvtk) { 484 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 485 } else if (ishdf5) { 486 #if defined(PETSC_HAVE_HDF5) 487 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 488 #else 489 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 490 #endif 491 } else if (isdraw) { 492 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 493 } else if (isglvis) { 494 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 495 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 496 PetscCall(VecView_GLVis(locv, viewer)); 497 } else if (iscgns) { 498 #if defined(PETSC_HAVE_CGNS) 499 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 500 #else 501 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 502 #endif 503 } 504 if (fem) { 505 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 506 PetscCall(DMRestoreLocalVector(dm, &locv)); 507 } 508 } else { 509 PetscBool isseq; 510 511 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 512 if (isseq) PetscCall(VecView_Seq(v, viewer)); 513 else PetscCall(VecView_MPI(v, viewer)); 514 } 515 PetscFunctionReturn(PETSC_SUCCESS); 516 } 517 518 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 519 { 520 DM dm; 521 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 522 523 PetscFunctionBegin; 524 PetscCall(VecGetDM(v, &dm)); 525 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 526 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 527 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 528 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 529 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 530 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 532 if (isvtk || isdraw || isglvis || iscgns) { 533 Vec locv; 534 PetscObject isZero; 535 const char *name; 536 537 PetscCall(DMGetLocalVector(dm, &locv)); 538 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 539 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 540 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 541 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 542 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 543 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 544 PetscCall(VecView_Plex_Local(locv, viewer)); 545 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 546 PetscCall(DMRestoreLocalVector(dm, &locv)); 547 } else if (ishdf5) { 548 #if defined(PETSC_HAVE_HDF5) 549 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 550 #else 551 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 552 #endif 553 } else if (isexodusii) { 554 #if defined(PETSC_HAVE_EXODUSII) 555 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 556 #else 557 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 558 #endif 559 } else { 560 PetscBool isseq; 561 562 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 563 if (isseq) PetscCall(VecView_Seq(v, viewer)); 564 else PetscCall(VecView_MPI(v, viewer)); 565 } 566 PetscFunctionReturn(PETSC_SUCCESS); 567 } 568 569 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 570 { 571 DM dm; 572 MPI_Comm comm; 573 PetscViewerFormat format; 574 Vec v; 575 PetscBool isvtk, ishdf5; 576 577 PetscFunctionBegin; 578 PetscCall(VecGetDM(originalv, &dm)); 579 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 580 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 581 PetscCall(PetscViewerGetFormat(viewer, &format)); 582 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 583 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 584 if (format == PETSC_VIEWER_NATIVE) { 585 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 586 /* this need a better fix */ 587 if (dm->useNatural) { 588 if (dm->sfNatural) { 589 const char *vecname; 590 PetscInt n, nroots; 591 592 PetscCall(VecGetLocalSize(originalv, &n)); 593 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 594 if (n == nroots) { 595 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 596 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 597 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 598 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 599 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 600 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 601 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 602 } else v = originalv; 603 } else v = originalv; 604 605 if (ishdf5) { 606 #if defined(PETSC_HAVE_HDF5) 607 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 608 #else 609 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 610 #endif 611 } else if (isvtk) { 612 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 613 } else { 614 PetscBool isseq; 615 616 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 617 if (isseq) PetscCall(VecView_Seq(v, viewer)); 618 else PetscCall(VecView_MPI(v, viewer)); 619 } 620 if (v != originalv) PetscCall(VecDestroy(&v)); 621 PetscFunctionReturn(PETSC_SUCCESS); 622 } 623 624 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 625 { 626 DM dm; 627 PetscBool ishdf5; 628 629 PetscFunctionBegin; 630 PetscCall(VecGetDM(v, &dm)); 631 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 632 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 633 if (ishdf5) { 634 DM dmBC; 635 Vec gv; 636 const char *name; 637 638 PetscCall(DMGetOutputDM(dm, &dmBC)); 639 PetscCall(DMGetGlobalVector(dmBC, &gv)); 640 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 641 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 642 PetscCall(VecLoad_Default(gv, viewer)); 643 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 644 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 645 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 646 } else PetscCall(VecLoad_Default(v, viewer)); 647 PetscFunctionReturn(PETSC_SUCCESS); 648 } 649 650 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 651 { 652 DM dm; 653 PetscBool ishdf5, isexodusii; 654 655 PetscFunctionBegin; 656 PetscCall(VecGetDM(v, &dm)); 657 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 658 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 659 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 660 if (ishdf5) { 661 #if defined(PETSC_HAVE_HDF5) 662 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 663 #else 664 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 665 #endif 666 } else if (isexodusii) { 667 #if defined(PETSC_HAVE_EXODUSII) 668 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 669 #else 670 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 671 #endif 672 } else PetscCall(VecLoad_Default(v, viewer)); 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 677 { 678 DM dm; 679 PetscViewerFormat format; 680 PetscBool ishdf5; 681 682 PetscFunctionBegin; 683 PetscCall(VecGetDM(originalv, &dm)); 684 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 685 PetscCall(PetscViewerGetFormat(viewer, &format)); 686 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 687 if (format == PETSC_VIEWER_NATIVE) { 688 if (dm->useNatural) { 689 if (dm->sfNatural) { 690 if (ishdf5) { 691 #if defined(PETSC_HAVE_HDF5) 692 Vec v; 693 const char *vecname; 694 695 PetscCall(DMPlexCreateNaturalVector(dm, &v)); 696 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 697 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 698 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 699 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 700 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 701 PetscCall(VecDestroy(&v)); 702 #else 703 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 704 #endif 705 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 706 } 707 } else PetscCall(VecLoad_Default(originalv, viewer)); 708 } 709 PetscFunctionReturn(PETSC_SUCCESS); 710 } 711 712 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 713 { 714 PetscSection coordSection; 715 Vec coordinates; 716 DMLabel depthLabel, celltypeLabel; 717 const char *name[4]; 718 const PetscScalar *a; 719 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 720 721 PetscFunctionBegin; 722 PetscCall(DMGetDimension(dm, &dim)); 723 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 724 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 725 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 726 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 727 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 728 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 729 PetscCall(VecGetArrayRead(coordinates, &a)); 730 name[0] = "vertex"; 731 name[1] = "edge"; 732 name[dim - 1] = "face"; 733 name[dim] = "cell"; 734 for (c = cStart; c < cEnd; ++c) { 735 PetscInt *closure = NULL; 736 PetscInt closureSize, cl, ct; 737 738 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 739 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 740 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 741 PetscCall(PetscViewerASCIIPushTab(viewer)); 742 for (cl = 0; cl < closureSize * 2; cl += 2) { 743 PetscInt point = closure[cl], depth, dof, off, d, p; 744 745 if ((point < pStart) || (point >= pEnd)) continue; 746 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 747 if (!dof) continue; 748 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 749 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 750 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 751 for (p = 0; p < dof / dim; ++p) { 752 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 753 for (d = 0; d < dim; ++d) { 754 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 755 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 756 } 757 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 758 } 759 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 760 } 761 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 762 PetscCall(PetscViewerASCIIPopTab(viewer)); 763 } 764 PetscCall(VecRestoreArrayRead(coordinates, &a)); 765 PetscFunctionReturn(PETSC_SUCCESS); 766 } 767 768 typedef enum { 769 CS_CARTESIAN, 770 CS_POLAR, 771 CS_CYLINDRICAL, 772 CS_SPHERICAL 773 } CoordSystem; 774 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 775 776 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 777 { 778 PetscInt i; 779 780 PetscFunctionBegin; 781 if (dim > 3) { 782 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 783 } else { 784 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 785 786 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 787 switch (cs) { 788 case CS_CARTESIAN: 789 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 790 break; 791 case CS_POLAR: 792 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 793 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 794 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 795 break; 796 case CS_CYLINDRICAL: 797 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 798 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 799 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 800 trcoords[2] = coords[2]; 801 break; 802 case CS_SPHERICAL: 803 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 804 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 805 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 806 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 807 break; 808 } 809 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 810 } 811 PetscFunctionReturn(PETSC_SUCCESS); 812 } 813 814 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 815 { 816 DM_Plex *mesh = (DM_Plex *)dm->data; 817 DM cdm, cdmCell; 818 PetscSection coordSection, coordSectionCell; 819 Vec coordinates, coordinatesCell; 820 PetscViewerFormat format; 821 822 PetscFunctionBegin; 823 PetscCall(PetscViewerGetFormat(viewer, &format)); 824 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 825 const char *name; 826 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 827 PetscInt pStart, pEnd, p, numLabels, l; 828 PetscMPIInt rank, size; 829 830 PetscCall(DMGetCoordinateDM(dm, &cdm)); 831 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 832 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 833 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 834 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 835 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 836 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 837 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 838 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 839 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 840 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 841 PetscCall(DMGetDimension(dm, &dim)); 842 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 843 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 844 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 845 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 846 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 847 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 848 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 849 for (p = pStart; p < pEnd; ++p) { 850 PetscInt dof, off, s; 851 852 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 853 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 854 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 855 } 856 PetscCall(PetscViewerFlush(viewer)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 858 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 859 for (p = pStart; p < pEnd; ++p) { 860 PetscInt dof, off, c; 861 862 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 863 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 864 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 865 } 866 PetscCall(PetscViewerFlush(viewer)); 867 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 868 if (coordSection && coordinates) { 869 CoordSystem cs = CS_CARTESIAN; 870 const PetscScalar *array, *arrayCell = NULL; 871 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 872 PetscMPIInt rank; 873 const char *name; 874 875 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 876 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 877 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 878 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 879 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 880 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 881 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 882 pStart = PetscMin(pvStart, pcStart); 883 pEnd = PetscMax(pvEnd, pcEnd); 884 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 885 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 886 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 887 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 888 889 PetscCall(VecGetArrayRead(coordinates, &array)); 890 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 891 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 892 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 893 for (p = pStart; p < pEnd; ++p) { 894 PetscInt dof, off; 895 896 if (p >= pvStart && p < pvEnd) { 897 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 898 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 899 if (dof) { 900 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 901 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 902 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 903 } 904 } 905 if (cdmCell && p >= pcStart && p < pcEnd) { 906 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 907 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 908 if (dof) { 909 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 910 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 911 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 912 } 913 } 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 917 PetscCall(VecRestoreArrayRead(coordinates, &array)); 918 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 919 } 920 PetscCall(DMGetNumLabels(dm, &numLabels)); 921 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 922 for (l = 0; l < numLabels; ++l) { 923 DMLabel label; 924 PetscBool isdepth; 925 const char *name; 926 927 PetscCall(DMGetLabelName(dm, l, &name)); 928 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 929 if (isdepth) continue; 930 PetscCall(DMGetLabel(dm, name, &label)); 931 PetscCall(DMLabelView(label, viewer)); 932 } 933 if (size > 1) { 934 PetscSF sf; 935 936 PetscCall(DMGetPointSF(dm, &sf)); 937 PetscCall(PetscSFView(sf, viewer)); 938 } 939 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 940 PetscCall(PetscViewerFlush(viewer)); 941 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 942 const char *name, *color; 943 const char *defcolors[3] = {"gray", "orange", "green"}; 944 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 945 char lname[PETSC_MAX_PATH_LEN]; 946 PetscReal scale = 2.0; 947 PetscReal tikzscale = 1.0; 948 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 949 double tcoords[3]; 950 PetscScalar *coords; 951 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 952 PetscMPIInt rank, size; 953 char **names, **colors, **lcolors; 954 PetscBool flg, lflg; 955 PetscBT wp = NULL; 956 PetscInt pEnd, pStart; 957 958 PetscCall(DMGetCoordinateDM(dm, &cdm)); 959 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 960 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 961 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 962 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 963 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 964 PetscCall(DMGetDimension(dm, &dim)); 965 PetscCall(DMPlexGetDepth(dm, &depth)); 966 PetscCall(DMGetNumLabels(dm, &numLabels)); 967 numLabels = PetscMax(numLabels, 10); 968 numColors = 10; 969 numLColors = 10; 970 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 971 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 972 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 973 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 974 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 975 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 976 n = 4; 977 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 978 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 979 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 980 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 981 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 982 if (!useLabels) numLabels = 0; 983 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 984 if (!useColors) { 985 numColors = 3; 986 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 987 } 988 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 989 if (!useColors) { 990 numLColors = 4; 991 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 992 } 993 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 994 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 995 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 996 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 997 if (depth < dim) plotEdges = PETSC_FALSE; 998 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 999 1000 /* filter points with labelvalue != labeldefaultvalue */ 1001 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1002 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1003 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1004 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1005 if (lflg) { 1006 DMLabel lbl; 1007 1008 PetscCall(DMGetLabel(dm, lname, &lbl)); 1009 if (lbl) { 1010 PetscInt val, defval; 1011 1012 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1013 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1014 for (c = pStart; c < pEnd; c++) { 1015 PetscInt *closure = NULL; 1016 PetscInt closureSize; 1017 1018 PetscCall(DMLabelGetValue(lbl, c, &val)); 1019 if (val == defval) continue; 1020 1021 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1022 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1023 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1024 } 1025 } 1026 } 1027 1028 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1029 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1030 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1031 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1032 \\documentclass[tikz]{standalone}\n\n\ 1033 \\usepackage{pgflibraryshapes}\n\ 1034 \\usetikzlibrary{backgrounds}\n\ 1035 \\usetikzlibrary{arrows}\n\ 1036 \\begin{document}\n")); 1037 if (size > 1) { 1038 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1039 for (p = 0; p < size; ++p) { 1040 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1041 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1042 } 1043 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1044 } 1045 if (drawHasse) { 1046 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1047 1048 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1049 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1050 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1058 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1060 } 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1062 1063 /* Plot vertices */ 1064 PetscCall(VecGetArray(coordinates, &coords)); 1065 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1066 for (v = vStart; v < vEnd; ++v) { 1067 PetscInt off, dof, d; 1068 PetscBool isLabeled = PETSC_FALSE; 1069 1070 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1071 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1072 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1073 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1074 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1075 for (d = 0; d < dof; ++d) { 1076 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1077 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1078 } 1079 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1080 if (dim == 3) { 1081 PetscReal tmp = tcoords[1]; 1082 tcoords[1] = tcoords[2]; 1083 tcoords[2] = -tmp; 1084 } 1085 for (d = 0; d < dof; ++d) { 1086 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1088 } 1089 if (drawHasse) color = colors[0 % numColors]; 1090 else color = colors[rank % numColors]; 1091 for (l = 0; l < numLabels; ++l) { 1092 PetscInt val; 1093 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1094 if (val >= 0) { 1095 color = lcolors[l % numLColors]; 1096 isLabeled = PETSC_TRUE; 1097 break; 1098 } 1099 } 1100 if (drawNumbers[0]) { 1101 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1102 } else if (drawColors[0]) { 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1104 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1105 } 1106 PetscCall(VecRestoreArray(coordinates, &coords)); 1107 PetscCall(PetscViewerFlush(viewer)); 1108 /* Plot edges */ 1109 if (plotEdges) { 1110 PetscCall(VecGetArray(coordinates, &coords)); 1111 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1112 for (e = eStart; e < eEnd; ++e) { 1113 const PetscInt *cone; 1114 PetscInt coneSize, offA, offB, dof, d; 1115 1116 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1117 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1118 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1119 PetscCall(DMPlexGetCone(dm, e, &cone)); 1120 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1121 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1122 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1123 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1124 for (d = 0; d < dof; ++d) { 1125 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1126 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1127 } 1128 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1129 if (dim == 3) { 1130 PetscReal tmp = tcoords[1]; 1131 tcoords[1] = tcoords[2]; 1132 tcoords[2] = -tmp; 1133 } 1134 for (d = 0; d < dof; ++d) { 1135 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1136 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1137 } 1138 if (drawHasse) color = colors[1 % numColors]; 1139 else color = colors[rank % numColors]; 1140 for (l = 0; l < numLabels; ++l) { 1141 PetscInt val; 1142 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1143 if (val >= 0) { 1144 color = lcolors[l % numLColors]; 1145 break; 1146 } 1147 } 1148 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1149 } 1150 PetscCall(VecRestoreArray(coordinates, &coords)); 1151 PetscCall(PetscViewerFlush(viewer)); 1152 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1153 } 1154 /* Plot cells */ 1155 if (dim == 3 || !drawNumbers[1]) { 1156 for (e = eStart; e < eEnd; ++e) { 1157 const PetscInt *cone; 1158 1159 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1160 color = colors[rank % numColors]; 1161 for (l = 0; l < numLabels; ++l) { 1162 PetscInt val; 1163 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1164 if (val >= 0) { 1165 color = lcolors[l % numLColors]; 1166 break; 1167 } 1168 } 1169 PetscCall(DMPlexGetCone(dm, e, &cone)); 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1171 } 1172 } else { 1173 DMPolytopeType ct; 1174 1175 /* Drawing a 2D polygon */ 1176 for (c = cStart; c < cEnd; ++c) { 1177 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1178 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1179 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1180 const PetscInt *cone; 1181 PetscInt coneSize, e; 1182 1183 PetscCall(DMPlexGetCone(dm, c, &cone)); 1184 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1185 for (e = 0; e < coneSize; ++e) { 1186 const PetscInt *econe; 1187 1188 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1190 } 1191 } else { 1192 PetscInt *closure = NULL; 1193 PetscInt closureSize, Nv = 0, v; 1194 1195 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1196 for (p = 0; p < closureSize * 2; p += 2) { 1197 const PetscInt point = closure[p]; 1198 1199 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1200 } 1201 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1202 for (v = 0; v <= Nv; ++v) { 1203 const PetscInt vertex = closure[v % Nv]; 1204 1205 if (v > 0) { 1206 if (plotEdges) { 1207 const PetscInt *edge; 1208 PetscInt endpoints[2], ne; 1209 1210 endpoints[0] = closure[v - 1]; 1211 endpoints[1] = vertex; 1212 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1213 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1214 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1215 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1216 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1217 } 1218 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1219 } 1220 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1221 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1222 } 1223 } 1224 } 1225 for (c = cStart; c < cEnd; ++c) { 1226 double ccoords[3] = {0.0, 0.0, 0.0}; 1227 PetscBool isLabeled = PETSC_FALSE; 1228 PetscScalar *cellCoords = NULL; 1229 const PetscScalar *array; 1230 PetscInt numCoords, cdim, d; 1231 PetscBool isDG; 1232 1233 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1234 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1235 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1236 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1237 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1238 for (p = 0; p < numCoords / cdim; ++p) { 1239 for (d = 0; d < cdim; ++d) { 1240 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1241 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1242 } 1243 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1244 if (cdim == 3) { 1245 PetscReal tmp = tcoords[1]; 1246 tcoords[1] = tcoords[2]; 1247 tcoords[2] = -tmp; 1248 } 1249 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1250 } 1251 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1252 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1253 for (d = 0; d < cdim; ++d) { 1254 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1255 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1256 } 1257 if (drawHasse) color = colors[depth % numColors]; 1258 else color = colors[rank % numColors]; 1259 for (l = 0; l < numLabels; ++l) { 1260 PetscInt val; 1261 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1262 if (val >= 0) { 1263 color = lcolors[l % numLColors]; 1264 isLabeled = PETSC_TRUE; 1265 break; 1266 } 1267 } 1268 if (drawNumbers[dim]) { 1269 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1270 } else if (drawColors[dim]) { 1271 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1272 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1273 } 1274 if (drawHasse) { 1275 color = colors[depth % numColors]; 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1278 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1279 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1280 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1281 1282 color = colors[1 % numColors]; 1283 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1284 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1286 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1287 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1288 1289 color = colors[0 % numColors]; 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1291 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1293 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1294 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1295 1296 for (p = pStart; p < pEnd; ++p) { 1297 const PetscInt *cone; 1298 PetscInt coneSize, cp; 1299 1300 PetscCall(DMPlexGetCone(dm, p, &cone)); 1301 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1302 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1303 } 1304 } 1305 PetscCall(PetscViewerFlush(viewer)); 1306 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1307 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1308 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1309 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1310 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1311 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1312 PetscCall(PetscFree3(names, colors, lcolors)); 1313 PetscCall(PetscBTDestroy(&wp)); 1314 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1315 Vec cown, acown; 1316 VecScatter sct; 1317 ISLocalToGlobalMapping g2l; 1318 IS gid, acis; 1319 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1320 MPI_Group ggroup, ngroup; 1321 PetscScalar *array, nid; 1322 const PetscInt *idxs; 1323 PetscInt *idxs2, *start, *adjacency, *work; 1324 PetscInt64 lm[3], gm[3]; 1325 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1326 PetscMPIInt d1, d2, rank; 1327 1328 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1329 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1330 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1331 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1332 #endif 1333 if (ncomm != MPI_COMM_NULL) { 1334 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1335 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1336 d1 = 0; 1337 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1338 nid = d2; 1339 PetscCallMPI(MPI_Group_free(&ggroup)); 1340 PetscCallMPI(MPI_Group_free(&ngroup)); 1341 PetscCallMPI(MPI_Comm_free(&ncomm)); 1342 } else nid = 0.0; 1343 1344 /* Get connectivity */ 1345 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1346 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1347 1348 /* filter overlapped local cells */ 1349 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1350 PetscCall(ISGetIndices(gid, &idxs)); 1351 PetscCall(ISGetLocalSize(gid, &cum)); 1352 PetscCall(PetscMalloc1(cum, &idxs2)); 1353 for (c = cStart, cum = 0; c < cEnd; c++) { 1354 if (idxs[c - cStart] < 0) continue; 1355 idxs2[cum++] = idxs[c - cStart]; 1356 } 1357 PetscCall(ISRestoreIndices(gid, &idxs)); 1358 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1359 PetscCall(ISDestroy(&gid)); 1360 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1361 1362 /* support for node-aware cell locality */ 1363 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1364 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1365 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1366 PetscCall(VecGetArray(cown, &array)); 1367 for (c = 0; c < numVertices; c++) array[c] = nid; 1368 PetscCall(VecRestoreArray(cown, &array)); 1369 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1370 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1371 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1372 PetscCall(ISDestroy(&acis)); 1373 PetscCall(VecScatterDestroy(&sct)); 1374 PetscCall(VecDestroy(&cown)); 1375 1376 /* compute edgeCut */ 1377 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1378 PetscCall(PetscMalloc1(cum, &work)); 1379 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1380 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1381 PetscCall(ISDestroy(&gid)); 1382 PetscCall(VecGetArray(acown, &array)); 1383 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1384 PetscInt totl; 1385 1386 totl = start[c + 1] - start[c]; 1387 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1388 for (i = 0; i < totl; i++) { 1389 if (work[i] < 0) { 1390 ect += 1; 1391 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1392 } 1393 } 1394 } 1395 PetscCall(PetscFree(work)); 1396 PetscCall(VecRestoreArray(acown, &array)); 1397 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1398 lm[1] = -numVertices; 1399 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1400 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1401 lm[0] = ect; /* edgeCut */ 1402 lm[1] = ectn; /* node-aware edgeCut */ 1403 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1404 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1406 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1407 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1408 #else 1409 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1410 #endif 1411 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1412 PetscCall(PetscFree(start)); 1413 PetscCall(PetscFree(adjacency)); 1414 PetscCall(VecDestroy(&acown)); 1415 } else { 1416 const char *name; 1417 PetscInt *sizes, *hybsizes, *ghostsizes; 1418 PetscInt locDepth, depth, cellHeight, dim, d; 1419 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1420 PetscInt numLabels, l, maxSize = 17; 1421 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1422 MPI_Comm comm; 1423 PetscMPIInt size, rank; 1424 1425 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1426 PetscCallMPI(MPI_Comm_size(comm, &size)); 1427 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1428 PetscCall(DMGetDimension(dm, &dim)); 1429 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1430 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1431 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1432 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1433 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1434 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1435 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1436 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1437 gcNum = gcEnd - gcStart; 1438 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1439 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1440 for (d = 0; d <= depth; d++) { 1441 PetscInt Nc[2] = {0, 0}, ict; 1442 1443 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1444 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1445 ict = ct0; 1446 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1447 ct0 = (DMPolytopeType)ict; 1448 for (p = pStart; p < pEnd; ++p) { 1449 DMPolytopeType ct; 1450 1451 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1452 if (ct == ct0) ++Nc[0]; 1453 else ++Nc[1]; 1454 } 1455 if (size < maxSize) { 1456 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1457 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1458 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1459 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1460 for (p = 0; p < size; ++p) { 1461 if (rank == 0) { 1462 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1463 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1464 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1465 } 1466 } 1467 } else { 1468 PetscInt locMinMax[2]; 1469 1470 locMinMax[0] = Nc[0] + Nc[1]; 1471 locMinMax[1] = Nc[0] + Nc[1]; 1472 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1473 locMinMax[0] = Nc[1]; 1474 locMinMax[1] = Nc[1]; 1475 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1476 if (d == depth) { 1477 locMinMax[0] = gcNum; 1478 locMinMax[1] = gcNum; 1479 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1480 } 1481 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1482 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1483 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1484 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1485 } 1486 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1487 } 1488 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1489 { 1490 const PetscReal *maxCell; 1491 const PetscReal *L; 1492 PetscBool localized; 1493 1494 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1495 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1496 if (L || localized) { 1497 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1498 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1499 if (L) { 1500 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1501 for (d = 0; d < dim; ++d) { 1502 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1503 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1504 } 1505 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1506 } 1507 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1508 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1509 } 1510 } 1511 PetscCall(DMGetNumLabels(dm, &numLabels)); 1512 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1513 for (l = 0; l < numLabels; ++l) { 1514 DMLabel label; 1515 const char *name; 1516 IS valueIS; 1517 const PetscInt *values; 1518 PetscInt numValues, v; 1519 1520 PetscCall(DMGetLabelName(dm, l, &name)); 1521 PetscCall(DMGetLabel(dm, name, &label)); 1522 PetscCall(DMLabelGetNumValues(label, &numValues)); 1523 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1524 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1525 PetscCall(ISGetIndices(valueIS, &values)); 1526 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1527 for (v = 0; v < numValues; ++v) { 1528 PetscInt size; 1529 1530 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1531 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1532 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1533 } 1534 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1535 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1536 PetscCall(ISRestoreIndices(valueIS, &values)); 1537 PetscCall(ISDestroy(&valueIS)); 1538 } 1539 { 1540 char **labelNames; 1541 PetscInt Nl = numLabels; 1542 PetscBool flg; 1543 1544 PetscCall(PetscMalloc1(Nl, &labelNames)); 1545 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1546 for (l = 0; l < Nl; ++l) { 1547 DMLabel label; 1548 1549 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1550 if (flg) { 1551 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1552 PetscCall(DMLabelView(label, viewer)); 1553 } 1554 PetscCall(PetscFree(labelNames[l])); 1555 } 1556 PetscCall(PetscFree(labelNames)); 1557 } 1558 /* If no fields are specified, people do not want to see adjacency */ 1559 if (dm->Nf) { 1560 PetscInt f; 1561 1562 for (f = 0; f < dm->Nf; ++f) { 1563 const char *name; 1564 1565 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1566 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1567 PetscCall(PetscViewerASCIIPushTab(viewer)); 1568 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1569 if (dm->fields[f].adjacency[0]) { 1570 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1571 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1572 } else { 1573 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1574 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1575 } 1576 PetscCall(PetscViewerASCIIPopTab(viewer)); 1577 } 1578 } 1579 PetscCall(DMGetCoarseDM(dm, &cdm)); 1580 if (cdm) { 1581 PetscCall(PetscViewerASCIIPushTab(viewer)); 1582 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1583 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1584 PetscCall(PetscViewerASCIIPopTab(viewer)); 1585 } 1586 } 1587 PetscFunctionReturn(PETSC_SUCCESS); 1588 } 1589 1590 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1591 { 1592 DMPolytopeType ct; 1593 PetscMPIInt rank; 1594 PetscInt cdim; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1600 switch (ct) { 1601 case DM_POLYTOPE_SEGMENT: 1602 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1603 switch (cdim) { 1604 case 1: { 1605 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1606 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1607 1608 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1609 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1610 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1611 } break; 1612 case 2: { 1613 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1614 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1615 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1616 1617 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1618 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1619 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1620 } break; 1621 default: 1622 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1623 } 1624 break; 1625 case DM_POLYTOPE_TRIANGLE: 1626 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1627 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1628 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1629 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1630 break; 1631 case DM_POLYTOPE_QUADRILATERAL: 1632 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1633 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1634 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1635 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1636 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1637 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1638 break; 1639 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1640 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1641 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1642 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1643 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1644 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1645 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1646 break; 1647 case DM_POLYTOPE_FV_GHOST: 1648 break; 1649 default: 1650 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1651 } 1652 PetscFunctionReturn(PETSC_SUCCESS); 1653 } 1654 1655 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1656 { 1657 DMPolytopeType ct; 1658 PetscReal centroid[2] = {0., 0.}; 1659 PetscMPIInt rank; 1660 PetscInt fillColor, v, e, d; 1661 1662 PetscFunctionBegin; 1663 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1664 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1665 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1666 switch (ct) { 1667 case DM_POLYTOPE_TRIANGLE: { 1668 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1669 1670 for (v = 0; v < 3; ++v) { 1671 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1672 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1673 } 1674 for (e = 0; e < 3; ++e) { 1675 refCoords[0] = refVertices[e * 2 + 0]; 1676 refCoords[1] = refVertices[e * 2 + 1]; 1677 for (d = 1; d <= edgeDiv; ++d) { 1678 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1679 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1680 } 1681 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1682 for (d = 0; d < edgeDiv; ++d) { 1683 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1684 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1685 } 1686 } 1687 } break; 1688 default: 1689 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1690 } 1691 PetscFunctionReturn(PETSC_SUCCESS); 1692 } 1693 1694 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1695 { 1696 PetscDraw draw; 1697 DM cdm; 1698 PetscSection coordSection; 1699 Vec coordinates; 1700 PetscReal xyl[3], xyr[3]; 1701 PetscReal *refCoords, *edgeCoords; 1702 PetscBool isnull, drawAffine = PETSC_TRUE; 1703 PetscInt dim, vStart, vEnd, cStart, cEnd, c, edgeDiv = 4; 1704 1705 PetscFunctionBegin; 1706 PetscCall(DMGetCoordinateDim(dm, &dim)); 1707 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1708 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1709 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1710 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1711 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1712 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1713 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1714 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1715 1716 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1717 PetscCall(PetscDrawIsNull(draw, &isnull)); 1718 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 1719 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1720 1721 PetscCall(DMGetBoundingBox(dm, xyl, xyr)); 1722 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1723 PetscCall(PetscDrawClear(draw)); 1724 1725 for (c = cStart; c < cEnd; ++c) { 1726 PetscScalar *coords = NULL; 1727 const PetscScalar *coords_arr; 1728 PetscInt numCoords; 1729 PetscBool isDG; 1730 1731 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1732 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1733 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1734 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &coords_arr, &coords)); 1735 } 1736 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1737 PetscCall(PetscDrawFlush(draw)); 1738 PetscCall(PetscDrawPause(draw)); 1739 PetscCall(PetscDrawSave(draw)); 1740 PetscFunctionReturn(PETSC_SUCCESS); 1741 } 1742 1743 #if defined(PETSC_HAVE_EXODUSII) 1744 #include <exodusII.h> 1745 #include <petscviewerexodusii.h> 1746 #endif 1747 1748 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1749 { 1750 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1751 char name[PETSC_MAX_PATH_LEN]; 1752 1753 PetscFunctionBegin; 1754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1755 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1756 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1757 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1758 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1759 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1760 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1761 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1762 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1763 if (iascii) { 1764 PetscViewerFormat format; 1765 PetscCall(PetscViewerGetFormat(viewer, &format)); 1766 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1767 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1768 } else if (ishdf5) { 1769 #if defined(PETSC_HAVE_HDF5) 1770 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1771 #else 1772 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1773 #endif 1774 } else if (isvtk) { 1775 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1776 } else if (isdraw) { 1777 PetscCall(DMPlexView_Draw(dm, viewer)); 1778 } else if (isglvis) { 1779 PetscCall(DMPlexView_GLVis(dm, viewer)); 1780 #if defined(PETSC_HAVE_EXODUSII) 1781 } else if (isexodus) { 1782 /* 1783 exodusII requires that all sets be part of exactly one cell set. 1784 If the dm does not have a "Cell Sets" label defined, we create one 1785 with ID 1, containing all cells. 1786 Note that if the Cell Sets label is defined but does not cover all cells, 1787 we may still have a problem. This should probably be checked here or in the viewer; 1788 */ 1789 PetscInt numCS; 1790 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1791 if (!numCS) { 1792 PetscInt cStart, cEnd, c; 1793 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1794 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1795 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1796 } 1797 PetscCall(DMView_PlexExodusII(dm, viewer)); 1798 #endif 1799 #if defined(PETSC_HAVE_CGNS) 1800 } else if (iscgns) { 1801 PetscCall(DMView_PlexCGNS(dm, viewer)); 1802 #endif 1803 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1804 /* Optionally view the partition */ 1805 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1806 if (flg) { 1807 Vec ranks; 1808 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1809 PetscCall(VecView(ranks, viewer)); 1810 PetscCall(VecDestroy(&ranks)); 1811 } 1812 /* Optionally view a label */ 1813 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1814 if (flg) { 1815 DMLabel label; 1816 Vec val; 1817 1818 PetscCall(DMGetLabel(dm, name, &label)); 1819 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1820 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1821 PetscCall(VecView(val, viewer)); 1822 PetscCall(VecDestroy(&val)); 1823 } 1824 PetscFunctionReturn(PETSC_SUCCESS); 1825 } 1826 1827 /*@ 1828 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1829 1830 Collective 1831 1832 Input Parameters: 1833 + dm - The `DM` whose topology is to be saved 1834 - viewer - The `PetscViewer` to save it in 1835 1836 Level: advanced 1837 1838 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1839 @*/ 1840 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1841 { 1842 PetscBool ishdf5; 1843 1844 PetscFunctionBegin; 1845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1846 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1848 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1849 if (ishdf5) { 1850 #if defined(PETSC_HAVE_HDF5) 1851 PetscViewerFormat format; 1852 PetscCall(PetscViewerGetFormat(viewer, &format)); 1853 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1854 IS globalPointNumbering; 1855 1856 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1857 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1858 PetscCall(ISDestroy(&globalPointNumbering)); 1859 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1860 #else 1861 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1862 #endif 1863 } 1864 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1865 PetscFunctionReturn(PETSC_SUCCESS); 1866 } 1867 1868 /*@ 1869 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1870 1871 Collective 1872 1873 Input Parameters: 1874 + dm - The `DM` whose coordinates are to be saved 1875 - viewer - The `PetscViewer` for saving 1876 1877 Level: advanced 1878 1879 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1880 @*/ 1881 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1882 { 1883 PetscBool ishdf5; 1884 1885 PetscFunctionBegin; 1886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1887 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1888 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1889 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1890 if (ishdf5) { 1891 #if defined(PETSC_HAVE_HDF5) 1892 PetscViewerFormat format; 1893 PetscCall(PetscViewerGetFormat(viewer, &format)); 1894 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1895 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1896 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1897 #else 1898 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1899 #endif 1900 } 1901 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1902 PetscFunctionReturn(PETSC_SUCCESS); 1903 } 1904 1905 /*@ 1906 DMPlexLabelsView - Saves `DMPLEX` labels into a file 1907 1908 Collective 1909 1910 Input Parameters: 1911 + dm - The `DM` whose labels are to be saved 1912 - viewer - The `PetscViewer` for saving 1913 1914 Level: advanced 1915 1916 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 1917 @*/ 1918 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1919 { 1920 PetscBool ishdf5; 1921 1922 PetscFunctionBegin; 1923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1924 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1925 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1926 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1927 if (ishdf5) { 1928 #if defined(PETSC_HAVE_HDF5) 1929 IS globalPointNumbering; 1930 PetscViewerFormat format; 1931 1932 PetscCall(PetscViewerGetFormat(viewer, &format)); 1933 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1934 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1935 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1936 PetscCall(ISDestroy(&globalPointNumbering)); 1937 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1938 #else 1939 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1940 #endif 1941 } 1942 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1943 PetscFunctionReturn(PETSC_SUCCESS); 1944 } 1945 1946 /*@ 1947 DMPlexSectionView - Saves a section associated with a `DMPLEX` 1948 1949 Collective 1950 1951 Input Parameters: 1952 + dm - The `DM` that contains the topology on which the section to be saved is defined 1953 . viewer - The `PetscViewer` for saving 1954 - sectiondm - The `DM` that contains the section to be saved 1955 1956 Level: advanced 1957 1958 Notes: 1959 This function is a wrapper around `PetscSectionView()`; in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with `DMPlexTopologyLoad()` and `DMPlexSectionLoad()`, respectively, this information is used to match section points with topology points. 1960 1961 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1962 1963 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 1964 @*/ 1965 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1966 { 1967 PetscBool ishdf5; 1968 1969 PetscFunctionBegin; 1970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1971 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1972 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1973 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1974 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1975 if (ishdf5) { 1976 #if defined(PETSC_HAVE_HDF5) 1977 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1978 #else 1979 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1980 #endif 1981 } 1982 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1983 PetscFunctionReturn(PETSC_SUCCESS); 1984 } 1985 1986 /*@ 1987 DMPlexGlobalVectorView - Saves a global vector 1988 1989 Collective 1990 1991 Input Parameters: 1992 + dm - The `DM` that represents the topology 1993 . viewer - The `PetscViewer` to save data with 1994 . sectiondm - The `DM` that contains the global section on which vec is defined 1995 - vec - The global vector to be saved 1996 1997 Level: advanced 1998 1999 Notes: 2000 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2001 2002 Typical calling sequence: 2003 .vb 2004 DMCreate(PETSC_COMM_WORLD, &dm); 2005 DMSetType(dm, DMPLEX); 2006 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2007 DMClone(dm, §iondm); 2008 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2009 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2010 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2011 PetscSectionSetChart(section, pStart, pEnd); 2012 PetscSectionSetUp(section); 2013 DMSetLocalSection(sectiondm, section); 2014 PetscSectionDestroy(§ion); 2015 DMGetGlobalVector(sectiondm, &vec); 2016 PetscObjectSetName((PetscObject)vec, "vec_name"); 2017 DMPlexTopologyView(dm, viewer); 2018 DMPlexSectionView(dm, viewer, sectiondm); 2019 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2020 DMRestoreGlobalVector(sectiondm, &vec); 2021 DMDestroy(§iondm); 2022 DMDestroy(&dm); 2023 .ve 2024 2025 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2026 @*/ 2027 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2028 { 2029 PetscBool ishdf5; 2030 2031 PetscFunctionBegin; 2032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2033 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2034 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2035 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2036 /* Check consistency */ 2037 { 2038 PetscSection section; 2039 PetscBool includesConstraints; 2040 PetscInt m, m1; 2041 2042 PetscCall(VecGetLocalSize(vec, &m1)); 2043 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2044 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2045 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2046 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2047 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2048 } 2049 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2050 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2051 if (ishdf5) { 2052 #if defined(PETSC_HAVE_HDF5) 2053 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2054 #else 2055 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2056 #endif 2057 } 2058 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2059 PetscFunctionReturn(PETSC_SUCCESS); 2060 } 2061 2062 /*@ 2063 DMPlexLocalVectorView - Saves a local vector 2064 2065 Collective 2066 2067 Input Parameters: 2068 + dm - The `DM` that represents the topology 2069 . viewer - The `PetscViewer` to save data with 2070 . sectiondm - The `DM` that contains the local section on which `vec` is defined; may be the same as `dm` 2071 - vec - The local vector to be saved 2072 2073 Level: advanced 2074 2075 Note: 2076 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2077 2078 Typical calling sequence: 2079 .vb 2080 DMCreate(PETSC_COMM_WORLD, &dm); 2081 DMSetType(dm, DMPLEX); 2082 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2083 DMClone(dm, §iondm); 2084 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2085 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2086 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2087 PetscSectionSetChart(section, pStart, pEnd); 2088 PetscSectionSetUp(section); 2089 DMSetLocalSection(sectiondm, section); 2090 DMGetLocalVector(sectiondm, &vec); 2091 PetscObjectSetName((PetscObject)vec, "vec_name"); 2092 DMPlexTopologyView(dm, viewer); 2093 DMPlexSectionView(dm, viewer, sectiondm); 2094 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2095 DMRestoreLocalVector(sectiondm, &vec); 2096 DMDestroy(§iondm); 2097 DMDestroy(&dm); 2098 .ve 2099 2100 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2101 @*/ 2102 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2103 { 2104 PetscBool ishdf5; 2105 2106 PetscFunctionBegin; 2107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2108 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2109 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2110 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2111 /* Check consistency */ 2112 { 2113 PetscSection section; 2114 PetscBool includesConstraints; 2115 PetscInt m, m1; 2116 2117 PetscCall(VecGetLocalSize(vec, &m1)); 2118 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2119 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2120 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2121 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2122 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2123 } 2124 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2125 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2126 if (ishdf5) { 2127 #if defined(PETSC_HAVE_HDF5) 2128 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2129 #else 2130 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2131 #endif 2132 } 2133 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2134 PetscFunctionReturn(PETSC_SUCCESS); 2135 } 2136 2137 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2138 { 2139 PetscBool ishdf5; 2140 2141 PetscFunctionBegin; 2142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2143 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2144 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2145 if (ishdf5) { 2146 #if defined(PETSC_HAVE_HDF5) 2147 PetscViewerFormat format; 2148 PetscCall(PetscViewerGetFormat(viewer, &format)); 2149 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2150 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2151 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2152 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2153 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2154 PetscFunctionReturn(PETSC_SUCCESS); 2155 #else 2156 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2157 #endif 2158 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2159 } 2160 2161 /*@ 2162 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2163 2164 Collective 2165 2166 Input Parameters: 2167 + dm - The `DM` into which the topology is loaded 2168 - viewer - The `PetscViewer` for the saved topology 2169 2170 Output Parameter: 2171 . globalToLocalPointSF - The `PetscSF` that pushes points in [0, N) to the associated points in the loaded `DMPLEX`, where N is the global number of points; `NULL` if unneeded 2172 2173 Level: advanced 2174 2175 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2176 `PetscViewer`, `PetscSF` 2177 @*/ 2178 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2179 { 2180 PetscBool ishdf5; 2181 2182 PetscFunctionBegin; 2183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2184 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2185 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2186 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2187 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2188 if (ishdf5) { 2189 #if defined(PETSC_HAVE_HDF5) 2190 PetscViewerFormat format; 2191 PetscCall(PetscViewerGetFormat(viewer, &format)); 2192 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2193 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2194 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2195 #else 2196 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2197 #endif 2198 } 2199 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2200 PetscFunctionReturn(PETSC_SUCCESS); 2201 } 2202 2203 /*@ 2204 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2205 2206 Collective 2207 2208 Input Parameters: 2209 + dm - The `DM` into which the coordinates are loaded 2210 . viewer - The `PetscViewer` for the saved coordinates 2211 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2212 2213 Level: advanced 2214 2215 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2216 `PetscSF`, `PetscViewer` 2217 @*/ 2218 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2219 { 2220 PetscBool ishdf5; 2221 2222 PetscFunctionBegin; 2223 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2224 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2225 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2226 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2227 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2228 if (ishdf5) { 2229 #if defined(PETSC_HAVE_HDF5) 2230 PetscViewerFormat format; 2231 PetscCall(PetscViewerGetFormat(viewer, &format)); 2232 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2233 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2234 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2235 #else 2236 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2237 #endif 2238 } 2239 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2240 PetscFunctionReturn(PETSC_SUCCESS); 2241 } 2242 2243 /*@ 2244 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2245 2246 Collective 2247 2248 Input Parameters: 2249 + dm - The `DM` into which the labels are loaded 2250 . viewer - The `PetscViewer` for the saved labels 2251 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading `dm` from viewer 2252 2253 Level: advanced 2254 2255 Note: 2256 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2257 2258 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2259 `PetscSF`, `PetscViewer` 2260 @*/ 2261 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2262 { 2263 PetscBool ishdf5; 2264 2265 PetscFunctionBegin; 2266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2267 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2268 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2269 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2270 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2271 if (ishdf5) { 2272 #if defined(PETSC_HAVE_HDF5) 2273 PetscViewerFormat format; 2274 2275 PetscCall(PetscViewerGetFormat(viewer, &format)); 2276 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2277 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2278 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2279 #else 2280 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2281 #endif 2282 } 2283 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2284 PetscFunctionReturn(PETSC_SUCCESS); 2285 } 2286 2287 /*@ 2288 DMPlexSectionLoad - Loads section into a `DMPLEX` 2289 2290 Collective 2291 2292 Input Parameters: 2293 + dm - The `DM` that represents the topology 2294 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2295 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2296 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2297 2298 Output Parameters 2299 + globalDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a global `Vec` associated with the `sectiondm`'s global section (`NULL` if not needed) 2300 - localDofSF - The `PetscSF` that migrates any on-disk `Vec` data associated with sectionA into a local `Vec` associated with the `sectiondm`'s local section (`NULL` if not needed) 2301 2302 Level: advanced 2303 2304 Notes: 2305 This function is a wrapper around `PetscSectionLoad()`; it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in `dm`. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2306 2307 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2308 2309 The output parameter, `globalDofSF` (`localDofSF`), can later be used with `DMPlexGlobalVectorLoad()` (`DMPlexLocalVectorLoad()`) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2310 2311 Example using 2 processes: 2312 .vb 2313 NX (number of points on dm): 4 2314 sectionA : the on-disk section 2315 vecA : a vector associated with sectionA 2316 sectionB : sectiondm's local section constructed in this function 2317 vecB (local) : a vector associated with sectiondm's local section 2318 vecB (global) : a vector associated with sectiondm's global section 2319 2320 rank 0 rank 1 2321 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2322 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2323 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2324 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2325 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2326 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2327 sectionB->atlasDof : 1 0 1 | 1 3 2328 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2329 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2330 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2331 .ve 2332 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2333 2334 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2335 @*/ 2336 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2337 { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2344 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2345 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2346 if (localDofSF) PetscValidPointer(localDofSF, 6); 2347 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2348 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2349 if (ishdf5) { 2350 #if defined(PETSC_HAVE_HDF5) 2351 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2352 #else 2353 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2354 #endif 2355 } 2356 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2357 PetscFunctionReturn(PETSC_SUCCESS); 2358 } 2359 2360 /*@ 2361 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2362 2363 Collective 2364 2365 Input Parameters: 2366 + dm - The `DM` that represents the topology 2367 . viewer - The `PetscViewer` that represents the on-disk vector data 2368 . sectiondm - The `DM` that contains the global section on which vec is defined 2369 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2370 - vec - The global vector to set values of 2371 2372 Level: advanced 2373 2374 Notes: 2375 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2376 2377 Typical calling sequence: 2378 .vb 2379 DMCreate(PETSC_COMM_WORLD, &dm); 2380 DMSetType(dm, DMPLEX); 2381 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2382 DMPlexTopologyLoad(dm, viewer, &sfX); 2383 DMClone(dm, §iondm); 2384 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2385 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2386 DMGetGlobalVector(sectiondm, &vec); 2387 PetscObjectSetName((PetscObject)vec, "vec_name"); 2388 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2389 DMRestoreGlobalVector(sectiondm, &vec); 2390 PetscSFDestroy(&gsf); 2391 PetscSFDestroy(&sfX); 2392 DMDestroy(§iondm); 2393 DMDestroy(&dm); 2394 .ve 2395 2396 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2397 `PetscSF`, `PetscViewer` 2398 @*/ 2399 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2400 { 2401 PetscBool ishdf5; 2402 2403 PetscFunctionBegin; 2404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2405 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2406 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2407 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2408 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2409 /* Check consistency */ 2410 { 2411 PetscSection section; 2412 PetscBool includesConstraints; 2413 PetscInt m, m1; 2414 2415 PetscCall(VecGetLocalSize(vec, &m1)); 2416 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2417 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2418 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2419 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2420 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2421 } 2422 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2423 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2424 if (ishdf5) { 2425 #if defined(PETSC_HAVE_HDF5) 2426 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2427 #else 2428 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2429 #endif 2430 } 2431 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2432 PetscFunctionReturn(PETSC_SUCCESS); 2433 } 2434 2435 /*@ 2436 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2437 2438 Collective 2439 2440 Input Parameters: 2441 + dm - The `DM` that represents the topology 2442 . viewer - The `PetscViewer` that represents the on-disk vector data 2443 . sectiondm - The `DM` that contains the local section on which vec is defined 2444 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2445 - vec - The local vector to set values of 2446 2447 Level: advanced 2448 2449 Notes: 2450 In general `dm` and `sectiondm` are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with `PetscObjectSetName()`. In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2451 2452 Typical calling sequence: 2453 .vb 2454 DMCreate(PETSC_COMM_WORLD, &dm); 2455 DMSetType(dm, DMPLEX); 2456 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2457 DMPlexTopologyLoad(dm, viewer, &sfX); 2458 DMClone(dm, §iondm); 2459 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2460 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2461 DMGetLocalVector(sectiondm, &vec); 2462 PetscObjectSetName((PetscObject)vec, "vec_name"); 2463 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2464 DMRestoreLocalVector(sectiondm, &vec); 2465 PetscSFDestroy(&lsf); 2466 PetscSFDestroy(&sfX); 2467 DMDestroy(§iondm); 2468 DMDestroy(&dm); 2469 .ve 2470 2471 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2472 `PetscSF`, `PetscViewer` 2473 @*/ 2474 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2475 { 2476 PetscBool ishdf5; 2477 2478 PetscFunctionBegin; 2479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2480 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2481 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2482 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2483 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2484 /* Check consistency */ 2485 { 2486 PetscSection section; 2487 PetscBool includesConstraints; 2488 PetscInt m, m1; 2489 2490 PetscCall(VecGetLocalSize(vec, &m1)); 2491 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2492 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2493 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2494 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2495 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2496 } 2497 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2498 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2499 if (ishdf5) { 2500 #if defined(PETSC_HAVE_HDF5) 2501 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2502 #else 2503 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2504 #endif 2505 } 2506 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2507 PetscFunctionReturn(PETSC_SUCCESS); 2508 } 2509 2510 PetscErrorCode DMDestroy_Plex(DM dm) 2511 { 2512 DM_Plex *mesh = (DM_Plex *)dm->data; 2513 2514 PetscFunctionBegin; 2515 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2516 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2517 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2518 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2519 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2520 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2521 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2522 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2523 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2524 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2525 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2526 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2527 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2528 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2529 if (--mesh->refct > 0) PetscFunctionReturn(PETSC_SUCCESS); 2530 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2531 PetscCall(PetscFree(mesh->cones)); 2532 PetscCall(PetscFree(mesh->coneOrientations)); 2533 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2534 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2535 PetscCall(PetscFree(mesh->supports)); 2536 PetscCall(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 Parameter: 2689 . subsection - The subdomain section 2690 2691 Level: developer 2692 2693 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `PetscSection` 2694 @*/ 2695 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2696 { 2697 DM_Plex *mesh = (DM_Plex *)dm->data; 2698 2699 PetscFunctionBegin; 2700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2701 if (!mesh->subdomainSection) { 2702 PetscSection section; 2703 PetscSF sf; 2704 2705 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2706 PetscCall(DMGetLocalSection(dm, §ion)); 2707 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2708 PetscCall(PetscSFDestroy(&sf)); 2709 } 2710 *subsection = mesh->subdomainSection; 2711 PetscFunctionReturn(PETSC_SUCCESS); 2712 } 2713 2714 /*@ 2715 DMPlexGetChart - Return the interval for all mesh points [`pStart`, `pEnd`) 2716 2717 Not Collective 2718 2719 Input Parameter: 2720 . mesh - The `DMPLEX` 2721 2722 Output Parameters: 2723 + pStart - The first mesh point 2724 - pEnd - The upper bound for mesh points 2725 2726 Level: beginner 2727 2728 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2729 @*/ 2730 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2731 { 2732 DM_Plex *mesh = (DM_Plex *)dm->data; 2733 2734 PetscFunctionBegin; 2735 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2736 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2737 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2738 PetscFunctionReturn(PETSC_SUCCESS); 2739 } 2740 2741 /*@ 2742 DMPlexSetChart - Set the interval for all mesh points [`pStart`, `pEnd`) 2743 2744 Not Collective 2745 2746 Input Parameters: 2747 + mesh - The `DMPLEX` 2748 . pStart - The first mesh point 2749 - pEnd - The upper bound for mesh points 2750 2751 Level: beginner 2752 2753 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2754 @*/ 2755 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2756 { 2757 DM_Plex *mesh = (DM_Plex *)dm->data; 2758 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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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 PetscCall(MPIU_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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 Parameter: 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: [](ch_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 Parameter: 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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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: [](ch_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 Parameter: 5260 . dm - The `DMPLEX` object 5261 5262 Output Parameter: 5263 . section - The `PetscSection` object 5264 5265 Level: developer 5266 5267 .seealso: [](ch_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 Parameter: 5285 . dm - The `DMPLEX` object 5286 5287 Output Parameter: 5288 . section - The `PetscSection` object 5289 5290 Level: developer 5291 5292 .seealso: [](ch_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 Parameter: 5310 . dm - The `DMPLEX` object 5311 5312 Output Parameter: 5313 . cones - The cone for each point 5314 5315 Level: developer 5316 5317 .seealso: [](ch_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 Parameter: 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: [](ch_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: [](ch_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 ornt, 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 (!ornt && *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_Internal(dm, point, ornt, 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 PetscErrorCode DMPlexVecGetOrientedClosure_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt ornt, PetscInt *csize, PetscScalar *values[]) 5957 { 5958 PetscSection clSection; 5959 IS clPoints; 5960 PetscInt *points = NULL; 5961 const PetscInt *clp, *perm; 5962 PetscInt depth, numFields, numPoints, asize; 5963 5964 PetscFunctionBeginHot; 5965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5966 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5967 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5968 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5969 PetscCall(DMPlexGetDepth(dm, &depth)); 5970 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5971 if (depth == 1 && numFields < 2) { 5972 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5973 PetscFunctionReturn(PETSC_SUCCESS); 5974 } 5975 /* Get points */ 5976 PetscCall(DMPlexGetCompressedClosure(dm, section, point, ornt, &numPoints, &points, &clSection, &clPoints, &clp)); 5977 /* Get sizes */ 5978 asize = 0; 5979 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5980 PetscInt dof; 5981 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5982 asize += dof; 5983 } 5984 if (values) { 5985 const PetscScalar *vArray; 5986 PetscInt size; 5987 5988 if (*values) { 5989 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); 5990 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5991 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5992 PetscCall(VecGetArrayRead(v, &vArray)); 5993 /* Get values */ 5994 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5995 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5996 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5997 /* Cleanup array */ 5998 PetscCall(VecRestoreArrayRead(v, &vArray)); 5999 } 6000 if (csize) *csize = asize; 6001 /* Cleanup points */ 6002 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6003 PetscFunctionReturn(PETSC_SUCCESS); 6004 } 6005 6006 /*@C 6007 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 6008 6009 Not collective 6010 6011 Input Parameters: 6012 + dm - The `DM` 6013 . section - The section describing the layout in `v`, or `NULL` to use the default section 6014 . v - The local vector 6015 - point - The point in the `DM` 6016 6017 Input/Output Parameters: 6018 + csize - The size of the input values array, or `NULL`; on output the number of values in the closure 6019 - values - An array to use for the values, or `NULL` to have it allocated automatically; 6020 if the user provided `NULL`, it is a borrowed array and should not be freed 6021 6022 Level: intermediate 6023 6024 Notes: 6025 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to `NULL` in the 6026 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 6027 assembly function, and a user may already have allocated storage for this operation. 6028 6029 A typical use could be 6030 .vb 6031 values = NULL; 6032 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6033 for (cl = 0; cl < clSize; ++cl) { 6034 <Compute on closure> 6035 } 6036 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 6037 .ve 6038 or 6039 .vb 6040 PetscMalloc1(clMaxSize, &values); 6041 for (p = pStart; p < pEnd; ++p) { 6042 clSize = clMaxSize; 6043 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 6044 for (cl = 0; cl < clSize; ++cl) { 6045 <Compute on closure> 6046 } 6047 } 6048 PetscFree(values); 6049 .ve 6050 6051 Fortran Note: 6052 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6053 6054 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6055 @*/ 6056 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6057 { 6058 PetscFunctionBeginHot; 6059 PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, section, v, point, 0, csize, values)); 6060 PetscFunctionReturn(PETSC_SUCCESS); 6061 } 6062 6063 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6064 { 6065 DMLabel depthLabel; 6066 PetscSection clSection; 6067 IS clPoints; 6068 PetscScalar *array; 6069 const PetscScalar *vArray; 6070 PetscInt *points = NULL; 6071 const PetscInt *clp, *perm = NULL; 6072 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6073 6074 PetscFunctionBeginHot; 6075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6076 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6077 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6078 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6079 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6080 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6081 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6082 if (mdepth == 1 && numFields < 2) { 6083 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6084 PetscFunctionReturn(PETSC_SUCCESS); 6085 } 6086 /* Get points */ 6087 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6088 for (clsize = 0, p = 0; p < Np; p++) { 6089 PetscInt dof; 6090 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6091 clsize += dof; 6092 } 6093 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6094 /* Filter points */ 6095 for (p = 0; p < numPoints * 2; p += 2) { 6096 PetscInt dep; 6097 6098 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6099 if (dep != depth) continue; 6100 points[Np * 2 + 0] = points[p]; 6101 points[Np * 2 + 1] = points[p + 1]; 6102 ++Np; 6103 } 6104 /* Get array */ 6105 if (!values || !*values) { 6106 PetscInt asize = 0, dof; 6107 6108 for (p = 0; p < Np * 2; p += 2) { 6109 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6110 asize += dof; 6111 } 6112 if (!values) { 6113 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6114 if (csize) *csize = asize; 6115 PetscFunctionReturn(PETSC_SUCCESS); 6116 } 6117 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6118 } else { 6119 array = *values; 6120 } 6121 PetscCall(VecGetArrayRead(v, &vArray)); 6122 /* Get values */ 6123 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6124 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6125 /* Cleanup points */ 6126 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6127 /* Cleanup array */ 6128 PetscCall(VecRestoreArrayRead(v, &vArray)); 6129 if (!*values) { 6130 if (csize) *csize = size; 6131 *values = array; 6132 } else { 6133 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6134 *csize = size; 6135 } 6136 PetscFunctionReturn(PETSC_SUCCESS); 6137 } 6138 6139 /*@C 6140 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6141 6142 Not collective 6143 6144 Input Parameters: 6145 + dm - The `DM` 6146 . section - The section describing the layout in `v`, or `NULL` to use the default section 6147 . v - The local vector 6148 . point - The point in the `DM` 6149 . csize - The number of values in the closure, or `NULL` 6150 - values - The array of values, which is a borrowed array and should not be freed 6151 6152 Level: intermediate 6153 6154 Note: 6155 The array values are discarded and not copied back into `v`. In order to copy values back to `v`, use `DMPlexVecSetClosure()` 6156 6157 Fortran Note: 6158 The `csize` argument is not present in the Fortran binding since it is internal to the array. 6159 6160 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6161 @*/ 6162 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6163 { 6164 PetscInt size = 0; 6165 6166 PetscFunctionBegin; 6167 /* Should work without recalculating size */ 6168 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6169 *values = NULL; 6170 PetscFunctionReturn(PETSC_SUCCESS); 6171 } 6172 6173 static inline void add(PetscScalar *x, PetscScalar y) 6174 { 6175 *x += y; 6176 } 6177 static inline void insert(PetscScalar *x, PetscScalar y) 6178 { 6179 *x = y; 6180 } 6181 6182 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[]) 6183 { 6184 PetscInt cdof; /* The number of constraints on this point */ 6185 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6186 PetscScalar *a; 6187 PetscInt off, cind = 0, k; 6188 6189 PetscFunctionBegin; 6190 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6191 PetscCall(PetscSectionGetOffset(section, point, &off)); 6192 a = &array[off]; 6193 if (!cdof || setBC) { 6194 if (clperm) { 6195 if (perm) { 6196 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6197 } else { 6198 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6199 } 6200 } else { 6201 if (perm) { 6202 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6203 } else { 6204 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6205 } 6206 } 6207 } else { 6208 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6209 if (clperm) { 6210 if (perm) { 6211 for (k = 0; k < dof; ++k) { 6212 if ((cind < cdof) && (k == cdofs[cind])) { 6213 ++cind; 6214 continue; 6215 } 6216 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6217 } 6218 } else { 6219 for (k = 0; k < dof; ++k) { 6220 if ((cind < cdof) && (k == cdofs[cind])) { 6221 ++cind; 6222 continue; 6223 } 6224 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6225 } 6226 } 6227 } else { 6228 if (perm) { 6229 for (k = 0; k < dof; ++k) { 6230 if ((cind < cdof) && (k == cdofs[cind])) { 6231 ++cind; 6232 continue; 6233 } 6234 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6235 } 6236 } else { 6237 for (k = 0; k < dof; ++k) { 6238 if ((cind < cdof) && (k == cdofs[cind])) { 6239 ++cind; 6240 continue; 6241 } 6242 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6243 } 6244 } 6245 } 6246 } 6247 PetscFunctionReturn(PETSC_SUCCESS); 6248 } 6249 6250 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[]) 6251 { 6252 PetscInt cdof; /* The number of constraints on this point */ 6253 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6254 PetscScalar *a; 6255 PetscInt off, cind = 0, k; 6256 6257 PetscFunctionBegin; 6258 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6259 PetscCall(PetscSectionGetOffset(section, point, &off)); 6260 a = &array[off]; 6261 if (cdof) { 6262 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6263 if (clperm) { 6264 if (perm) { 6265 for (k = 0; k < dof; ++k) { 6266 if ((cind < cdof) && (k == cdofs[cind])) { 6267 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6268 cind++; 6269 } 6270 } 6271 } else { 6272 for (k = 0; k < dof; ++k) { 6273 if ((cind < cdof) && (k == cdofs[cind])) { 6274 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6275 cind++; 6276 } 6277 } 6278 } 6279 } else { 6280 if (perm) { 6281 for (k = 0; k < dof; ++k) { 6282 if ((cind < cdof) && (k == cdofs[cind])) { 6283 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6284 cind++; 6285 } 6286 } 6287 } else { 6288 for (k = 0; k < dof; ++k) { 6289 if ((cind < cdof) && (k == cdofs[cind])) { 6290 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6291 cind++; 6292 } 6293 } 6294 } 6295 } 6296 } 6297 PetscFunctionReturn(PETSC_SUCCESS); 6298 } 6299 6300 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[]) 6301 { 6302 PetscScalar *a; 6303 PetscInt fdof, foff, fcdof, foffset = *offset; 6304 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6305 PetscInt cind = 0, b; 6306 6307 PetscFunctionBegin; 6308 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6309 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6310 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6311 a = &array[foff]; 6312 if (!fcdof || setBC) { 6313 if (clperm) { 6314 if (perm) { 6315 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6316 } else { 6317 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6318 } 6319 } else { 6320 if (perm) { 6321 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6322 } else { 6323 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6324 } 6325 } 6326 } else { 6327 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6328 if (clperm) { 6329 if (perm) { 6330 for (b = 0; b < fdof; b++) { 6331 if ((cind < fcdof) && (b == fcdofs[cind])) { 6332 ++cind; 6333 continue; 6334 } 6335 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6336 } 6337 } else { 6338 for (b = 0; b < fdof; b++) { 6339 if ((cind < fcdof) && (b == fcdofs[cind])) { 6340 ++cind; 6341 continue; 6342 } 6343 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6344 } 6345 } 6346 } else { 6347 if (perm) { 6348 for (b = 0; b < fdof; b++) { 6349 if ((cind < fcdof) && (b == fcdofs[cind])) { 6350 ++cind; 6351 continue; 6352 } 6353 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6354 } 6355 } else { 6356 for (b = 0; b < fdof; b++) { 6357 if ((cind < fcdof) && (b == fcdofs[cind])) { 6358 ++cind; 6359 continue; 6360 } 6361 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6362 } 6363 } 6364 } 6365 } 6366 *offset += fdof; 6367 PetscFunctionReturn(PETSC_SUCCESS); 6368 } 6369 6370 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[]) 6371 { 6372 PetscScalar *a; 6373 PetscInt fdof, foff, fcdof, foffset = *offset; 6374 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6375 PetscInt Nc, cind = 0, ncind = 0, b; 6376 PetscBool ncSet, fcSet; 6377 6378 PetscFunctionBegin; 6379 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6380 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6381 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6382 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6383 a = &array[foff]; 6384 if (fcdof) { 6385 /* We just override fcdof and fcdofs with Ncc and comps */ 6386 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6387 if (clperm) { 6388 if (perm) { 6389 if (comps) { 6390 for (b = 0; b < fdof; b++) { 6391 ncSet = fcSet = PETSC_FALSE; 6392 if (b % Nc == comps[ncind]) { 6393 ncind = (ncind + 1) % Ncc; 6394 ncSet = PETSC_TRUE; 6395 } 6396 if ((cind < fcdof) && (b == fcdofs[cind])) { 6397 ++cind; 6398 fcSet = PETSC_TRUE; 6399 } 6400 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6401 } 6402 } else { 6403 for (b = 0; b < fdof; b++) { 6404 if ((cind < fcdof) && (b == fcdofs[cind])) { 6405 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6406 ++cind; 6407 } 6408 } 6409 } 6410 } else { 6411 if (comps) { 6412 for (b = 0; b < fdof; b++) { 6413 ncSet = fcSet = PETSC_FALSE; 6414 if (b % Nc == comps[ncind]) { 6415 ncind = (ncind + 1) % Ncc; 6416 ncSet = PETSC_TRUE; 6417 } 6418 if ((cind < fcdof) && (b == fcdofs[cind])) { 6419 ++cind; 6420 fcSet = PETSC_TRUE; 6421 } 6422 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6423 } 6424 } else { 6425 for (b = 0; b < fdof; b++) { 6426 if ((cind < fcdof) && (b == fcdofs[cind])) { 6427 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6428 ++cind; 6429 } 6430 } 6431 } 6432 } 6433 } else { 6434 if (perm) { 6435 if (comps) { 6436 for (b = 0; b < fdof; b++) { 6437 ncSet = fcSet = PETSC_FALSE; 6438 if (b % Nc == comps[ncind]) { 6439 ncind = (ncind + 1) % Ncc; 6440 ncSet = PETSC_TRUE; 6441 } 6442 if ((cind < fcdof) && (b == fcdofs[cind])) { 6443 ++cind; 6444 fcSet = PETSC_TRUE; 6445 } 6446 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6447 } 6448 } else { 6449 for (b = 0; b < fdof; b++) { 6450 if ((cind < fcdof) && (b == fcdofs[cind])) { 6451 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6452 ++cind; 6453 } 6454 } 6455 } 6456 } else { 6457 if (comps) { 6458 for (b = 0; b < fdof; b++) { 6459 ncSet = fcSet = PETSC_FALSE; 6460 if (b % Nc == comps[ncind]) { 6461 ncind = (ncind + 1) % Ncc; 6462 ncSet = PETSC_TRUE; 6463 } 6464 if ((cind < fcdof) && (b == fcdofs[cind])) { 6465 ++cind; 6466 fcSet = PETSC_TRUE; 6467 } 6468 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6469 } 6470 } else { 6471 for (b = 0; b < fdof; b++) { 6472 if ((cind < fcdof) && (b == fcdofs[cind])) { 6473 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6474 ++cind; 6475 } 6476 } 6477 } 6478 } 6479 } 6480 } 6481 *offset += fdof; 6482 PetscFunctionReturn(PETSC_SUCCESS); 6483 } 6484 6485 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6486 { 6487 PetscScalar *array; 6488 const PetscInt *cone, *coneO; 6489 PetscInt pStart, pEnd, p, numPoints, off, dof; 6490 6491 PetscFunctionBeginHot; 6492 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6493 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6494 PetscCall(DMPlexGetCone(dm, point, &cone)); 6495 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6496 PetscCall(VecGetArray(v, &array)); 6497 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6498 const PetscInt cp = !p ? point : cone[p - 1]; 6499 const PetscInt o = !p ? 0 : coneO[p - 1]; 6500 6501 if ((cp < pStart) || (cp >= pEnd)) { 6502 dof = 0; 6503 continue; 6504 } 6505 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6506 /* ADD_VALUES */ 6507 { 6508 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6509 PetscScalar *a; 6510 PetscInt cdof, coff, cind = 0, k; 6511 6512 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6513 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6514 a = &array[coff]; 6515 if (!cdof) { 6516 if (o >= 0) { 6517 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6518 } else { 6519 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6520 } 6521 } else { 6522 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6523 if (o >= 0) { 6524 for (k = 0; k < dof; ++k) { 6525 if ((cind < cdof) && (k == cdofs[cind])) { 6526 ++cind; 6527 continue; 6528 } 6529 a[k] += values[off + k]; 6530 } 6531 } else { 6532 for (k = 0; k < dof; ++k) { 6533 if ((cind < cdof) && (k == cdofs[cind])) { 6534 ++cind; 6535 continue; 6536 } 6537 a[k] += values[off + dof - k - 1]; 6538 } 6539 } 6540 } 6541 } 6542 } 6543 PetscCall(VecRestoreArray(v, &array)); 6544 PetscFunctionReturn(PETSC_SUCCESS); 6545 } 6546 6547 /*@C 6548 DMPlexVecSetClosure - Set an array of the values on the closure of `point` 6549 6550 Not collective 6551 6552 Input Parameters: 6553 + dm - The `DM` 6554 . section - The section describing the layout in `v`, or `NULL` to use the default section 6555 . v - The local vector 6556 . point - The point in the `DM` 6557 . values - The array of values 6558 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6559 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6560 6561 Level: intermediate 6562 6563 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6564 @*/ 6565 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6566 { 6567 PetscSection clSection; 6568 IS clPoints; 6569 PetscScalar *array; 6570 PetscInt *points = NULL; 6571 const PetscInt *clp, *clperm = NULL; 6572 PetscInt depth, numFields, numPoints, p, clsize; 6573 6574 PetscFunctionBeginHot; 6575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6576 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6577 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6578 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6579 PetscCall(DMPlexGetDepth(dm, &depth)); 6580 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6581 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6582 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6583 PetscFunctionReturn(PETSC_SUCCESS); 6584 } 6585 /* Get points */ 6586 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6587 for (clsize = 0, p = 0; p < numPoints; p++) { 6588 PetscInt dof; 6589 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6590 clsize += dof; 6591 } 6592 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6593 /* Get array */ 6594 PetscCall(VecGetArray(v, &array)); 6595 /* Get values */ 6596 if (numFields > 0) { 6597 PetscInt offset = 0, f; 6598 for (f = 0; f < numFields; ++f) { 6599 const PetscInt **perms = NULL; 6600 const PetscScalar **flips = NULL; 6601 6602 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6603 switch (mode) { 6604 case INSERT_VALUES: 6605 for (p = 0; p < numPoints; p++) { 6606 const PetscInt point = points[2 * p]; 6607 const PetscInt *perm = perms ? perms[p] : NULL; 6608 const PetscScalar *flip = flips ? flips[p] : NULL; 6609 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array)); 6610 } 6611 break; 6612 case INSERT_ALL_VALUES: 6613 for (p = 0; p < numPoints; p++) { 6614 const PetscInt point = points[2 * p]; 6615 const PetscInt *perm = perms ? perms[p] : NULL; 6616 const PetscScalar *flip = flips ? flips[p] : NULL; 6617 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array)); 6618 } 6619 break; 6620 case INSERT_BC_VALUES: 6621 for (p = 0; p < numPoints; p++) { 6622 const PetscInt point = points[2 * p]; 6623 const PetscInt *perm = perms ? perms[p] : NULL; 6624 const PetscScalar *flip = flips ? flips[p] : NULL; 6625 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array)); 6626 } 6627 break; 6628 case ADD_VALUES: 6629 for (p = 0; p < numPoints; p++) { 6630 const PetscInt point = points[2 * p]; 6631 const PetscInt *perm = perms ? perms[p] : NULL; 6632 const PetscScalar *flip = flips ? flips[p] : NULL; 6633 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array)); 6634 } 6635 break; 6636 case ADD_ALL_VALUES: 6637 for (p = 0; p < numPoints; p++) { 6638 const PetscInt point = points[2 * p]; 6639 const PetscInt *perm = perms ? perms[p] : NULL; 6640 const PetscScalar *flip = flips ? flips[p] : NULL; 6641 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array)); 6642 } 6643 break; 6644 case ADD_BC_VALUES: 6645 for (p = 0; p < numPoints; p++) { 6646 const PetscInt point = points[2 * p]; 6647 const PetscInt *perm = perms ? perms[p] : NULL; 6648 const PetscScalar *flip = flips ? flips[p] : NULL; 6649 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array)); 6650 } 6651 break; 6652 default: 6653 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6654 } 6655 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6656 } 6657 } else { 6658 PetscInt dof, off; 6659 const PetscInt **perms = NULL; 6660 const PetscScalar **flips = NULL; 6661 6662 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6663 switch (mode) { 6664 case INSERT_VALUES: 6665 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6666 const PetscInt point = points[2 * p]; 6667 const PetscInt *perm = perms ? perms[p] : NULL; 6668 const PetscScalar *flip = flips ? flips[p] : NULL; 6669 PetscCall(PetscSectionGetDof(section, point, &dof)); 6670 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6671 } 6672 break; 6673 case INSERT_ALL_VALUES: 6674 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6675 const PetscInt point = points[2 * p]; 6676 const PetscInt *perm = perms ? perms[p] : NULL; 6677 const PetscScalar *flip = flips ? flips[p] : NULL; 6678 PetscCall(PetscSectionGetDof(section, point, &dof)); 6679 PetscCall(updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6680 } 6681 break; 6682 case INSERT_BC_VALUES: 6683 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6684 const PetscInt point = points[2 * p]; 6685 const PetscInt *perm = perms ? perms[p] : NULL; 6686 const PetscScalar *flip = flips ? flips[p] : NULL; 6687 PetscCall(PetscSectionGetDof(section, point, &dof)); 6688 PetscCall(updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array)); 6689 } 6690 break; 6691 case ADD_VALUES: 6692 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6693 const PetscInt point = points[2 * p]; 6694 const PetscInt *perm = perms ? perms[p] : NULL; 6695 const PetscScalar *flip = flips ? flips[p] : NULL; 6696 PetscCall(PetscSectionGetDof(section, point, &dof)); 6697 PetscCall(updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array)); 6698 } 6699 break; 6700 case ADD_ALL_VALUES: 6701 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6702 const PetscInt point = points[2 * p]; 6703 const PetscInt *perm = perms ? perms[p] : NULL; 6704 const PetscScalar *flip = flips ? flips[p] : NULL; 6705 PetscCall(PetscSectionGetDof(section, point, &dof)); 6706 PetscCall(updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array)); 6707 } 6708 break; 6709 case ADD_BC_VALUES: 6710 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6711 const PetscInt point = points[2 * p]; 6712 const PetscInt *perm = perms ? perms[p] : NULL; 6713 const PetscScalar *flip = flips ? flips[p] : NULL; 6714 PetscCall(PetscSectionGetDof(section, point, &dof)); 6715 PetscCall(updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array)); 6716 } 6717 break; 6718 default: 6719 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6720 } 6721 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6722 } 6723 /* Cleanup points */ 6724 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6725 /* Cleanup array */ 6726 PetscCall(VecRestoreArray(v, &array)); 6727 PetscFunctionReturn(PETSC_SUCCESS); 6728 } 6729 6730 PetscErrorCode DMPlexVecSetStar(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6731 { 6732 const PetscInt *supp, *cone; 6733 PetscScalar *a; 6734 PetscInt dim, Ns, dof, off, n = 0; 6735 6736 PetscFunctionBegin; 6737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6738 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6739 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6740 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6741 if (PetscDefined(USE_DEBUG)) { 6742 PetscInt vStart, vEnd; 6743 6744 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6745 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); 6746 } 6747 PetscValidScalarPointer(values, 5); 6748 6749 PetscCall(DMGetDimension(dm, &dim)); 6750 PetscCall(DMPlexGetSupportSize(dm, point, &Ns)); 6751 PetscCall(DMPlexGetSupport(dm, point, &supp)); 6752 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); 6753 PetscCall(VecGetArray(v, &a)); 6754 PetscCall(PetscSectionGetDof(section, point, &dof)); 6755 PetscCall(PetscSectionGetOffset(section, point, &off)); 6756 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6757 for (PetscInt d = 0; d < dim; ++d) { 6758 // Left edge 6759 PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone)); 6760 PetscCall(PetscSectionGetDof(section, cone[0], &dof)); 6761 PetscCall(PetscSectionGetOffset(section, cone[0], &off)); 6762 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6763 // Right edge 6764 PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone)); 6765 PetscCall(PetscSectionGetDof(section, cone[1], &dof)); 6766 PetscCall(PetscSectionGetOffset(section, cone[1], &off)); 6767 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6768 } 6769 PetscCall(VecRestoreArray(v, &a)); 6770 PetscFunctionReturn(PETSC_SUCCESS); 6771 } 6772 6773 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6774 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6775 { 6776 PetscFunctionBegin; 6777 *contains = PETSC_TRUE; 6778 if (label) { 6779 PetscInt fdof; 6780 6781 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6782 if (!*contains) { 6783 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6784 *offset += fdof; 6785 PetscFunctionReturn(PETSC_SUCCESS); 6786 } 6787 } 6788 PetscFunctionReturn(PETSC_SUCCESS); 6789 } 6790 6791 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6792 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) 6793 { 6794 PetscSection clSection; 6795 IS clPoints; 6796 PetscScalar *array; 6797 PetscInt *points = NULL; 6798 const PetscInt *clp; 6799 PetscInt numFields, numPoints, p; 6800 PetscInt offset = 0, f; 6801 6802 PetscFunctionBeginHot; 6803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6804 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6805 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6806 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6807 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6808 /* Get points */ 6809 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &numPoints, &points, &clSection, &clPoints, &clp)); 6810 /* Get array */ 6811 PetscCall(VecGetArray(v, &array)); 6812 /* Get values */ 6813 for (f = 0; f < numFields; ++f) { 6814 const PetscInt **perms = NULL; 6815 const PetscScalar **flips = NULL; 6816 PetscBool contains; 6817 6818 if (!fieldActive[f]) { 6819 for (p = 0; p < numPoints * 2; p += 2) { 6820 PetscInt fdof; 6821 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6822 offset += fdof; 6823 } 6824 continue; 6825 } 6826 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6827 switch (mode) { 6828 case INSERT_VALUES: 6829 for (p = 0; p < numPoints; p++) { 6830 const PetscInt point = points[2 * p]; 6831 const PetscInt *perm = perms ? perms[p] : NULL; 6832 const PetscScalar *flip = flips ? flips[p] : NULL; 6833 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6834 if (!contains) continue; 6835 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6836 } 6837 break; 6838 case INSERT_ALL_VALUES: 6839 for (p = 0; p < numPoints; p++) { 6840 const PetscInt point = points[2 * p]; 6841 const PetscInt *perm = perms ? perms[p] : NULL; 6842 const PetscScalar *flip = flips ? flips[p] : NULL; 6843 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6844 if (!contains) continue; 6845 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6846 } 6847 break; 6848 case INSERT_BC_VALUES: 6849 for (p = 0; p < numPoints; p++) { 6850 const PetscInt point = points[2 * p]; 6851 const PetscInt *perm = perms ? perms[p] : NULL; 6852 const PetscScalar *flip = flips ? flips[p] : NULL; 6853 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6854 if (!contains) continue; 6855 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6856 } 6857 break; 6858 case ADD_VALUES: 6859 for (p = 0; p < numPoints; p++) { 6860 const PetscInt point = points[2 * p]; 6861 const PetscInt *perm = perms ? perms[p] : NULL; 6862 const PetscScalar *flip = flips ? flips[p] : NULL; 6863 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6864 if (!contains) continue; 6865 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6866 } 6867 break; 6868 case ADD_ALL_VALUES: 6869 for (p = 0; p < numPoints; p++) { 6870 const PetscInt point = points[2 * p]; 6871 const PetscInt *perm = perms ? perms[p] : NULL; 6872 const PetscScalar *flip = flips ? flips[p] : NULL; 6873 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6874 if (!contains) continue; 6875 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6876 } 6877 break; 6878 default: 6879 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6880 } 6881 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6882 } 6883 /* Cleanup points */ 6884 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6885 /* Cleanup array */ 6886 PetscCall(VecRestoreArray(v, &array)); 6887 PetscFunctionReturn(PETSC_SUCCESS); 6888 } 6889 6890 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6891 { 6892 PetscMPIInt rank; 6893 PetscInt i, j; 6894 6895 PetscFunctionBegin; 6896 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6897 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6898 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6899 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6900 numCIndices = numCIndices ? numCIndices : numRIndices; 6901 if (!values) PetscFunctionReturn(PETSC_SUCCESS); 6902 for (i = 0; i < numRIndices; i++) { 6903 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6904 for (j = 0; j < numCIndices; j++) { 6905 #if defined(PETSC_USE_COMPLEX) 6906 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6907 #else 6908 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6909 #endif 6910 } 6911 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6912 } 6913 PetscFunctionReturn(PETSC_SUCCESS); 6914 } 6915 6916 /* 6917 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6918 6919 Input Parameters: 6920 + section - The section for this data layout 6921 . islocal - Is the section (and thus indices being requested) local or global? 6922 . point - The point contributing dofs with these indices 6923 . off - The global offset of this point 6924 . loff - The local offset of each field 6925 . setBC - The flag determining whether to include indices of boundary values 6926 . perm - A permutation of the dofs on this point, or NULL 6927 - indperm - A permutation of the entire indices array, or NULL 6928 6929 Output Parameter: 6930 . indices - Indices for dofs on this point 6931 6932 Level: developer 6933 6934 Note: The indices could be local or global, depending on the value of 'off'. 6935 */ 6936 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6937 { 6938 PetscInt dof; /* The number of unknowns on this point */ 6939 PetscInt cdof; /* The number of constraints on this point */ 6940 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6941 PetscInt cind = 0, k; 6942 6943 PetscFunctionBegin; 6944 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6945 PetscCall(PetscSectionGetDof(section, point, &dof)); 6946 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6947 if (!cdof || setBC) { 6948 for (k = 0; k < dof; ++k) { 6949 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6950 const PetscInt ind = indperm ? indperm[preind] : preind; 6951 6952 indices[ind] = off + k; 6953 } 6954 } else { 6955 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6956 for (k = 0; k < dof; ++k) { 6957 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6958 const PetscInt ind = indperm ? indperm[preind] : preind; 6959 6960 if ((cind < cdof) && (k == cdofs[cind])) { 6961 /* Insert check for returning constrained indices */ 6962 indices[ind] = -(off + k + 1); 6963 ++cind; 6964 } else { 6965 indices[ind] = off + k - (islocal ? 0 : cind); 6966 } 6967 } 6968 } 6969 *loff += dof; 6970 PetscFunctionReturn(PETSC_SUCCESS); 6971 } 6972 6973 /* 6974 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6975 6976 Input Parameters: 6977 + section - a section (global or local) 6978 - islocal - `PETSC_TRUE` if requesting local indices (i.e., section is local); `PETSC_FALSE` for global 6979 . point - point within section 6980 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6981 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6982 . setBC - identify constrained (boundary condition) points via involution. 6983 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6984 . permsoff - offset 6985 - indperm - index permutation 6986 6987 Output Parameter: 6988 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6989 . indices - array to hold indices (as defined by section) of each dof associated with point 6990 6991 Notes: 6992 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6993 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6994 in the local vector. 6995 6996 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6997 significant). It is invalid to call with a global section and setBC=true. 6998 6999 Developer Note: 7000 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 7001 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 7002 offset could be obtained from the section instead of passing it explicitly as we do now. 7003 7004 Example: 7005 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 7006 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 7007 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 7008 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. 7009 7010 Level: developer 7011 */ 7012 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[]) 7013 { 7014 PetscInt numFields, foff, f; 7015 7016 PetscFunctionBegin; 7017 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7018 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7019 for (f = 0, foff = 0; f < numFields; ++f) { 7020 PetscInt fdof, cfdof; 7021 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7022 PetscInt cind = 0, b; 7023 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7024 7025 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7026 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7027 if (!cfdof || setBC) { 7028 for (b = 0; b < fdof; ++b) { 7029 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7030 const PetscInt ind = indperm ? indperm[preind] : preind; 7031 7032 indices[ind] = off + foff + b; 7033 } 7034 } else { 7035 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7036 for (b = 0; b < fdof; ++b) { 7037 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7038 const PetscInt ind = indperm ? indperm[preind] : preind; 7039 7040 if ((cind < cfdof) && (b == fcdofs[cind])) { 7041 indices[ind] = -(off + foff + b + 1); 7042 ++cind; 7043 } else { 7044 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7045 } 7046 } 7047 } 7048 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7049 foffs[f] += fdof; 7050 } 7051 PetscFunctionReturn(PETSC_SUCCESS); 7052 } 7053 7054 /* 7055 This version believes the globalSection offsets for each field, rather than just the point offset 7056 7057 . foffs - The offset into 'indices' for each field, since it is segregated by field 7058 7059 Notes: 7060 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7061 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7062 */ 7063 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7064 { 7065 PetscInt numFields, foff, f; 7066 7067 PetscFunctionBegin; 7068 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7069 for (f = 0; f < numFields; ++f) { 7070 PetscInt fdof, cfdof; 7071 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7072 PetscInt cind = 0, b; 7073 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7074 7075 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7076 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7077 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7078 if (!cfdof) { 7079 for (b = 0; b < fdof; ++b) { 7080 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7081 const PetscInt ind = indperm ? indperm[preind] : preind; 7082 7083 indices[ind] = foff + b; 7084 } 7085 } else { 7086 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7087 for (b = 0; b < fdof; ++b) { 7088 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7089 const PetscInt ind = indperm ? indperm[preind] : preind; 7090 7091 if ((cind < cfdof) && (b == fcdofs[cind])) { 7092 indices[ind] = -(foff + b + 1); 7093 ++cind; 7094 } else { 7095 indices[ind] = foff + b - cind; 7096 } 7097 } 7098 } 7099 foffs[f] += fdof; 7100 } 7101 PetscFunctionReturn(PETSC_SUCCESS); 7102 } 7103 7104 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) 7105 { 7106 Mat cMat; 7107 PetscSection aSec, cSec; 7108 IS aIS; 7109 PetscInt aStart = -1, aEnd = -1; 7110 const PetscInt *anchors; 7111 PetscInt numFields, f, p, q, newP = 0; 7112 PetscInt newNumPoints = 0, newNumIndices = 0; 7113 PetscInt *newPoints, *indices, *newIndices; 7114 PetscInt maxAnchor, maxDof; 7115 PetscInt newOffsets[32]; 7116 PetscInt *pointMatOffsets[32]; 7117 PetscInt *newPointOffsets[32]; 7118 PetscScalar *pointMat[32]; 7119 PetscScalar *newValues = NULL, *tmpValues; 7120 PetscBool anyConstrained = PETSC_FALSE; 7121 7122 PetscFunctionBegin; 7123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7124 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7125 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7126 7127 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7128 /* if there are point-to-point constraints */ 7129 if (aSec) { 7130 PetscCall(PetscArrayzero(newOffsets, 32)); 7131 PetscCall(ISGetIndices(aIS, &anchors)); 7132 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7133 /* figure out how many points are going to be in the new element matrix 7134 * (we allow double counting, because it's all just going to be summed 7135 * into the global matrix anyway) */ 7136 for (p = 0; p < 2 * numPoints; p += 2) { 7137 PetscInt b = points[p]; 7138 PetscInt bDof = 0, bSecDof; 7139 7140 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7141 if (!bSecDof) continue; 7142 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7143 if (bDof) { 7144 /* this point is constrained */ 7145 /* it is going to be replaced by its anchors */ 7146 PetscInt bOff, q; 7147 7148 anyConstrained = PETSC_TRUE; 7149 newNumPoints += bDof; 7150 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7151 for (q = 0; q < bDof; q++) { 7152 PetscInt a = anchors[bOff + q]; 7153 PetscInt aDof; 7154 7155 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7156 newNumIndices += aDof; 7157 for (f = 0; f < numFields; ++f) { 7158 PetscInt fDof; 7159 7160 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7161 newOffsets[f + 1] += fDof; 7162 } 7163 } 7164 } else { 7165 /* this point is not constrained */ 7166 newNumPoints++; 7167 newNumIndices += bSecDof; 7168 for (f = 0; f < numFields; ++f) { 7169 PetscInt fDof; 7170 7171 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7172 newOffsets[f + 1] += fDof; 7173 } 7174 } 7175 } 7176 } 7177 if (!anyConstrained) { 7178 if (outNumPoints) *outNumPoints = 0; 7179 if (outNumIndices) *outNumIndices = 0; 7180 if (outPoints) *outPoints = NULL; 7181 if (outValues) *outValues = NULL; 7182 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7183 PetscFunctionReturn(PETSC_SUCCESS); 7184 } 7185 7186 if (outNumPoints) *outNumPoints = newNumPoints; 7187 if (outNumIndices) *outNumIndices = newNumIndices; 7188 7189 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7190 7191 if (!outPoints && !outValues) { 7192 if (offsets) { 7193 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7194 } 7195 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7196 PetscFunctionReturn(PETSC_SUCCESS); 7197 } 7198 7199 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7200 7201 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7202 7203 /* workspaces */ 7204 if (numFields) { 7205 for (f = 0; f < numFields; f++) { 7206 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7207 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7208 } 7209 } else { 7210 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7211 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7212 } 7213 7214 /* get workspaces for the point-to-point matrices */ 7215 if (numFields) { 7216 PetscInt totalOffset, totalMatOffset; 7217 7218 for (p = 0; p < numPoints; p++) { 7219 PetscInt b = points[2 * p]; 7220 PetscInt bDof = 0, bSecDof; 7221 7222 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7223 if (!bSecDof) { 7224 for (f = 0; f < numFields; f++) { 7225 newPointOffsets[f][p + 1] = 0; 7226 pointMatOffsets[f][p + 1] = 0; 7227 } 7228 continue; 7229 } 7230 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7231 if (bDof) { 7232 for (f = 0; f < numFields; f++) { 7233 PetscInt fDof, q, bOff, allFDof = 0; 7234 7235 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7236 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7237 for (q = 0; q < bDof; q++) { 7238 PetscInt a = anchors[bOff + q]; 7239 PetscInt aFDof; 7240 7241 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7242 allFDof += aFDof; 7243 } 7244 newPointOffsets[f][p + 1] = allFDof; 7245 pointMatOffsets[f][p + 1] = fDof * allFDof; 7246 } 7247 } else { 7248 for (f = 0; f < numFields; f++) { 7249 PetscInt fDof; 7250 7251 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7252 newPointOffsets[f][p + 1] = fDof; 7253 pointMatOffsets[f][p + 1] = 0; 7254 } 7255 } 7256 } 7257 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7258 newPointOffsets[f][0] = totalOffset; 7259 pointMatOffsets[f][0] = totalMatOffset; 7260 for (p = 0; p < numPoints; p++) { 7261 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7262 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7263 } 7264 totalOffset = newPointOffsets[f][numPoints]; 7265 totalMatOffset = pointMatOffsets[f][numPoints]; 7266 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7267 } 7268 } else { 7269 for (p = 0; p < numPoints; p++) { 7270 PetscInt b = points[2 * p]; 7271 PetscInt bDof = 0, bSecDof; 7272 7273 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7274 if (!bSecDof) { 7275 newPointOffsets[0][p + 1] = 0; 7276 pointMatOffsets[0][p + 1] = 0; 7277 continue; 7278 } 7279 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7280 if (bDof) { 7281 PetscInt bOff, q, allDof = 0; 7282 7283 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7284 for (q = 0; q < bDof; q++) { 7285 PetscInt a = anchors[bOff + q], aDof; 7286 7287 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7288 allDof += aDof; 7289 } 7290 newPointOffsets[0][p + 1] = allDof; 7291 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7292 } else { 7293 newPointOffsets[0][p + 1] = bSecDof; 7294 pointMatOffsets[0][p + 1] = 0; 7295 } 7296 } 7297 newPointOffsets[0][0] = 0; 7298 pointMatOffsets[0][0] = 0; 7299 for (p = 0; p < numPoints; p++) { 7300 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7301 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7302 } 7303 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7304 } 7305 7306 /* output arrays */ 7307 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7308 7309 /* get the point-to-point matrices; construct newPoints */ 7310 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7311 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7312 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7313 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7314 if (numFields) { 7315 for (p = 0, newP = 0; p < numPoints; p++) { 7316 PetscInt b = points[2 * p]; 7317 PetscInt o = points[2 * p + 1]; 7318 PetscInt bDof = 0, bSecDof; 7319 7320 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7321 if (!bSecDof) continue; 7322 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7323 if (bDof) { 7324 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7325 7326 fStart[0] = 0; 7327 fEnd[0] = 0; 7328 for (f = 0; f < numFields; f++) { 7329 PetscInt fDof; 7330 7331 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7332 fStart[f + 1] = fStart[f] + fDof; 7333 fEnd[f + 1] = fStart[f + 1]; 7334 } 7335 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7336 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7337 7338 fAnchorStart[0] = 0; 7339 fAnchorEnd[0] = 0; 7340 for (f = 0; f < numFields; f++) { 7341 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7342 7343 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7344 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7345 } 7346 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7347 for (q = 0; q < bDof; q++) { 7348 PetscInt a = anchors[bOff + q], aOff; 7349 7350 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7351 newPoints[2 * (newP + q)] = a; 7352 newPoints[2 * (newP + q) + 1] = 0; 7353 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7354 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7355 } 7356 newP += bDof; 7357 7358 if (outValues) { 7359 /* get the point-to-point submatrix */ 7360 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])); 7361 } 7362 } else { 7363 newPoints[2 * newP] = b; 7364 newPoints[2 * newP + 1] = o; 7365 newP++; 7366 } 7367 } 7368 } else { 7369 for (p = 0; p < numPoints; p++) { 7370 PetscInt b = points[2 * p]; 7371 PetscInt o = points[2 * p + 1]; 7372 PetscInt bDof = 0, bSecDof; 7373 7374 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7375 if (!bSecDof) continue; 7376 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7377 if (bDof) { 7378 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7379 7380 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7381 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7382 7383 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7384 for (q = 0; q < bDof; q++) { 7385 PetscInt a = anchors[bOff + q], aOff; 7386 7387 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7388 7389 newPoints[2 * (newP + q)] = a; 7390 newPoints[2 * (newP + q) + 1] = 0; 7391 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7392 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7393 } 7394 newP += bDof; 7395 7396 /* get the point-to-point submatrix */ 7397 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7398 } else { 7399 newPoints[2 * newP] = b; 7400 newPoints[2 * newP + 1] = o; 7401 newP++; 7402 } 7403 } 7404 } 7405 7406 if (outValues) { 7407 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7408 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7409 /* multiply constraints on the right */ 7410 if (numFields) { 7411 for (f = 0; f < numFields; f++) { 7412 PetscInt oldOff = offsets[f]; 7413 7414 for (p = 0; p < numPoints; p++) { 7415 PetscInt cStart = newPointOffsets[f][p]; 7416 PetscInt b = points[2 * p]; 7417 PetscInt c, r, k; 7418 PetscInt dof; 7419 7420 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7421 if (!dof) continue; 7422 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7423 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7424 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7425 7426 for (r = 0; r < numIndices; r++) { 7427 for (c = 0; c < nCols; c++) { 7428 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7429 } 7430 } 7431 } else { 7432 /* copy this column as is */ 7433 for (r = 0; r < numIndices; r++) { 7434 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7435 } 7436 } 7437 oldOff += dof; 7438 } 7439 } 7440 } else { 7441 PetscInt oldOff = 0; 7442 for (p = 0; p < numPoints; p++) { 7443 PetscInt cStart = newPointOffsets[0][p]; 7444 PetscInt b = points[2 * p]; 7445 PetscInt c, r, k; 7446 PetscInt dof; 7447 7448 PetscCall(PetscSectionGetDof(section, b, &dof)); 7449 if (!dof) continue; 7450 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7451 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7452 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7453 7454 for (r = 0; r < numIndices; r++) { 7455 for (c = 0; c < nCols; c++) { 7456 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7457 } 7458 } 7459 } else { 7460 /* copy this column as is */ 7461 for (r = 0; r < numIndices; r++) { 7462 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7463 } 7464 } 7465 oldOff += dof; 7466 } 7467 } 7468 7469 if (multiplyLeft) { 7470 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7471 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7472 /* multiply constraints transpose on the left */ 7473 if (numFields) { 7474 for (f = 0; f < numFields; f++) { 7475 PetscInt oldOff = offsets[f]; 7476 7477 for (p = 0; p < numPoints; p++) { 7478 PetscInt rStart = newPointOffsets[f][p]; 7479 PetscInt b = points[2 * p]; 7480 PetscInt c, r, k; 7481 PetscInt dof; 7482 7483 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7484 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7485 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7486 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7487 7488 for (r = 0; r < nRows; r++) { 7489 for (c = 0; c < newNumIndices; c++) { 7490 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7491 } 7492 } 7493 } else { 7494 /* copy this row as is */ 7495 for (r = 0; r < dof; r++) { 7496 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7497 } 7498 } 7499 oldOff += dof; 7500 } 7501 } 7502 } else { 7503 PetscInt oldOff = 0; 7504 7505 for (p = 0; p < numPoints; p++) { 7506 PetscInt rStart = newPointOffsets[0][p]; 7507 PetscInt b = points[2 * p]; 7508 PetscInt c, r, k; 7509 PetscInt dof; 7510 7511 PetscCall(PetscSectionGetDof(section, b, &dof)); 7512 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7513 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7514 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7515 7516 for (r = 0; r < nRows; r++) { 7517 for (c = 0; c < newNumIndices; c++) { 7518 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7519 } 7520 } 7521 } else { 7522 /* copy this row as is */ 7523 for (r = 0; r < dof; r++) { 7524 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7525 } 7526 } 7527 oldOff += dof; 7528 } 7529 } 7530 7531 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7532 } else { 7533 newValues = tmpValues; 7534 } 7535 } 7536 7537 /* clean up */ 7538 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7539 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7540 7541 if (numFields) { 7542 for (f = 0; f < numFields; f++) { 7543 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7544 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7545 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7546 } 7547 } else { 7548 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7549 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7550 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7551 } 7552 PetscCall(ISRestoreIndices(aIS, &anchors)); 7553 7554 /* output */ 7555 if (outPoints) { 7556 *outPoints = newPoints; 7557 } else { 7558 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7559 } 7560 if (outValues) *outValues = newValues; 7561 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7562 PetscFunctionReturn(PETSC_SUCCESS); 7563 } 7564 7565 /*@C 7566 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7567 7568 Not collective 7569 7570 Input Parameters: 7571 + dm - The `DM` 7572 . section - The `PetscSection` describing the points (a local section) 7573 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7574 . point - The point defining the closure 7575 - useClPerm - Use the closure point permutation if available 7576 7577 Output Parameters: 7578 + numIndices - The number of dof indices in the closure of point with the input sections 7579 . indices - The dof indices 7580 . outOffsets - Array to write the field offsets into, or `NULL` 7581 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7582 7583 Level: advanced 7584 7585 Notes: 7586 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7587 7588 If `idxSection` is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7589 of those indices is not significant. If `idxSection` is local, the constrained dofs will yield the involution -(idx+1) 7590 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7591 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when `idxSection` == section, otherwise global 7592 indices (with the above semantics) are implied. 7593 7594 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7595 `PetscSection`, `DMGetGlobalSection()` 7596 @*/ 7597 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7598 { 7599 /* Closure ordering */ 7600 PetscSection clSection; 7601 IS clPoints; 7602 const PetscInt *clp; 7603 PetscInt *points; 7604 const PetscInt *clperm = NULL; 7605 /* Dof permutation and sign flips */ 7606 const PetscInt **perms[32] = {NULL}; 7607 const PetscScalar **flips[32] = {NULL}; 7608 PetscScalar *valCopy = NULL; 7609 /* Hanging node constraints */ 7610 PetscInt *pointsC = NULL; 7611 PetscScalar *valuesC = NULL; 7612 PetscInt NclC, NiC; 7613 7614 PetscInt *idx; 7615 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7616 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7617 7618 PetscFunctionBeginHot; 7619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7620 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7621 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7622 if (numIndices) PetscValidIntPointer(numIndices, 6); 7623 if (indices) PetscValidPointer(indices, 7); 7624 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7625 if (values) PetscValidPointer(values, 9); 7626 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7627 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7628 PetscCall(PetscArrayzero(offsets, 32)); 7629 /* 1) Get points in closure */ 7630 PetscCall(DMPlexGetCompressedClosure(dm, section, point, 0, &Ncl, &points, &clSection, &clPoints, &clp)); 7631 if (useClPerm) { 7632 PetscInt depth, clsize; 7633 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7634 for (clsize = 0, p = 0; p < Ncl; p++) { 7635 PetscInt dof; 7636 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7637 clsize += dof; 7638 } 7639 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7640 } 7641 /* 2) Get number of indices on these points and field offsets from section */ 7642 for (p = 0; p < Ncl * 2; p += 2) { 7643 PetscInt dof, fdof; 7644 7645 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7646 for (f = 0; f < Nf; ++f) { 7647 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7648 offsets[f + 1] += fdof; 7649 } 7650 Ni += dof; 7651 } 7652 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7653 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7654 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7655 for (f = 0; f < PetscMax(1, Nf); ++f) { 7656 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7657 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7658 /* may need to apply sign changes to the element matrix */ 7659 if (values && flips[f]) { 7660 PetscInt foffset = offsets[f]; 7661 7662 for (p = 0; p < Ncl; ++p) { 7663 PetscInt pnt = points[2 * p], fdof; 7664 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7665 7666 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7667 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7668 if (flip) { 7669 PetscInt i, j, k; 7670 7671 if (!valCopy) { 7672 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7673 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7674 *values = valCopy; 7675 } 7676 for (i = 0; i < fdof; ++i) { 7677 PetscScalar fval = flip[i]; 7678 7679 for (k = 0; k < Ni; ++k) { 7680 valCopy[Ni * (foffset + i) + k] *= fval; 7681 valCopy[Ni * k + (foffset + i)] *= fval; 7682 } 7683 } 7684 } 7685 foffset += fdof; 7686 } 7687 } 7688 } 7689 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7690 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7691 if (NclC) { 7692 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7693 for (f = 0; f < PetscMax(1, Nf); ++f) { 7694 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7695 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7696 } 7697 for (f = 0; f < PetscMax(1, Nf); ++f) { 7698 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7699 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7700 } 7701 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7702 Ncl = NclC; 7703 Ni = NiC; 7704 points = pointsC; 7705 if (values) *values = valuesC; 7706 } 7707 /* 5) Calculate indices */ 7708 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7709 if (Nf) { 7710 PetscInt idxOff; 7711 PetscBool useFieldOffsets; 7712 7713 if (outOffsets) { 7714 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7715 } 7716 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7717 if (useFieldOffsets) { 7718 for (p = 0; p < Ncl; ++p) { 7719 const PetscInt pnt = points[p * 2]; 7720 7721 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7722 } 7723 } else { 7724 for (p = 0; p < Ncl; ++p) { 7725 const PetscInt pnt = points[p * 2]; 7726 7727 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7728 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7729 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7730 * global section. */ 7731 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7732 } 7733 } 7734 } else { 7735 PetscInt off = 0, idxOff; 7736 7737 for (p = 0; p < Ncl; ++p) { 7738 const PetscInt pnt = points[p * 2]; 7739 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7740 7741 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7742 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7743 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7744 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7745 } 7746 } 7747 /* 6) Cleanup */ 7748 for (f = 0; f < PetscMax(1, Nf); ++f) { 7749 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7750 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7751 } 7752 if (NclC) { 7753 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7754 } else { 7755 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7756 } 7757 7758 if (numIndices) *numIndices = Ni; 7759 if (indices) *indices = idx; 7760 PetscFunctionReturn(PETSC_SUCCESS); 7761 } 7762 7763 /*@C 7764 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7765 7766 Not collective 7767 7768 Input Parameters: 7769 + dm - The `DM` 7770 . section - The `PetscSection` describing the points (a local section) 7771 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7772 . point - The point defining the closure 7773 - useClPerm - Use the closure point permutation if available 7774 7775 Output Parameters: 7776 + numIndices - The number of dof indices in the closure of point with the input sections 7777 . indices - The dof indices 7778 . outOffsets - Array to write the field offsets into, or `NULL` 7779 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or `NULL` 7780 7781 Level: advanced 7782 7783 Notes: 7784 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7785 7786 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7787 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7788 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7789 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7790 indices (with the above semantics) are implied. 7791 7792 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7793 @*/ 7794 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7795 { 7796 PetscFunctionBegin; 7797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7798 PetscValidPointer(indices, 7); 7799 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7800 PetscFunctionReturn(PETSC_SUCCESS); 7801 } 7802 7803 /*@C 7804 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7805 7806 Not collective 7807 7808 Input Parameters: 7809 + dm - The `DM` 7810 . section - The section describing the layout in `v`, or `NULL` to use the default section 7811 . globalSection - The section describing the layout in `v`, or `NULL` to use the default global section 7812 . A - The matrix 7813 . point - The point in the `DM` 7814 . values - The array of values 7815 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7816 7817 Level: intermediate 7818 7819 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7820 @*/ 7821 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7822 { 7823 DM_Plex *mesh = (DM_Plex *)dm->data; 7824 PetscInt *indices; 7825 PetscInt numIndices; 7826 const PetscScalar *valuesOrig = values; 7827 PetscErrorCode ierr; 7828 7829 PetscFunctionBegin; 7830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7831 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7832 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7833 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7834 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7835 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7836 7837 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7838 7839 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7840 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7841 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7842 if (ierr) { 7843 PetscMPIInt rank; 7844 7845 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7846 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7847 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7848 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7849 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7850 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7851 } 7852 if (mesh->printFEM > 1) { 7853 PetscInt i; 7854 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7855 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7856 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7857 } 7858 7859 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7860 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7861 PetscFunctionReturn(PETSC_SUCCESS); 7862 } 7863 7864 /*@C 7865 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7866 7867 Not collective 7868 7869 Input Parameters: 7870 + dmRow - The `DM` for the row fields 7871 . sectionRow - The section describing the layout, or `NULL` to use the default section in `dmRow` 7872 . globalSectionRow - The section describing the layout, or `NULL` to use the default global section in `dmRow` 7873 . dmCol - The `DM` for the column fields 7874 . sectionCol - The section describing the layout, or `NULL` to use the default section in `dmCol` 7875 . globalSectionCol - The section describing the layout, or `NULL` to use the default global section in `dmCol` 7876 . A - The matrix 7877 . point - The point in the `DM` 7878 . values - The array of values 7879 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7880 7881 Level: intermediate 7882 7883 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7884 @*/ 7885 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7886 { 7887 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7888 PetscInt *indicesRow, *indicesCol; 7889 PetscInt numIndicesRow, numIndicesCol; 7890 const PetscScalar *valuesOrig = values; 7891 PetscErrorCode ierr; 7892 7893 PetscFunctionBegin; 7894 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7895 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7896 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7897 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7898 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7899 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7900 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7901 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7902 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7903 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7904 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7905 7906 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7907 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7908 7909 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7910 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7911 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7912 if (ierr) { 7913 PetscMPIInt rank; 7914 7915 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7916 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7917 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7918 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7919 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7920 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7921 } 7922 7923 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7924 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7925 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7926 PetscFunctionReturn(PETSC_SUCCESS); 7927 } 7928 7929 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7930 { 7931 DM_Plex *mesh = (DM_Plex *)dmf->data; 7932 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7933 PetscInt *cpoints = NULL; 7934 PetscInt *findices, *cindices; 7935 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7936 PetscInt foffsets[32], coffsets[32]; 7937 DMPolytopeType ct; 7938 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7939 PetscErrorCode ierr; 7940 7941 PetscFunctionBegin; 7942 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7943 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7944 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7945 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7946 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7947 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7948 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7949 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7950 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7951 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7952 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7953 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7954 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7955 PetscCall(PetscArrayzero(foffsets, 32)); 7956 PetscCall(PetscArrayzero(coffsets, 32)); 7957 /* Column indices */ 7958 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7959 maxFPoints = numCPoints; 7960 /* Compress out points not in the section */ 7961 /* TODO: Squeeze out points with 0 dof as well */ 7962 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7963 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7964 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7965 cpoints[q * 2] = cpoints[p]; 7966 cpoints[q * 2 + 1] = cpoints[p + 1]; 7967 ++q; 7968 } 7969 } 7970 numCPoints = q; 7971 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7972 PetscInt fdof; 7973 7974 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7975 if (!dof) continue; 7976 for (f = 0; f < numFields; ++f) { 7977 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7978 coffsets[f + 1] += fdof; 7979 } 7980 numCIndices += dof; 7981 } 7982 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7983 /* Row indices */ 7984 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7985 { 7986 DMPlexTransform tr; 7987 DMPolytopeType *rct; 7988 PetscInt *rsize, *rcone, *rornt, Nt; 7989 7990 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7991 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7992 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7993 numSubcells = rsize[Nt - 1]; 7994 PetscCall(DMPlexTransformDestroy(&tr)); 7995 } 7996 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7997 for (r = 0, q = 0; r < numSubcells; ++r) { 7998 /* TODO Map from coarse to fine cells */ 7999 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8000 /* Compress out points not in the section */ 8001 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8002 for (p = 0; p < numFPoints * 2; p += 2) { 8003 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8004 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8005 if (!dof) continue; 8006 for (s = 0; s < q; ++s) 8007 if (fpoints[p] == ftotpoints[s * 2]) break; 8008 if (s < q) continue; 8009 ftotpoints[q * 2] = fpoints[p]; 8010 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8011 ++q; 8012 } 8013 } 8014 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8015 } 8016 numFPoints = q; 8017 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8018 PetscInt fdof; 8019 8020 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8021 if (!dof) continue; 8022 for (f = 0; f < numFields; ++f) { 8023 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8024 foffsets[f + 1] += fdof; 8025 } 8026 numFIndices += dof; 8027 } 8028 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8029 8030 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8031 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8032 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8033 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8034 if (numFields) { 8035 const PetscInt **permsF[32] = {NULL}; 8036 const PetscInt **permsC[32] = {NULL}; 8037 8038 for (f = 0; f < numFields; f++) { 8039 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8040 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8041 } 8042 for (p = 0; p < numFPoints; p++) { 8043 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8044 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8045 } 8046 for (p = 0; p < numCPoints; p++) { 8047 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8048 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8049 } 8050 for (f = 0; f < numFields; f++) { 8051 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8052 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8053 } 8054 } else { 8055 const PetscInt **permsF = NULL; 8056 const PetscInt **permsC = NULL; 8057 8058 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8059 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8060 for (p = 0, off = 0; p < numFPoints; p++) { 8061 const PetscInt *perm = permsF ? permsF[p] : NULL; 8062 8063 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8064 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8065 } 8066 for (p = 0, off = 0; p < numCPoints; p++) { 8067 const PetscInt *perm = permsC ? permsC[p] : NULL; 8068 8069 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8070 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8071 } 8072 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8073 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8074 } 8075 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8076 /* TODO: flips */ 8077 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8078 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8079 if (ierr) { 8080 PetscMPIInt rank; 8081 8082 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8083 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8084 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8085 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8086 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8087 } 8088 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8089 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8090 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8091 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8092 PetscFunctionReturn(PETSC_SUCCESS); 8093 } 8094 8095 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8096 { 8097 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8098 PetscInt *cpoints = NULL; 8099 PetscInt foffsets[32], coffsets[32]; 8100 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8101 DMPolytopeType ct; 8102 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8103 8104 PetscFunctionBegin; 8105 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8106 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8107 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8108 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8109 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8110 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8111 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8112 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8113 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8114 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8115 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8116 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8117 PetscCall(PetscArrayzero(foffsets, 32)); 8118 PetscCall(PetscArrayzero(coffsets, 32)); 8119 /* Column indices */ 8120 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8121 maxFPoints = numCPoints; 8122 /* Compress out points not in the section */ 8123 /* TODO: Squeeze out points with 0 dof as well */ 8124 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8125 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8126 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8127 cpoints[q * 2] = cpoints[p]; 8128 cpoints[q * 2 + 1] = cpoints[p + 1]; 8129 ++q; 8130 } 8131 } 8132 numCPoints = q; 8133 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8134 PetscInt fdof; 8135 8136 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8137 if (!dof) continue; 8138 for (f = 0; f < numFields; ++f) { 8139 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8140 coffsets[f + 1] += fdof; 8141 } 8142 numCIndices += dof; 8143 } 8144 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8145 /* Row indices */ 8146 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8147 { 8148 DMPlexTransform tr; 8149 DMPolytopeType *rct; 8150 PetscInt *rsize, *rcone, *rornt, Nt; 8151 8152 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8153 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8154 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8155 numSubcells = rsize[Nt - 1]; 8156 PetscCall(DMPlexTransformDestroy(&tr)); 8157 } 8158 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8159 for (r = 0, q = 0; r < numSubcells; ++r) { 8160 /* TODO Map from coarse to fine cells */ 8161 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8162 /* Compress out points not in the section */ 8163 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8164 for (p = 0; p < numFPoints * 2; p += 2) { 8165 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8166 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8167 if (!dof) continue; 8168 for (s = 0; s < q; ++s) 8169 if (fpoints[p] == ftotpoints[s * 2]) break; 8170 if (s < q) continue; 8171 ftotpoints[q * 2] = fpoints[p]; 8172 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8173 ++q; 8174 } 8175 } 8176 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8177 } 8178 numFPoints = q; 8179 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8180 PetscInt fdof; 8181 8182 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8183 if (!dof) continue; 8184 for (f = 0; f < numFields; ++f) { 8185 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8186 foffsets[f + 1] += fdof; 8187 } 8188 numFIndices += dof; 8189 } 8190 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8191 8192 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8193 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8194 if (numFields) { 8195 const PetscInt **permsF[32] = {NULL}; 8196 const PetscInt **permsC[32] = {NULL}; 8197 8198 for (f = 0; f < numFields; f++) { 8199 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8200 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8201 } 8202 for (p = 0; p < numFPoints; p++) { 8203 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8204 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8205 } 8206 for (p = 0; p < numCPoints; p++) { 8207 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8208 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8209 } 8210 for (f = 0; f < numFields; f++) { 8211 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8212 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8213 } 8214 } else { 8215 const PetscInt **permsF = NULL; 8216 const PetscInt **permsC = NULL; 8217 8218 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8219 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8220 for (p = 0, off = 0; p < numFPoints; p++) { 8221 const PetscInt *perm = permsF ? permsF[p] : NULL; 8222 8223 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8224 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8225 } 8226 for (p = 0, off = 0; p < numCPoints; p++) { 8227 const PetscInt *perm = permsC ? permsC[p] : NULL; 8228 8229 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8230 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8231 } 8232 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8233 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8234 } 8235 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8236 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8237 PetscFunctionReturn(PETSC_SUCCESS); 8238 } 8239 8240 /*@C 8241 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8242 8243 Input Parameter: 8244 . dm - The `DMPLEX` object 8245 8246 Output Parameter: 8247 . cellHeight - The height of a cell 8248 8249 Level: developer 8250 8251 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8252 @*/ 8253 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8254 { 8255 DM_Plex *mesh = (DM_Plex *)dm->data; 8256 8257 PetscFunctionBegin; 8258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8259 PetscValidIntPointer(cellHeight, 2); 8260 *cellHeight = mesh->vtkCellHeight; 8261 PetscFunctionReturn(PETSC_SUCCESS); 8262 } 8263 8264 /*@C 8265 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8266 8267 Input Parameters: 8268 + dm - The `DMPLEX` object 8269 - cellHeight - The height of a cell 8270 8271 Level: developer 8272 8273 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8274 @*/ 8275 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8276 { 8277 DM_Plex *mesh = (DM_Plex *)dm->data; 8278 8279 PetscFunctionBegin; 8280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8281 mesh->vtkCellHeight = cellHeight; 8282 PetscFunctionReturn(PETSC_SUCCESS); 8283 } 8284 8285 /*@ 8286 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8287 8288 Input Parameter: 8289 . dm - The `DMPLEX` object 8290 8291 Output Parameters: 8292 + gcStart - The first ghost cell, or `NULL` 8293 - gcEnd - The upper bound on ghost cells, or `NULL` 8294 8295 Level: advanced 8296 8297 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8298 @*/ 8299 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8300 { 8301 DMLabel ctLabel; 8302 8303 PetscFunctionBegin; 8304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8305 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8306 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8307 // Reset label for fast lookup 8308 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8309 PetscFunctionReturn(PETSC_SUCCESS); 8310 } 8311 8312 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8313 { 8314 PetscSection section, globalSection; 8315 PetscInt *numbers, p; 8316 8317 PetscFunctionBegin; 8318 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8319 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8320 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8321 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8322 PetscCall(PetscSectionSetUp(section)); 8323 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8324 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8325 for (p = pStart; p < pEnd; ++p) { 8326 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8327 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8328 else numbers[p - pStart] += shift; 8329 } 8330 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8331 if (globalSize) { 8332 PetscLayout layout; 8333 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8334 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8335 PetscCall(PetscLayoutDestroy(&layout)); 8336 } 8337 PetscCall(PetscSectionDestroy(§ion)); 8338 PetscCall(PetscSectionDestroy(&globalSection)); 8339 PetscFunctionReturn(PETSC_SUCCESS); 8340 } 8341 8342 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8343 { 8344 PetscInt cellHeight, cStart, cEnd; 8345 8346 PetscFunctionBegin; 8347 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8348 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8349 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8350 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8351 PetscFunctionReturn(PETSC_SUCCESS); 8352 } 8353 8354 /*@ 8355 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8356 8357 Input Parameter: 8358 . dm - The `DMPLEX` object 8359 8360 Output Parameter: 8361 . globalCellNumbers - Global cell numbers for all cells on this process 8362 8363 Level: developer 8364 8365 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8366 @*/ 8367 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8368 { 8369 DM_Plex *mesh = (DM_Plex *)dm->data; 8370 8371 PetscFunctionBegin; 8372 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8373 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8374 *globalCellNumbers = mesh->globalCellNumbers; 8375 PetscFunctionReturn(PETSC_SUCCESS); 8376 } 8377 8378 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8379 { 8380 PetscInt vStart, vEnd; 8381 8382 PetscFunctionBegin; 8383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8384 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8385 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8386 PetscFunctionReturn(PETSC_SUCCESS); 8387 } 8388 8389 /*@ 8390 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8391 8392 Input Parameter: 8393 . dm - The `DMPLEX` object 8394 8395 Output Parameter: 8396 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8397 8398 Level: developer 8399 8400 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8401 @*/ 8402 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8403 { 8404 DM_Plex *mesh = (DM_Plex *)dm->data; 8405 8406 PetscFunctionBegin; 8407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8408 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8409 *globalVertexNumbers = mesh->globalVertexNumbers; 8410 PetscFunctionReturn(PETSC_SUCCESS); 8411 } 8412 8413 /*@ 8414 DMPlexCreatePointNumbering - Create a global numbering for all points. 8415 8416 Collective 8417 8418 Input Parameter: 8419 . dm - The `DMPLEX` object 8420 8421 Output Parameter: 8422 . globalPointNumbers - Global numbers for all points on this process 8423 8424 Level: developer 8425 8426 Notes: 8427 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8428 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8429 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8430 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8431 8432 The partitioned mesh is 8433 ``` 8434 (2)--0--(3)--1--(4) (1)--0--(2) 8435 ``` 8436 and its global numbering is 8437 ``` 8438 (3)--0--(4)--1--(5)--2--(6) 8439 ``` 8440 Then the global numbering is provided as 8441 ``` 8442 [0] Number of indices in set 5 8443 [0] 0 0 8444 [0] 1 1 8445 [0] 2 3 8446 [0] 3 4 8447 [0] 4 -6 8448 [1] Number of indices in set 3 8449 [1] 0 2 8450 [1] 1 5 8451 [1] 2 6 8452 ``` 8453 8454 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8455 @*/ 8456 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8457 { 8458 IS nums[4]; 8459 PetscInt depths[4], gdepths[4], starts[4]; 8460 PetscInt depth, d, shift = 0; 8461 PetscBool empty = PETSC_FALSE; 8462 8463 PetscFunctionBegin; 8464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8465 PetscCall(DMPlexGetDepth(dm, &depth)); 8466 // For unstratified meshes use dim instead of depth 8467 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8468 // If any stratum is empty, we must mark all empty 8469 for (d = 0; d <= depth; ++d) { 8470 PetscInt end; 8471 8472 depths[d] = depth - d; 8473 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8474 if (!(starts[d] - end)) empty = PETSC_TRUE; 8475 } 8476 if (empty) 8477 for (d = 0; d <= depth; ++d) { 8478 depths[d] = -1; 8479 starts[d] = -1; 8480 } 8481 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8482 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8483 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]); 8484 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8485 for (d = 0; d <= depth; ++d) { 8486 PetscInt pStart, pEnd, gsize; 8487 8488 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8489 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8490 shift += gsize; 8491 } 8492 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8493 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8494 PetscFunctionReturn(PETSC_SUCCESS); 8495 } 8496 8497 /*@ 8498 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8499 8500 Input Parameter: 8501 . dm - The `DMPLEX` object 8502 8503 Output Parameter: 8504 . ranks - The rank field 8505 8506 Options Database Key: 8507 . -dm_partition_view - Adds the rank field into the `DM` output from `-dm_view` using the same viewer 8508 8509 Level: intermediate 8510 8511 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8512 @*/ 8513 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8514 { 8515 DM rdm; 8516 PetscFE fe; 8517 PetscScalar *r; 8518 PetscMPIInt rank; 8519 DMPolytopeType ct; 8520 PetscInt dim, cStart, cEnd, c; 8521 PetscBool simplex; 8522 8523 PetscFunctionBeginUser; 8524 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8525 PetscValidPointer(ranks, 2); 8526 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8527 PetscCall(DMClone(dm, &rdm)); 8528 PetscCall(DMGetDimension(rdm, &dim)); 8529 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8530 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8531 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8532 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8533 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8534 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8535 PetscCall(PetscFEDestroy(&fe)); 8536 PetscCall(DMCreateDS(rdm)); 8537 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8538 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8539 PetscCall(VecGetArray(*ranks, &r)); 8540 for (c = cStart; c < cEnd; ++c) { 8541 PetscScalar *lr; 8542 8543 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8544 if (lr) *lr = rank; 8545 } 8546 PetscCall(VecRestoreArray(*ranks, &r)); 8547 PetscCall(DMDestroy(&rdm)); 8548 PetscFunctionReturn(PETSC_SUCCESS); 8549 } 8550 8551 /*@ 8552 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8553 8554 Input Parameters: 8555 + dm - The `DMPLEX` 8556 - label - The `DMLabel` 8557 8558 Output Parameter: 8559 . val - The label value field 8560 8561 Options Database Key: 8562 . -dm_label_view - Adds the label value field into the `DM` output from `-dm_view` using the same viewer 8563 8564 Level: intermediate 8565 8566 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMView()` 8567 @*/ 8568 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8569 { 8570 DM rdm; 8571 PetscFE fe; 8572 PetscScalar *v; 8573 PetscInt dim, cStart, cEnd, c; 8574 8575 PetscFunctionBeginUser; 8576 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8577 PetscValidPointer(label, 2); 8578 PetscValidPointer(val, 3); 8579 PetscCall(DMClone(dm, &rdm)); 8580 PetscCall(DMGetDimension(rdm, &dim)); 8581 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8582 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8583 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8584 PetscCall(PetscFEDestroy(&fe)); 8585 PetscCall(DMCreateDS(rdm)); 8586 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8587 PetscCall(DMCreateGlobalVector(rdm, val)); 8588 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8589 PetscCall(VecGetArray(*val, &v)); 8590 for (c = cStart; c < cEnd; ++c) { 8591 PetscScalar *lv; 8592 PetscInt cval; 8593 8594 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8595 PetscCall(DMLabelGetValue(label, c, &cval)); 8596 *lv = cval; 8597 } 8598 PetscCall(VecRestoreArray(*val, &v)); 8599 PetscCall(DMDestroy(&rdm)); 8600 PetscFunctionReturn(PETSC_SUCCESS); 8601 } 8602 8603 /*@ 8604 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8605 8606 Input Parameter: 8607 . dm - The `DMPLEX` object 8608 8609 Level: developer 8610 8611 Notes: 8612 This is a useful diagnostic when creating meshes programmatically. 8613 8614 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8615 8616 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8617 @*/ 8618 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8619 { 8620 PetscSection coneSection, supportSection; 8621 const PetscInt *cone, *support; 8622 PetscInt coneSize, c, supportSize, s; 8623 PetscInt pStart, pEnd, p, pp, csize, ssize; 8624 PetscBool storagecheck = PETSC_TRUE; 8625 8626 PetscFunctionBegin; 8627 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8628 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8629 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8630 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8631 /* Check that point p is found in the support of its cone points, and vice versa */ 8632 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8633 for (p = pStart; p < pEnd; ++p) { 8634 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8635 PetscCall(DMPlexGetCone(dm, p, &cone)); 8636 for (c = 0; c < coneSize; ++c) { 8637 PetscBool dup = PETSC_FALSE; 8638 PetscInt d; 8639 for (d = c - 1; d >= 0; --d) { 8640 if (cone[c] == cone[d]) { 8641 dup = PETSC_TRUE; 8642 break; 8643 } 8644 } 8645 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8646 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8647 for (s = 0; s < supportSize; ++s) { 8648 if (support[s] == p) break; 8649 } 8650 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8651 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8652 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8653 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8654 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8655 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8656 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8657 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]); 8658 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8659 } 8660 } 8661 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8662 if (p != pp) { 8663 storagecheck = PETSC_FALSE; 8664 continue; 8665 } 8666 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8667 PetscCall(DMPlexGetSupport(dm, p, &support)); 8668 for (s = 0; s < supportSize; ++s) { 8669 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8670 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8671 for (c = 0; c < coneSize; ++c) { 8672 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8673 if (cone[c] != pp) { 8674 c = 0; 8675 break; 8676 } 8677 if (cone[c] == p) break; 8678 } 8679 if (c >= coneSize) { 8680 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8681 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8682 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8683 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8684 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8685 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8686 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8687 } 8688 } 8689 } 8690 if (storagecheck) { 8691 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8692 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8693 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8694 } 8695 PetscFunctionReturn(PETSC_SUCCESS); 8696 } 8697 8698 /* 8699 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. 8700 */ 8701 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8702 { 8703 DMPolytopeType cct; 8704 PetscInt ptpoints[4]; 8705 const PetscInt *cone, *ccone, *ptcone; 8706 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8707 8708 PetscFunctionBegin; 8709 *unsplit = 0; 8710 switch (ct) { 8711 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8712 ptpoints[npt++] = c; 8713 break; 8714 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8715 PetscCall(DMPlexGetCone(dm, c, &cone)); 8716 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8717 for (cp = 0; cp < coneSize; ++cp) { 8718 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8719 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8720 } 8721 break; 8722 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8723 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8724 PetscCall(DMPlexGetCone(dm, c, &cone)); 8725 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8726 for (cp = 0; cp < coneSize; ++cp) { 8727 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8728 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8729 for (ccp = 0; ccp < cconeSize; ++ccp) { 8730 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8731 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8732 PetscInt p; 8733 for (p = 0; p < npt; ++p) 8734 if (ptpoints[p] == ccone[ccp]) break; 8735 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8736 } 8737 } 8738 } 8739 break; 8740 default: 8741 break; 8742 } 8743 for (pt = 0; pt < npt; ++pt) { 8744 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8745 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8746 } 8747 PetscFunctionReturn(PETSC_SUCCESS); 8748 } 8749 8750 /*@ 8751 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8752 8753 Input Parameters: 8754 + dm - The `DMPLEX` object 8755 - cellHeight - Normally 0 8756 8757 Level: developer 8758 8759 Notes: 8760 This is a useful diagnostic when creating meshes programmatically. 8761 Currently applicable only to homogeneous simplex or tensor meshes. 8762 8763 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8764 8765 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8766 @*/ 8767 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8768 { 8769 DMPlexInterpolatedFlag interp; 8770 DMPolytopeType ct; 8771 PetscInt vStart, vEnd, cStart, cEnd, c; 8772 8773 PetscFunctionBegin; 8774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8775 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8776 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8777 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8778 for (c = cStart; c < cEnd; ++c) { 8779 PetscInt *closure = NULL; 8780 PetscInt coneSize, closureSize, cl, Nv = 0; 8781 8782 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8783 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8784 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8785 if (interp == DMPLEX_INTERPOLATED_FULL) { 8786 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8787 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)); 8788 } 8789 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8790 for (cl = 0; cl < closureSize * 2; cl += 2) { 8791 const PetscInt p = closure[cl]; 8792 if ((p >= vStart) && (p < vEnd)) ++Nv; 8793 } 8794 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8795 /* Special Case: Tensor faces with identified vertices */ 8796 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8797 PetscInt unsplit; 8798 8799 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8800 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8801 } 8802 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)); 8803 } 8804 PetscFunctionReturn(PETSC_SUCCESS); 8805 } 8806 8807 /*@ 8808 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8809 8810 Collective 8811 8812 Input Parameters: 8813 + dm - The `DMPLEX` object 8814 - cellHeight - Normally 0 8815 8816 Level: developer 8817 8818 Notes: 8819 This is a useful diagnostic when creating meshes programmatically. 8820 This routine is only relevant for meshes that are fully interpolated across all ranks. 8821 It will error out if a partially interpolated mesh is given on some rank. 8822 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8823 8824 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8825 8826 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8827 @*/ 8828 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8829 { 8830 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8831 DMPlexInterpolatedFlag interpEnum; 8832 8833 PetscFunctionBegin; 8834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8835 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8836 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(PETSC_SUCCESS); 8837 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8838 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported")); 8839 PetscFunctionReturn(PETSC_SUCCESS); 8840 } 8841 8842 PetscCall(DMGetDimension(dm, &dim)); 8843 PetscCall(DMPlexGetDepth(dm, &depth)); 8844 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8845 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8846 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8847 for (c = cStart; c < cEnd; ++c) { 8848 const PetscInt *cone, *ornt, *faceSizes, *faces; 8849 const DMPolytopeType *faceTypes; 8850 DMPolytopeType ct; 8851 PetscInt numFaces, coneSize, f; 8852 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8853 8854 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8855 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8856 if (unsplit) continue; 8857 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8858 PetscCall(DMPlexGetCone(dm, c, &cone)); 8859 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8860 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8861 for (cl = 0; cl < closureSize * 2; cl += 2) { 8862 const PetscInt p = closure[cl]; 8863 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8864 } 8865 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8866 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); 8867 for (f = 0; f < numFaces; ++f) { 8868 DMPolytopeType fct; 8869 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8870 8871 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8872 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8873 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8874 const PetscInt p = fclosure[cl]; 8875 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8876 } 8877 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]); 8878 for (v = 0; v < fnumCorners; ++v) { 8879 if (fclosure[v] != faces[fOff + v]) { 8880 PetscInt v1; 8881 8882 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8883 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8884 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8885 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8886 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8887 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]); 8888 } 8889 } 8890 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8891 fOff += faceSizes[f]; 8892 } 8893 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8894 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8895 } 8896 } 8897 PetscFunctionReturn(PETSC_SUCCESS); 8898 } 8899 8900 /*@ 8901 DMPlexCheckGeometry - Check the geometry of mesh cells 8902 8903 Input Parameter: 8904 . dm - The `DMPLEX` object 8905 8906 Level: developer 8907 8908 Notes: 8909 This is a useful diagnostic when creating meshes programmatically. 8910 8911 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8912 8913 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8914 @*/ 8915 PetscErrorCode DMPlexCheckGeometry(DM dm) 8916 { 8917 Vec coordinates; 8918 PetscReal detJ, J[9], refVol = 1.0; 8919 PetscReal vol; 8920 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8921 8922 PetscFunctionBegin; 8923 PetscCall(DMGetDimension(dm, &dim)); 8924 PetscCall(DMGetCoordinateDim(dm, &dE)); 8925 if (dim != dE) PetscFunctionReturn(PETSC_SUCCESS); 8926 PetscCall(DMPlexGetDepth(dm, &depth)); 8927 for (d = 0; d < dim; ++d) refVol *= 2.0; 8928 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8929 /* Make sure local coordinates are created, because that step is collective */ 8930 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8931 if (!coordinates) PetscFunctionReturn(PETSC_SUCCESS); 8932 for (c = cStart; c < cEnd; ++c) { 8933 DMPolytopeType ct; 8934 PetscInt unsplit; 8935 PetscBool ignoreZeroVol = PETSC_FALSE; 8936 8937 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8938 switch (ct) { 8939 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8940 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8941 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8942 ignoreZeroVol = PETSC_TRUE; 8943 break; 8944 default: 8945 break; 8946 } 8947 switch (ct) { 8948 case DM_POLYTOPE_TRI_PRISM: 8949 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8950 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8951 case DM_POLYTOPE_PYRAMID: 8952 continue; 8953 default: 8954 break; 8955 } 8956 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8957 if (unsplit) continue; 8958 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8959 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); 8960 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8961 /* This should work with periodicity since DG coordinates should be used */ 8962 if (depth > 1) { 8963 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8964 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); 8965 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8966 } 8967 } 8968 PetscFunctionReturn(PETSC_SUCCESS); 8969 } 8970 8971 /*@ 8972 DMPlexCheckPointSF - Check that several necessary conditions are met for the point `PetscSF` of this plex. 8973 8974 Collective 8975 8976 Input Parameters: 8977 + dm - The `DMPLEX` object 8978 . pointSF - The `PetscSF`, or `NULL` for `PointSF` attached to `DM` 8979 - allowExtraRoots - Flag to allow extra points not present in the `DM` 8980 8981 Level: developer 8982 8983 Notes: 8984 This is mainly intended for debugging/testing purposes. 8985 8986 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8987 8988 Extra roots can come from priodic cuts, where additional points appear on the boundary 8989 8990 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 8991 @*/ 8992 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 8993 { 8994 PetscInt l, nleaves, nroots, overlap; 8995 const PetscInt *locals; 8996 const PetscSFNode *remotes; 8997 PetscBool distributed; 8998 MPI_Comm comm; 8999 PetscMPIInt rank; 9000 9001 PetscFunctionBegin; 9002 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9003 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9004 else pointSF = dm->sf; 9005 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9006 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 9007 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9008 { 9009 PetscMPIInt mpiFlag; 9010 9011 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 9012 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 9013 } 9014 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 9015 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9016 if (!distributed) { 9017 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); 9018 PetscFunctionReturn(PETSC_SUCCESS); 9019 } 9020 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); 9021 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9022 9023 /* Check SF graph is compatible with DMPlex chart */ 9024 { 9025 PetscInt pStart, pEnd, maxLeaf; 9026 9027 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9028 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9029 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9030 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9031 } 9032 9033 /* Check Point SF has no local points referenced */ 9034 for (l = 0; l < nleaves; l++) { 9035 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); 9036 } 9037 9038 /* Check there are no cells in interface */ 9039 if (!overlap) { 9040 PetscInt cellHeight, cStart, cEnd; 9041 9042 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9043 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9044 for (l = 0; l < nleaves; ++l) { 9045 const PetscInt point = locals ? locals[l] : l; 9046 9047 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9048 } 9049 } 9050 9051 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9052 { 9053 const PetscInt *rootdegree; 9054 9055 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9056 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9057 for (l = 0; l < nleaves; ++l) { 9058 const PetscInt point = locals ? locals[l] : l; 9059 const PetscInt *cone; 9060 PetscInt coneSize, c, idx; 9061 9062 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9063 PetscCall(DMPlexGetCone(dm, point, &cone)); 9064 for (c = 0; c < coneSize; ++c) { 9065 if (!rootdegree[cone[c]]) { 9066 if (locals) { 9067 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9068 } else { 9069 idx = (cone[c] < nleaves) ? cone[c] : -1; 9070 } 9071 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9072 } 9073 } 9074 } 9075 } 9076 PetscFunctionReturn(PETSC_SUCCESS); 9077 } 9078 9079 /*@ 9080 DMPlexCheck - Perform various checks of `DMPLEX` sanity 9081 9082 Input Parameter: 9083 . dm - The `DMPLEX` object 9084 9085 Level: developer 9086 9087 Notes: 9088 This is a useful diagnostic when creating meshes programmatically. 9089 9090 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9091 9092 Currently does not include `DMPlexCheckCellShape()`. 9093 9094 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 9095 @*/ 9096 PetscErrorCode DMPlexCheck(DM dm) 9097 { 9098 PetscInt cellHeight; 9099 9100 PetscFunctionBegin; 9101 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9102 PetscCall(DMPlexCheckSymmetry(dm)); 9103 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9104 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9105 PetscCall(DMPlexCheckGeometry(dm)); 9106 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9107 PetscCall(DMPlexCheckInterfaceCones(dm)); 9108 PetscFunctionReturn(PETSC_SUCCESS); 9109 } 9110 9111 typedef struct cell_stats { 9112 PetscReal min, max, sum, squaresum; 9113 PetscInt count; 9114 } cell_stats_t; 9115 9116 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9117 { 9118 PetscInt i, N = *len; 9119 9120 for (i = 0; i < N; i++) { 9121 cell_stats_t *A = (cell_stats_t *)a; 9122 cell_stats_t *B = (cell_stats_t *)b; 9123 9124 B->min = PetscMin(A->min, B->min); 9125 B->max = PetscMax(A->max, B->max); 9126 B->sum += A->sum; 9127 B->squaresum += A->squaresum; 9128 B->count += A->count; 9129 } 9130 } 9131 9132 /*@ 9133 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9134 9135 Collective 9136 9137 Input Parameters: 9138 + dm - The `DMPLEX` object 9139 . output - If true, statistics will be displayed on `stdout` 9140 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9141 9142 Level: developer 9143 9144 Notes: 9145 This is mainly intended for debugging/testing purposes. 9146 9147 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9148 9149 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9150 @*/ 9151 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9152 { 9153 DM dmCoarse; 9154 cell_stats_t stats, globalStats; 9155 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9156 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9157 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9158 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9159 PetscMPIInt rank, size; 9160 9161 PetscFunctionBegin; 9162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9163 stats.min = PETSC_MAX_REAL; 9164 stats.max = PETSC_MIN_REAL; 9165 stats.sum = stats.squaresum = 0.; 9166 stats.count = 0; 9167 9168 PetscCallMPI(MPI_Comm_size(comm, &size)); 9169 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9170 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9171 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9172 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9173 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9174 for (c = cStart; c < cEnd; c++) { 9175 PetscInt i; 9176 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9177 9178 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9179 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9180 for (i = 0; i < PetscSqr(cdim); ++i) { 9181 frobJ += J[i] * J[i]; 9182 frobInvJ += invJ[i] * invJ[i]; 9183 } 9184 cond2 = frobJ * frobInvJ; 9185 cond = PetscSqrtReal(cond2); 9186 9187 stats.min = PetscMin(stats.min, cond); 9188 stats.max = PetscMax(stats.max, cond); 9189 stats.sum += cond; 9190 stats.squaresum += cond2; 9191 stats.count++; 9192 if (output && cond > limit) { 9193 PetscSection coordSection; 9194 Vec coordsLocal; 9195 PetscScalar *coords = NULL; 9196 PetscInt Nv, d, clSize, cl, *closure = NULL; 9197 9198 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9199 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9200 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9201 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9202 for (i = 0; i < Nv / cdim; ++i) { 9203 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9204 for (d = 0; d < cdim; ++d) { 9205 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9206 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9207 } 9208 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9209 } 9210 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9211 for (cl = 0; cl < clSize * 2; cl += 2) { 9212 const PetscInt edge = closure[cl]; 9213 9214 if ((edge >= eStart) && (edge < eEnd)) { 9215 PetscReal len; 9216 9217 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9218 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9219 } 9220 } 9221 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9222 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9223 } 9224 } 9225 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9226 9227 if (size > 1) { 9228 PetscMPIInt blockLengths[2] = {4, 1}; 9229 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9230 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9231 MPI_Op statReduce; 9232 9233 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9234 PetscCallMPI(MPI_Type_commit(&statType)); 9235 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9236 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9237 PetscCallMPI(MPI_Op_free(&statReduce)); 9238 PetscCallMPI(MPI_Type_free(&statType)); 9239 } else { 9240 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9241 } 9242 if (rank == 0) { 9243 count = globalStats.count; 9244 min = globalStats.min; 9245 max = globalStats.max; 9246 mean = globalStats.sum / globalStats.count; 9247 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9248 } 9249 9250 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)); 9251 PetscCall(PetscFree2(J, invJ)); 9252 9253 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9254 if (dmCoarse) { 9255 PetscBool isplex; 9256 9257 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9258 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9259 } 9260 PetscFunctionReturn(PETSC_SUCCESS); 9261 } 9262 9263 /*@ 9264 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9265 orthogonal quality below given tolerance. 9266 9267 Collective 9268 9269 Input Parameters: 9270 + dm - The `DMPLEX` object 9271 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9272 - atol - [0, 1] Absolute tolerance for tagging cells. 9273 9274 Output Parameters: 9275 + OrthQual - `Vec` containing orthogonal quality per cell 9276 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9277 9278 Options Database Keys: 9279 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9280 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9281 9282 Level: intermediate 9283 9284 Notes: 9285 Orthogonal quality is given by the following formula: 9286 9287 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9288 9289 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 9290 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9291 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9292 calculating the cosine of the angle between these vectors. 9293 9294 Orthogonal quality ranges from 1 (best) to 0 (worst). 9295 9296 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9297 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9298 9299 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9300 9301 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9302 @*/ 9303 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9304 { 9305 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9306 PetscInt *idx; 9307 PetscScalar *oqVals; 9308 const PetscScalar *cellGeomArr, *faceGeomArr; 9309 PetscReal *ci, *fi, *Ai; 9310 MPI_Comm comm; 9311 Vec cellgeom, facegeom; 9312 DM dmFace, dmCell; 9313 IS glob; 9314 ISLocalToGlobalMapping ltog; 9315 PetscViewer vwr; 9316 9317 PetscFunctionBegin; 9318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9319 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9320 PetscValidPointer(OrthQual, 4); 9321 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9322 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9323 PetscCall(DMGetDimension(dm, &nc)); 9324 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9325 { 9326 DMPlexInterpolatedFlag interpFlag; 9327 9328 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9329 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9330 PetscMPIInt rank; 9331 9332 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9333 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9334 } 9335 } 9336 if (OrthQualLabel) { 9337 PetscValidPointer(OrthQualLabel, 5); 9338 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9339 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9340 } else { 9341 *OrthQualLabel = NULL; 9342 } 9343 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9344 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9345 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9346 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9347 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9348 PetscCall(VecCreate(comm, OrthQual)); 9349 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9350 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9351 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9352 PetscCall(VecSetUp(*OrthQual)); 9353 PetscCall(ISDestroy(&glob)); 9354 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9355 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9356 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9357 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9358 PetscCall(VecGetDM(cellgeom, &dmCell)); 9359 PetscCall(VecGetDM(facegeom, &dmFace)); 9360 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9361 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9362 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9363 PetscInt cellarr[2], *adj = NULL; 9364 PetscScalar *cArr, *fArr; 9365 PetscReal minvalc = 1.0, minvalf = 1.0; 9366 PetscFVCellGeom *cg; 9367 9368 idx[cellIter] = cell - cStart; 9369 cellarr[0] = cell; 9370 /* Make indexing into cellGeom easier */ 9371 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9372 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9373 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9374 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9375 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9376 PetscInt i; 9377 const PetscInt neigh = adj[cellneigh]; 9378 PetscReal normci = 0, normfi = 0, normai = 0; 9379 PetscFVCellGeom *cgneigh; 9380 PetscFVFaceGeom *fg; 9381 9382 /* Don't count ourselves in the neighbor list */ 9383 if (neigh == cell) continue; 9384 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9385 cellarr[1] = neigh; 9386 { 9387 PetscInt numcovpts; 9388 const PetscInt *covpts; 9389 9390 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9391 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9392 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9393 } 9394 9395 /* Compute c_i, f_i and their norms */ 9396 for (i = 0; i < nc; i++) { 9397 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9398 fi[i] = fg->centroid[i] - cg->centroid[i]; 9399 Ai[i] = fg->normal[i]; 9400 normci += PetscPowReal(ci[i], 2); 9401 normfi += PetscPowReal(fi[i], 2); 9402 normai += PetscPowReal(Ai[i], 2); 9403 } 9404 normci = PetscSqrtReal(normci); 9405 normfi = PetscSqrtReal(normfi); 9406 normai = PetscSqrtReal(normai); 9407 9408 /* Normalize and compute for each face-cell-normal pair */ 9409 for (i = 0; i < nc; i++) { 9410 ci[i] = ci[i] / normci; 9411 fi[i] = fi[i] / normfi; 9412 Ai[i] = Ai[i] / normai; 9413 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9414 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9415 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9416 } 9417 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9418 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9419 } 9420 PetscCall(PetscFree(adj)); 9421 PetscCall(PetscFree2(cArr, fArr)); 9422 /* Defer to cell if they're equal */ 9423 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9424 if (OrthQualLabel) { 9425 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9426 } 9427 } 9428 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9429 PetscCall(VecAssemblyBegin(*OrthQual)); 9430 PetscCall(VecAssemblyEnd(*OrthQual)); 9431 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9432 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9433 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9434 if (OrthQualLabel) { 9435 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9436 } 9437 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9438 PetscCall(PetscViewerDestroy(&vwr)); 9439 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9440 PetscFunctionReturn(PETSC_SUCCESS); 9441 } 9442 9443 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9444 * interpolator construction */ 9445 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9446 { 9447 PetscSection section, newSection, gsection; 9448 PetscSF sf; 9449 PetscBool hasConstraints, ghasConstraints; 9450 9451 PetscFunctionBegin; 9452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9453 PetscValidPointer(odm, 2); 9454 PetscCall(DMGetLocalSection(dm, §ion)); 9455 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9456 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9457 if (!ghasConstraints) { 9458 PetscCall(PetscObjectReference((PetscObject)dm)); 9459 *odm = dm; 9460 PetscFunctionReturn(PETSC_SUCCESS); 9461 } 9462 PetscCall(DMClone(dm, odm)); 9463 PetscCall(DMCopyFields(dm, *odm)); 9464 PetscCall(DMGetLocalSection(*odm, &newSection)); 9465 PetscCall(DMGetPointSF(*odm, &sf)); 9466 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9467 PetscCall(DMSetGlobalSection(*odm, gsection)); 9468 PetscCall(PetscSectionDestroy(&gsection)); 9469 PetscFunctionReturn(PETSC_SUCCESS); 9470 } 9471 9472 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9473 { 9474 DM dmco, dmfo; 9475 Mat interpo; 9476 Vec rscale; 9477 Vec cglobalo, clocal; 9478 Vec fglobal, fglobalo, flocal; 9479 PetscBool regular; 9480 9481 PetscFunctionBegin; 9482 PetscCall(DMGetFullDM(dmc, &dmco)); 9483 PetscCall(DMGetFullDM(dmf, &dmfo)); 9484 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9485 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9486 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9487 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9488 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9489 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9490 PetscCall(VecSet(cglobalo, 0.)); 9491 PetscCall(VecSet(clocal, 0.)); 9492 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9493 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9494 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9495 PetscCall(VecSet(fglobal, 0.)); 9496 PetscCall(VecSet(fglobalo, 0.)); 9497 PetscCall(VecSet(flocal, 0.)); 9498 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9499 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9500 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9501 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9502 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9503 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9504 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9505 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9506 *shift = fglobal; 9507 PetscCall(VecDestroy(&flocal)); 9508 PetscCall(VecDestroy(&fglobalo)); 9509 PetscCall(VecDestroy(&clocal)); 9510 PetscCall(VecDestroy(&cglobalo)); 9511 PetscCall(VecDestroy(&rscale)); 9512 PetscCall(MatDestroy(&interpo)); 9513 PetscCall(DMDestroy(&dmfo)); 9514 PetscCall(DMDestroy(&dmco)); 9515 PetscFunctionReturn(PETSC_SUCCESS); 9516 } 9517 9518 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9519 { 9520 PetscObject shifto; 9521 Vec shift; 9522 9523 PetscFunctionBegin; 9524 if (!interp) { 9525 Vec rscale; 9526 9527 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9528 PetscCall(VecDestroy(&rscale)); 9529 } else { 9530 PetscCall(PetscObjectReference((PetscObject)interp)); 9531 } 9532 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9533 if (!shifto) { 9534 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9535 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9536 shifto = (PetscObject)shift; 9537 PetscCall(VecDestroy(&shift)); 9538 } 9539 shift = (Vec)shifto; 9540 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9541 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9542 PetscCall(MatDestroy(&interp)); 9543 PetscFunctionReturn(PETSC_SUCCESS); 9544 } 9545 9546 /* Pointwise interpolation 9547 Just code FEM for now 9548 u^f = I u^c 9549 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9550 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9551 I_{ij} = psi^f_i phi^c_j 9552 */ 9553 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9554 { 9555 PetscSection gsc, gsf; 9556 PetscInt m, n; 9557 void *ctx; 9558 DM cdm; 9559 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9560 9561 PetscFunctionBegin; 9562 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9563 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9564 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9565 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9566 9567 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9568 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9569 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9570 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9571 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9572 9573 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9574 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9575 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9576 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9577 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9578 if (scaling) { 9579 /* Use naive scaling */ 9580 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9581 } 9582 PetscFunctionReturn(PETSC_SUCCESS); 9583 } 9584 9585 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9586 { 9587 VecScatter ctx; 9588 9589 PetscFunctionBegin; 9590 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9591 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9592 PetscCall(VecScatterDestroy(&ctx)); 9593 PetscFunctionReturn(PETSC_SUCCESS); 9594 } 9595 9596 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[]) 9597 { 9598 const PetscInt Nc = uOff[1] - uOff[0]; 9599 PetscInt c; 9600 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9601 } 9602 9603 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9604 { 9605 DM dmc; 9606 PetscDS ds; 9607 Vec ones, locmass; 9608 IS cellIS; 9609 PetscFormKey key; 9610 PetscInt depth; 9611 9612 PetscFunctionBegin; 9613 PetscCall(DMClone(dm, &dmc)); 9614 PetscCall(DMCopyDisc(dm, dmc)); 9615 PetscCall(DMGetDS(dmc, &ds)); 9616 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9617 PetscCall(DMCreateGlobalVector(dmc, mass)); 9618 PetscCall(DMGetLocalVector(dmc, &ones)); 9619 PetscCall(DMGetLocalVector(dmc, &locmass)); 9620 PetscCall(DMPlexGetDepth(dmc, &depth)); 9621 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9622 PetscCall(VecSet(locmass, 0.0)); 9623 PetscCall(VecSet(ones, 1.0)); 9624 key.label = NULL; 9625 key.value = 0; 9626 key.field = 0; 9627 key.part = 0; 9628 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9629 PetscCall(ISDestroy(&cellIS)); 9630 PetscCall(VecSet(*mass, 0.0)); 9631 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9632 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9633 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9634 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9635 PetscCall(DMDestroy(&dmc)); 9636 PetscFunctionReturn(PETSC_SUCCESS); 9637 } 9638 9639 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9640 { 9641 PetscSection gsc, gsf; 9642 PetscInt m, n; 9643 void *ctx; 9644 DM cdm; 9645 PetscBool regular; 9646 9647 PetscFunctionBegin; 9648 if (dmFine == dmCoarse) { 9649 DM dmc; 9650 PetscDS ds; 9651 PetscWeakForm wf; 9652 Vec u; 9653 IS cellIS; 9654 PetscFormKey key; 9655 PetscInt depth; 9656 9657 PetscCall(DMClone(dmFine, &dmc)); 9658 PetscCall(DMCopyDisc(dmFine, dmc)); 9659 PetscCall(DMGetDS(dmc, &ds)); 9660 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9661 PetscCall(PetscWeakFormClear(wf)); 9662 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9663 PetscCall(DMCreateMatrix(dmc, mass)); 9664 PetscCall(DMGetLocalVector(dmc, &u)); 9665 PetscCall(DMPlexGetDepth(dmc, &depth)); 9666 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9667 PetscCall(MatZeroEntries(*mass)); 9668 key.label = NULL; 9669 key.value = 0; 9670 key.field = 0; 9671 key.part = 0; 9672 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9673 PetscCall(ISDestroy(&cellIS)); 9674 PetscCall(DMRestoreLocalVector(dmc, &u)); 9675 PetscCall(DMDestroy(&dmc)); 9676 } else { 9677 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9678 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9679 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9680 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9681 9682 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9683 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9684 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9685 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9686 9687 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9688 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9689 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9690 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9691 } 9692 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9693 PetscFunctionReturn(PETSC_SUCCESS); 9694 } 9695 9696 /*@ 9697 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9698 9699 Input Parameter: 9700 . dm - The `DMPLEX` object 9701 9702 Output Parameter: 9703 . regular - The flag 9704 9705 Level: intermediate 9706 9707 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9708 @*/ 9709 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9710 { 9711 PetscFunctionBegin; 9712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9713 PetscValidBoolPointer(regular, 2); 9714 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9715 PetscFunctionReturn(PETSC_SUCCESS); 9716 } 9717 9718 /*@ 9719 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9720 9721 Input Parameters: 9722 + dm - The `DMPLEX` object 9723 - regular - The flag 9724 9725 Level: intermediate 9726 9727 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9728 @*/ 9729 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9730 { 9731 PetscFunctionBegin; 9732 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9733 ((DM_Plex *)dm->data)->regularRefinement = regular; 9734 PetscFunctionReturn(PETSC_SUCCESS); 9735 } 9736 9737 /*@ 9738 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9739 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9740 9741 Not Collective 9742 9743 Input Parameter: 9744 . dm - The `DMPLEX` object 9745 9746 Output Parameters: 9747 + anchorSection - If not `NULL`, set to the section describing which points anchor the constrained points. 9748 - anchorIS - If not `NULL`, set to the list of anchors indexed by `anchorSection` 9749 9750 Level: intermediate 9751 9752 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9753 @*/ 9754 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9755 { 9756 DM_Plex *plex = (DM_Plex *)dm->data; 9757 9758 PetscFunctionBegin; 9759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9760 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9761 if (anchorSection) *anchorSection = plex->anchorSection; 9762 if (anchorIS) *anchorIS = plex->anchorIS; 9763 PetscFunctionReturn(PETSC_SUCCESS); 9764 } 9765 9766 /*@ 9767 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9768 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9769 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9770 9771 Collective 9772 9773 Input Parameters: 9774 + dm - The `DMPLEX` object 9775 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9776 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9777 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9778 9779 Level: intermediate 9780 9781 Notes: 9782 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9783 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9784 9785 The reference counts of `anchorSection` and `anchorIS` are incremented. 9786 9787 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9788 @*/ 9789 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9790 { 9791 DM_Plex *plex = (DM_Plex *)dm->data; 9792 PetscMPIInt result; 9793 9794 PetscFunctionBegin; 9795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9796 if (anchorSection) { 9797 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9798 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9799 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9800 } 9801 if (anchorIS) { 9802 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9803 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9804 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9805 } 9806 9807 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9808 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9809 plex->anchorSection = anchorSection; 9810 9811 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9812 PetscCall(ISDestroy(&plex->anchorIS)); 9813 plex->anchorIS = anchorIS; 9814 9815 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9816 PetscInt size, a, pStart, pEnd; 9817 const PetscInt *anchors; 9818 9819 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9820 PetscCall(ISGetLocalSize(anchorIS, &size)); 9821 PetscCall(ISGetIndices(anchorIS, &anchors)); 9822 for (a = 0; a < size; a++) { 9823 PetscInt p; 9824 9825 p = anchors[a]; 9826 if (p >= pStart && p < pEnd) { 9827 PetscInt dof; 9828 9829 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9830 if (dof) { 9831 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9832 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9833 } 9834 } 9835 } 9836 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9837 } 9838 /* reset the generic constraints */ 9839 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9840 PetscFunctionReturn(PETSC_SUCCESS); 9841 } 9842 9843 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9844 { 9845 PetscSection anchorSection; 9846 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9847 9848 PetscFunctionBegin; 9849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9850 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9851 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9852 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9853 if (numFields) { 9854 PetscInt f; 9855 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9856 9857 for (f = 0; f < numFields; f++) { 9858 PetscInt numComp; 9859 9860 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9861 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9862 } 9863 } 9864 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9865 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9866 pStart = PetscMax(pStart, sStart); 9867 pEnd = PetscMin(pEnd, sEnd); 9868 pEnd = PetscMax(pStart, pEnd); 9869 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9870 for (p = pStart; p < pEnd; p++) { 9871 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9872 if (dof) { 9873 PetscCall(PetscSectionGetDof(section, p, &dof)); 9874 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9875 for (f = 0; f < numFields; f++) { 9876 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9877 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9878 } 9879 } 9880 } 9881 PetscCall(PetscSectionSetUp(*cSec)); 9882 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9883 PetscFunctionReturn(PETSC_SUCCESS); 9884 } 9885 9886 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9887 { 9888 PetscSection aSec; 9889 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9890 const PetscInt *anchors; 9891 PetscInt numFields, f; 9892 IS aIS; 9893 MatType mtype; 9894 PetscBool iscuda, iskokkos; 9895 9896 PetscFunctionBegin; 9897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9898 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9899 PetscCall(PetscSectionGetStorageSize(section, &n)); 9900 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9901 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9902 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9903 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9904 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9905 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9906 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9907 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9908 else mtype = MATSEQAIJ; 9909 PetscCall(MatSetType(*cMat, mtype)); 9910 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9911 PetscCall(ISGetIndices(aIS, &anchors)); 9912 /* cSec will be a subset of aSec and section */ 9913 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9914 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9915 PetscCall(PetscMalloc1(m + 1, &i)); 9916 i[0] = 0; 9917 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9918 for (p = pStart; p < pEnd; p++) { 9919 PetscInt rDof, rOff, r; 9920 9921 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9922 if (!rDof) continue; 9923 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9924 if (numFields) { 9925 for (f = 0; f < numFields; f++) { 9926 annz = 0; 9927 for (r = 0; r < rDof; r++) { 9928 a = anchors[rOff + r]; 9929 if (a < sStart || a >= sEnd) continue; 9930 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9931 annz += aDof; 9932 } 9933 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9934 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9935 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9936 } 9937 } else { 9938 annz = 0; 9939 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9940 for (q = 0; q < dof; q++) { 9941 a = anchors[rOff + q]; 9942 if (a < sStart || a >= sEnd) continue; 9943 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9944 annz += aDof; 9945 } 9946 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9947 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9948 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9949 } 9950 } 9951 nnz = i[m]; 9952 PetscCall(PetscMalloc1(nnz, &j)); 9953 offset = 0; 9954 for (p = pStart; p < pEnd; p++) { 9955 if (numFields) { 9956 for (f = 0; f < numFields; f++) { 9957 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9958 for (q = 0; q < dof; q++) { 9959 PetscInt rDof, rOff, r; 9960 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9961 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9962 for (r = 0; r < rDof; r++) { 9963 PetscInt s; 9964 9965 a = anchors[rOff + r]; 9966 if (a < sStart || a >= sEnd) continue; 9967 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9968 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9969 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9970 } 9971 } 9972 } 9973 } else { 9974 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9975 for (q = 0; q < dof; q++) { 9976 PetscInt rDof, rOff, r; 9977 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9978 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9979 for (r = 0; r < rDof; r++) { 9980 PetscInt s; 9981 9982 a = anchors[rOff + r]; 9983 if (a < sStart || a >= sEnd) continue; 9984 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9985 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9986 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9987 } 9988 } 9989 } 9990 } 9991 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9992 PetscCall(PetscFree(i)); 9993 PetscCall(PetscFree(j)); 9994 PetscCall(ISRestoreIndices(aIS, &anchors)); 9995 PetscFunctionReturn(PETSC_SUCCESS); 9996 } 9997 9998 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9999 { 10000 DM_Plex *plex = (DM_Plex *)dm->data; 10001 PetscSection anchorSection, section, cSec; 10002 Mat cMat; 10003 10004 PetscFunctionBegin; 10005 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10006 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 10007 if (anchorSection) { 10008 PetscInt Nf; 10009 10010 PetscCall(DMGetLocalSection(dm, §ion)); 10011 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 10012 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 10013 PetscCall(DMGetNumFields(dm, &Nf)); 10014 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 10015 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10016 PetscCall(PetscSectionDestroy(&cSec)); 10017 PetscCall(MatDestroy(&cMat)); 10018 } 10019 PetscFunctionReturn(PETSC_SUCCESS); 10020 } 10021 10022 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10023 { 10024 IS subis; 10025 PetscSection section, subsection; 10026 10027 PetscFunctionBegin; 10028 PetscCall(DMGetLocalSection(dm, §ion)); 10029 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10030 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10031 /* Create subdomain */ 10032 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10033 /* Create submodel */ 10034 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10035 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10036 PetscCall(DMSetLocalSection(*subdm, subsection)); 10037 PetscCall(PetscSectionDestroy(&subsection)); 10038 PetscCall(DMCopyDisc(dm, *subdm)); 10039 /* Create map from submodel to global model */ 10040 if (is) { 10041 PetscSection sectionGlobal, subsectionGlobal; 10042 IS spIS; 10043 const PetscInt *spmap; 10044 PetscInt *subIndices; 10045 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10046 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10047 10048 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10049 PetscCall(ISGetIndices(spIS, &spmap)); 10050 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10051 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10052 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10053 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10054 for (p = pStart; p < pEnd; ++p) { 10055 PetscInt gdof, pSubSize = 0; 10056 10057 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10058 if (gdof > 0) { 10059 for (f = 0; f < Nf; ++f) { 10060 PetscInt fdof, fcdof; 10061 10062 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10063 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10064 pSubSize += fdof - fcdof; 10065 } 10066 subSize += pSubSize; 10067 if (pSubSize) { 10068 if (bs < 0) { 10069 bs = pSubSize; 10070 } else if (bs != pSubSize) { 10071 /* Layout does not admit a pointwise block size */ 10072 bs = 1; 10073 } 10074 } 10075 } 10076 } 10077 /* Must have same blocksize on all procs (some might have no points) */ 10078 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10079 bsLocal[1] = bs; 10080 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10081 if (bsMinMax[0] != bsMinMax[1]) { 10082 bs = 1; 10083 } else { 10084 bs = bsMinMax[0]; 10085 } 10086 PetscCall(PetscMalloc1(subSize, &subIndices)); 10087 for (p = pStart; p < pEnd; ++p) { 10088 PetscInt gdof, goff; 10089 10090 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10091 if (gdof > 0) { 10092 const PetscInt point = spmap[p]; 10093 10094 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10095 for (f = 0; f < Nf; ++f) { 10096 PetscInt fdof, fcdof, fc, f2, poff = 0; 10097 10098 /* Can get rid of this loop by storing field information in the global section */ 10099 for (f2 = 0; f2 < f; ++f2) { 10100 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10101 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10102 poff += fdof - fcdof; 10103 } 10104 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10105 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10106 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10107 } 10108 } 10109 } 10110 PetscCall(ISRestoreIndices(spIS, &spmap)); 10111 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10112 if (bs > 1) { 10113 /* We need to check that the block size does not come from non-contiguous fields */ 10114 PetscInt i, j, set = 1; 10115 for (i = 0; i < subSize; i += bs) { 10116 for (j = 0; j < bs; ++j) { 10117 if (subIndices[i + j] != subIndices[i] + j) { 10118 set = 0; 10119 break; 10120 } 10121 } 10122 } 10123 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10124 } 10125 /* Attach nullspace */ 10126 for (f = 0; f < Nf; ++f) { 10127 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10128 if ((*subdm)->nullspaceConstructors[f]) break; 10129 } 10130 if (f < Nf) { 10131 MatNullSpace nullSpace; 10132 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10133 10134 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10135 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10136 } 10137 } 10138 PetscFunctionReturn(PETSC_SUCCESS); 10139 } 10140 10141 /*@ 10142 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10143 10144 Input Parameters: 10145 + dm - The `DM` 10146 - dummy - unused argument 10147 10148 Options Database Key: 10149 . -dm_plex_monitor_throughput - Activate the monitor 10150 10151 Level: developer 10152 10153 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10154 @*/ 10155 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10156 { 10157 #if defined(PETSC_USE_LOG) 10158 PetscStageLog stageLog; 10159 PetscLogEvent event; 10160 PetscLogStage stage; 10161 PetscEventPerfInfo eventInfo; 10162 PetscReal cellRate, flopRate; 10163 PetscInt cStart, cEnd, Nf, N; 10164 const char *name; 10165 #endif 10166 10167 PetscFunctionBegin; 10168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10169 #if defined(PETSC_USE_LOG) 10170 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10171 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10172 PetscCall(DMGetNumFields(dm, &Nf)); 10173 PetscCall(PetscLogGetStageLog(&stageLog)); 10174 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10175 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10176 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10177 N = (cEnd - cStart) * Nf * eventInfo.count; 10178 flopRate = eventInfo.flops / eventInfo.time; 10179 cellRate = N / eventInfo.time; 10180 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))); 10181 #else 10182 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10183 #endif 10184 PetscFunctionReturn(PETSC_SUCCESS); 10185 } 10186