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