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