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; 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 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 35 { 36 DMPolytopeType ct; 37 PetscInt cStart, cEnd; 38 39 PetscFunctionBegin; 40 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 41 if (cEnd <= cStart) { 42 *simplex = PETSC_FALSE; 43 PetscFunctionReturn(0); 44 } 45 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 46 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 47 PetscFunctionReturn(0); 48 } 49 50 /*@ 51 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 52 53 Input Parameters: 54 + dm - The DMPlex object 55 - height - The cell height in the Plex, 0 is the default 56 57 Output Parameters: 58 + cStart - The first "normal" cell 59 - cEnd - The upper bound on "normal"" cells 60 61 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 62 63 Level: developer 64 65 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 66 @*/ 67 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 68 { 69 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 70 PetscInt cS, cE, c; 71 72 PetscFunctionBegin; 73 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 74 for (c = cS; c < cE; ++c) { 75 DMPolytopeType cct; 76 77 PetscCall(DMPlexGetCellType(dm, c, &cct)); 78 if ((PetscInt)cct < 0) break; 79 switch (cct) { 80 case DM_POLYTOPE_POINT: 81 case DM_POLYTOPE_SEGMENT: 82 case DM_POLYTOPE_TRIANGLE: 83 case DM_POLYTOPE_QUADRILATERAL: 84 case DM_POLYTOPE_TETRAHEDRON: 85 case DM_POLYTOPE_HEXAHEDRON: 86 ct = cct; 87 break; 88 default: 89 break; 90 } 91 if (ct != DM_POLYTOPE_UNKNOWN) break; 92 } 93 if (ct != DM_POLYTOPE_UNKNOWN) { 94 DMLabel ctLabel; 95 96 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 97 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 98 // Reset label for fast lookup 99 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 100 } 101 if (cStart) *cStart = cS; 102 if (cEnd) *cEnd = cE; 103 PetscFunctionReturn(0); 104 } 105 106 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 107 { 108 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 109 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 110 111 PetscFunctionBegin; 112 *ft = PETSC_VTK_INVALID; 113 PetscCall(DMGetCoordinateDim(dm, &cdim)); 114 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 115 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 116 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 117 if (field >= 0) { 118 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 119 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 120 } else { 121 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 122 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 123 } 124 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 125 if (globalvcdof[0]) { 126 *sStart = vStart; 127 *sEnd = vEnd; 128 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 129 else *ft = PETSC_VTK_POINT_FIELD; 130 } else if (globalvcdof[1]) { 131 *sStart = cStart; 132 *sEnd = cEnd; 133 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 134 else *ft = PETSC_VTK_CELL_FIELD; 135 } else { 136 if (field >= 0) { 137 const char *fieldname; 138 139 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 140 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 141 } else { 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 143 } 144 } 145 PetscFunctionReturn(0); 146 } 147 148 /*@ 149 DMPlexVecView1D - Plot many 1D solutions on the same line graph 150 151 Collective on dm 152 153 Input Parameters: 154 + dm - The DMPlex 155 . n - The number of vectors 156 . u - The array of local vectors 157 - viewer - The Draw viewer 158 159 Level: advanced 160 161 .seealso: `VecViewFromOptions()`, `VecView()` 162 @*/ 163 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 164 { 165 PetscDS ds; 166 PetscDraw draw = NULL; 167 PetscDrawLG lg; 168 Vec coordinates; 169 const PetscScalar *coords, **sol; 170 PetscReal *vals; 171 PetscInt *Nc; 172 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 173 char **names; 174 175 PetscFunctionBegin; 176 PetscCall(DMGetDS(dm, &ds)); 177 PetscCall(PetscDSGetNumFields(ds, &Nf)); 178 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 179 PetscCall(PetscDSGetComponents(ds, &Nc)); 180 181 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 182 if (!draw) PetscFunctionReturn(0); 183 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 184 185 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 186 for (i = 0, l = 0; i < n; ++i) { 187 const char *vname; 188 189 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 190 for (f = 0; f < Nf; ++f) { 191 PetscObject disc; 192 const char *fname; 193 char tmpname[PETSC_MAX_PATH_LEN]; 194 195 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 196 /* TODO Create names for components */ 197 for (c = 0; c < Nc[f]; ++c, ++l) { 198 PetscCall(PetscObjectGetName(disc, &fname)); 199 PetscCall(PetscStrcpy(tmpname, vname)); 200 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 201 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 202 PetscCall(PetscStrallocpy(tmpname, &names[l])); 203 } 204 } 205 } 206 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 207 /* Just add P_1 support for now */ 208 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 209 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 210 PetscCall(VecGetArrayRead(coordinates, &coords)); 211 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 212 for (v = vStart; v < vEnd; ++v) { 213 PetscScalar *x, *svals; 214 215 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 216 for (i = 0; i < n; ++i) { 217 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 218 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 219 } 220 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 221 } 222 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 223 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 224 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 225 PetscCall(PetscFree3(sol, names, vals)); 226 227 PetscCall(PetscDrawLGDraw(lg)); 228 PetscCall(PetscDrawLGDestroy(&lg)); 229 PetscFunctionReturn(0); 230 } 231 232 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 233 { 234 DM dm; 235 236 PetscFunctionBegin; 237 PetscCall(VecGetDM(u, &dm)); 238 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 239 PetscFunctionReturn(0); 240 } 241 242 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 243 { 244 DM dm; 245 PetscSection s; 246 PetscDraw draw, popup; 247 DM cdm; 248 PetscSection coordSection; 249 Vec coordinates; 250 const PetscScalar *coords, *array; 251 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 252 PetscReal vbound[2], time; 253 PetscBool flg; 254 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 255 const char *name; 256 char title[PETSC_MAX_PATH_LEN]; 257 258 PetscFunctionBegin; 259 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 260 PetscCall(VecGetDM(v, &dm)); 261 PetscCall(DMGetCoordinateDim(dm, &dim)); 262 PetscCall(DMGetLocalSection(dm, &s)); 263 PetscCall(PetscSectionGetNumFields(s, &Nf)); 264 PetscCall(DMGetCoarsenLevel(dm, &level)); 265 PetscCall(DMGetCoordinateDM(dm, &cdm)); 266 PetscCall(DMGetLocalSection(cdm, &coordSection)); 267 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 268 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 269 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 270 271 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 272 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 273 274 PetscCall(VecGetLocalSize(coordinates, &N)); 275 PetscCall(VecGetArrayRead(coordinates, &coords)); 276 for (c = 0; c < N; c += dim) { 277 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 278 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 279 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 280 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 281 } 282 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 283 PetscCall(PetscDrawClear(draw)); 284 285 /* Could implement something like DMDASelectFields() */ 286 for (f = 0; f < Nf; ++f) { 287 DM fdm = dm; 288 Vec fv = v; 289 IS fis; 290 char prefix[PETSC_MAX_PATH_LEN]; 291 const char *fname; 292 293 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 294 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 295 296 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 297 else prefix[0] = '\0'; 298 if (Nf > 1) { 299 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 300 PetscCall(VecGetSubVector(v, fis, &fv)); 301 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 302 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 303 } 304 for (comp = 0; comp < Nc; ++comp, ++w) { 305 PetscInt nmax = 2; 306 307 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 308 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 309 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 310 PetscCall(PetscDrawSetTitle(draw, title)); 311 312 /* TODO Get max and min only for this component */ 313 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 314 if (!flg) { 315 PetscCall(VecMin(fv, NULL, &vbound[0])); 316 PetscCall(VecMax(fv, NULL, &vbound[1])); 317 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 318 } 319 PetscCall(PetscDrawGetPopup(draw, &popup)); 320 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 321 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 322 323 PetscCall(VecGetArrayRead(fv, &array)); 324 for (c = cStart; c < cEnd; ++c) { 325 PetscScalar *coords = NULL, *a = NULL; 326 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 327 328 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 329 if (a) { 330 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 331 color[1] = color[2] = color[3] = color[0]; 332 } else { 333 PetscScalar *vals = NULL; 334 PetscInt numVals, va; 335 336 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 337 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); 338 switch (numVals / Nc) { 339 case 3: /* P1 Triangle */ 340 case 4: /* P1 Quadrangle */ 341 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 342 break; 343 case 6: /* P2 Triangle */ 344 case 8: /* P2 Quadrangle */ 345 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 346 break; 347 default: 348 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 349 } 350 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 351 } 352 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 353 switch (numCoords) { 354 case 6: 355 case 12: /* Localized triangle */ 356 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])); 357 break; 358 case 8: 359 case 16: /* Localized quadrilateral */ 360 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])); 361 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])); 362 break; 363 default: 364 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 365 } 366 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 367 } 368 PetscCall(VecRestoreArrayRead(fv, &array)); 369 PetscCall(PetscDrawFlush(draw)); 370 PetscCall(PetscDrawPause(draw)); 371 PetscCall(PetscDrawSave(draw)); 372 } 373 if (Nf > 1) { 374 PetscCall(VecRestoreSubVector(v, fis, &fv)); 375 PetscCall(ISDestroy(&fis)); 376 PetscCall(DMDestroy(&fdm)); 377 } 378 } 379 PetscFunctionReturn(0); 380 } 381 382 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 383 { 384 DM dm; 385 PetscDraw draw; 386 PetscInt dim; 387 PetscBool isnull; 388 389 PetscFunctionBegin; 390 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 391 PetscCall(PetscDrawIsNull(draw, &isnull)); 392 if (isnull) PetscFunctionReturn(0); 393 394 PetscCall(VecGetDM(v, &dm)); 395 PetscCall(DMGetCoordinateDim(dm, &dim)); 396 switch (dim) { 397 case 1: 398 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 399 break; 400 case 2: 401 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 402 break; 403 default: 404 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 405 } 406 PetscFunctionReturn(0); 407 } 408 409 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 410 { 411 DM dm; 412 Vec locv; 413 const char *name; 414 PetscSection section; 415 PetscInt pStart, pEnd; 416 PetscInt numFields; 417 PetscViewerVTKFieldType ft; 418 419 PetscFunctionBegin; 420 PetscCall(VecGetDM(v, &dm)); 421 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 422 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 423 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 424 PetscCall(VecCopy(v, locv)); 425 PetscCall(DMGetLocalSection(dm, §ion)); 426 PetscCall(PetscSectionGetNumFields(section, &numFields)); 427 if (!numFields) { 428 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 429 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 430 } else { 431 PetscInt f; 432 433 for (f = 0; f < numFields; f++) { 434 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 435 if (ft == PETSC_VTK_INVALID) continue; 436 PetscCall(PetscObjectReference((PetscObject)locv)); 437 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 438 } 439 PetscCall(VecDestroy(&locv)); 440 } 441 PetscFunctionReturn(0); 442 } 443 444 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 445 { 446 DM dm; 447 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 448 449 PetscFunctionBegin; 450 PetscCall(VecGetDM(v, &dm)); 451 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 453 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 454 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 455 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 456 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 457 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 458 PetscInt i, numFields; 459 PetscObject fe; 460 PetscBool fem = PETSC_FALSE; 461 Vec locv = v; 462 const char *name; 463 PetscInt step; 464 PetscReal time; 465 466 PetscCall(DMGetNumFields(dm, &numFields)); 467 for (i = 0; i < numFields; i++) { 468 PetscCall(DMGetField(dm, i, NULL, &fe)); 469 if (fe->classid == PETSCFE_CLASSID) { 470 fem = PETSC_TRUE; 471 break; 472 } 473 } 474 if (fem) { 475 PetscObject isZero; 476 477 PetscCall(DMGetLocalVector(dm, &locv)); 478 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 479 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 480 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 481 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 482 PetscCall(VecCopy(v, locv)); 483 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 484 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 485 } 486 if (isvtk) { 487 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 488 } else if (ishdf5) { 489 #if defined(PETSC_HAVE_HDF5) 490 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 491 #else 492 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 493 #endif 494 } else if (isdraw) { 495 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 496 } else if (isglvis) { 497 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 498 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 499 PetscCall(VecView_GLVis(locv, viewer)); 500 } else if (iscgns) { 501 #if defined(PETSC_HAVE_CGNS) 502 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 503 #else 504 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 505 #endif 506 } 507 if (fem) { 508 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 509 PetscCall(DMRestoreLocalVector(dm, &locv)); 510 } 511 } else { 512 PetscBool isseq; 513 514 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 515 if (isseq) PetscCall(VecView_Seq(v, viewer)); 516 else PetscCall(VecView_MPI(v, viewer)); 517 } 518 PetscFunctionReturn(0); 519 } 520 521 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 522 { 523 DM dm; 524 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 525 526 PetscFunctionBegin; 527 PetscCall(VecGetDM(v, &dm)); 528 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 529 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 530 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 532 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 535 if (isvtk || isdraw || isglvis || iscgns) { 536 Vec locv; 537 PetscObject isZero; 538 const char *name; 539 540 PetscCall(DMGetLocalVector(dm, &locv)); 541 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 542 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 543 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 544 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 545 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 546 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 547 PetscCall(VecView_Plex_Local(locv, viewer)); 548 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 549 PetscCall(DMRestoreLocalVector(dm, &locv)); 550 } else if (ishdf5) { 551 #if defined(PETSC_HAVE_HDF5) 552 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 553 #else 554 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 555 #endif 556 } else if (isexodusii) { 557 #if defined(PETSC_HAVE_EXODUSII) 558 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 559 #else 560 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 561 #endif 562 } else { 563 PetscBool isseq; 564 565 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 566 if (isseq) PetscCall(VecView_Seq(v, viewer)); 567 else PetscCall(VecView_MPI(v, viewer)); 568 } 569 PetscFunctionReturn(0); 570 } 571 572 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 573 { 574 DM dm; 575 MPI_Comm comm; 576 PetscViewerFormat format; 577 Vec v; 578 PetscBool isvtk, ishdf5; 579 580 PetscFunctionBegin; 581 PetscCall(VecGetDM(originalv, &dm)); 582 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 583 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 584 PetscCall(PetscViewerGetFormat(viewer, &format)); 585 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 586 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 587 if (format == PETSC_VIEWER_NATIVE) { 588 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 589 /* this need a better fix */ 590 if (dm->useNatural) { 591 if (dm->sfNatural) { 592 const char *vecname; 593 PetscInt n, nroots; 594 595 PetscCall(VecGetLocalSize(originalv, &n)); 596 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 597 if (n == nroots) { 598 PetscCall(DMGetGlobalVector(dm, &v)); 599 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 600 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 601 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 602 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 603 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 604 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 605 } else v = originalv; 606 } else v = originalv; 607 608 if (ishdf5) { 609 #if defined(PETSC_HAVE_HDF5) 610 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 611 #else 612 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 613 #endif 614 } else if (isvtk) { 615 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 if (ishdf5) { 637 DM dmBC; 638 Vec gv; 639 const char *name; 640 641 PetscCall(DMGetOutputDM(dm, &dmBC)); 642 PetscCall(DMGetGlobalVector(dmBC, &gv)); 643 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 644 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 645 PetscCall(VecLoad_Default(gv, viewer)); 646 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 647 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 648 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 649 } else PetscCall(VecLoad_Default(v, viewer)); 650 PetscFunctionReturn(0); 651 } 652 653 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 654 { 655 DM dm; 656 PetscBool ishdf5, isexodusii; 657 658 PetscFunctionBegin; 659 PetscCall(VecGetDM(v, &dm)); 660 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 661 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 662 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 663 if (ishdf5) { 664 #if defined(PETSC_HAVE_HDF5) 665 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 666 #else 667 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 668 #endif 669 } else if (isexodusii) { 670 #if defined(PETSC_HAVE_EXODUSII) 671 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 672 #else 673 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 674 #endif 675 } else PetscCall(VecLoad_Default(v, viewer)); 676 PetscFunctionReturn(0); 677 } 678 679 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 680 { 681 DM dm; 682 PetscViewerFormat format; 683 PetscBool ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 if (format == PETSC_VIEWER_NATIVE) { 691 if (dm->useNatural) { 692 if (dm->sfNatural) { 693 if (ishdf5) { 694 #if defined(PETSC_HAVE_HDF5) 695 Vec v; 696 const char *vecname; 697 698 PetscCall(DMGetGlobalVector(dm, &v)); 699 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 700 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 701 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 702 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 703 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 704 PetscCall(DMRestoreGlobalVector(dm, &v)); 705 #else 706 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 707 #endif 708 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 709 } 710 } else PetscCall(VecLoad_Default(originalv, viewer)); 711 } 712 PetscFunctionReturn(0); 713 } 714 715 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 716 { 717 PetscSection coordSection; 718 Vec coordinates; 719 DMLabel depthLabel, celltypeLabel; 720 const char *name[4]; 721 const PetscScalar *a; 722 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 723 724 PetscFunctionBegin; 725 PetscCall(DMGetDimension(dm, &dim)); 726 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 727 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 728 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 729 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 730 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 731 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 732 PetscCall(VecGetArrayRead(coordinates, &a)); 733 name[0] = "vertex"; 734 name[1] = "edge"; 735 name[dim - 1] = "face"; 736 name[dim] = "cell"; 737 for (c = cStart; c < cEnd; ++c) { 738 PetscInt *closure = NULL; 739 PetscInt closureSize, cl, ct; 740 741 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 742 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 743 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 744 PetscCall(PetscViewerASCIIPushTab(viewer)); 745 for (cl = 0; cl < closureSize * 2; cl += 2) { 746 PetscInt point = closure[cl], depth, dof, off, d, p; 747 748 if ((point < pStart) || (point >= pEnd)) continue; 749 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 750 if (!dof) continue; 751 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 752 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 753 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 754 for (p = 0; p < dof / dim; ++p) { 755 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 756 for (d = 0; d < dim; ++d) { 757 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 758 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 759 } 760 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 761 } 762 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 763 } 764 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 765 PetscCall(PetscViewerASCIIPopTab(viewer)); 766 } 767 PetscCall(VecRestoreArrayRead(coordinates, &a)); 768 PetscFunctionReturn(0); 769 } 770 771 typedef enum { 772 CS_CARTESIAN, 773 CS_POLAR, 774 CS_CYLINDRICAL, 775 CS_SPHERICAL 776 } CoordSystem; 777 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 778 779 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 780 { 781 PetscInt i; 782 783 PetscFunctionBegin; 784 if (dim > 3) { 785 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 786 } else { 787 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 788 789 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 790 switch (cs) { 791 case CS_CARTESIAN: 792 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 793 break; 794 case CS_POLAR: 795 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 796 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 797 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 798 break; 799 case CS_CYLINDRICAL: 800 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 801 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 802 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 803 trcoords[2] = coords[2]; 804 break; 805 case CS_SPHERICAL: 806 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 807 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 808 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 809 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 810 break; 811 } 812 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 813 } 814 PetscFunctionReturn(0); 815 } 816 817 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 818 { 819 DM_Plex *mesh = (DM_Plex *)dm->data; 820 DM cdm, cdmCell; 821 PetscSection coordSection, coordSectionCell; 822 Vec coordinates, coordinatesCell; 823 PetscViewerFormat format; 824 825 PetscFunctionBegin; 826 PetscCall(PetscViewerGetFormat(viewer, &format)); 827 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 828 const char *name; 829 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 830 PetscInt pStart, pEnd, p, numLabels, l; 831 PetscMPIInt rank, size; 832 833 PetscCall(DMGetCoordinateDM(dm, &cdm)); 834 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 835 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 836 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 837 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 838 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 839 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 840 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 841 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 842 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 843 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 844 PetscCall(DMGetDimension(dm, &dim)); 845 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 846 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 847 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 848 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 849 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 850 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 851 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 852 for (p = pStart; p < pEnd; ++p) { 853 PetscInt dof, off, s; 854 855 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 856 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 857 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 858 } 859 PetscCall(PetscViewerFlush(viewer)); 860 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 861 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 862 for (p = pStart; p < pEnd; ++p) { 863 PetscInt dof, off, c; 864 865 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 866 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 867 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])); 868 } 869 PetscCall(PetscViewerFlush(viewer)); 870 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 871 if (coordSection && coordinates) { 872 CoordSystem cs = CS_CARTESIAN; 873 const PetscScalar *array, *arrayCell = NULL; 874 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 875 PetscMPIInt rank; 876 const char *name; 877 878 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 879 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 880 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 881 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 882 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 883 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 884 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 885 pStart = PetscMin(pvStart, pcStart); 886 pEnd = PetscMax(pvEnd, pcEnd); 887 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 888 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 889 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 890 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 891 892 PetscCall(VecGetArrayRead(coordinates, &array)); 893 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 894 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 895 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 896 for (p = pStart; p < pEnd; ++p) { 897 PetscInt dof, off; 898 899 if (p >= pvStart && p < pvEnd) { 900 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 901 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 902 if (dof) { 903 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 904 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 905 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 906 } 907 } 908 if (cdmCell && p >= pcStart && p < pcEnd) { 909 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 910 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 911 if (dof) { 912 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 913 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 914 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 915 } 916 } 917 } 918 PetscCall(PetscViewerFlush(viewer)); 919 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 920 PetscCall(VecRestoreArrayRead(coordinates, &array)); 921 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 922 } 923 PetscCall(DMGetNumLabels(dm, &numLabels)); 924 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 925 for (l = 0; l < numLabels; ++l) { 926 DMLabel label; 927 PetscBool isdepth; 928 const char *name; 929 930 PetscCall(DMGetLabelName(dm, l, &name)); 931 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 932 if (isdepth) continue; 933 PetscCall(DMGetLabel(dm, name, &label)); 934 PetscCall(DMLabelView(label, viewer)); 935 } 936 if (size > 1) { 937 PetscSF sf; 938 939 PetscCall(DMGetPointSF(dm, &sf)); 940 PetscCall(PetscSFView(sf, viewer)); 941 } 942 PetscCall(PetscViewerFlush(viewer)); 943 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 944 const char *name, *color; 945 const char *defcolors[3] = {"gray", "orange", "green"}; 946 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 947 char lname[PETSC_MAX_PATH_LEN]; 948 PetscReal scale = 2.0; 949 PetscReal tikzscale = 1.0; 950 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 951 double tcoords[3]; 952 PetscScalar *coords; 953 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 954 PetscMPIInt rank, size; 955 char **names, **colors, **lcolors; 956 PetscBool flg, lflg; 957 PetscBT wp = NULL; 958 PetscInt pEnd, pStart; 959 960 PetscCall(DMGetCoordinateDM(dm, &cdm)); 961 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 962 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 963 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 964 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 965 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 966 PetscCall(DMGetDimension(dm, &dim)); 967 PetscCall(DMPlexGetDepth(dm, &depth)); 968 PetscCall(DMGetNumLabels(dm, &numLabels)); 969 numLabels = PetscMax(numLabels, 10); 970 numColors = 10; 971 numLColors = 10; 972 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 973 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 974 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 975 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 976 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 977 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 978 n = 4; 979 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &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(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 982 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 983 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 984 if (!useLabels) numLabels = 0; 985 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 986 if (!useColors) { 987 numColors = 3; 988 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 989 } 990 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 991 if (!useColors) { 992 numLColors = 4; 993 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 994 } 995 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 996 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 997 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 998 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 999 if (depth < dim) plotEdges = PETSC_FALSE; 1000 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1001 1002 /* filter points with labelvalue != labeldefaultvalue */ 1003 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1004 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1005 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1006 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1007 if (lflg) { 1008 DMLabel lbl; 1009 1010 PetscCall(DMGetLabel(dm, lname, &lbl)); 1011 if (lbl) { 1012 PetscInt val, defval; 1013 1014 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1015 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1016 for (c = pStart; c < pEnd; c++) { 1017 PetscInt *closure = NULL; 1018 PetscInt closureSize; 1019 1020 PetscCall(DMLabelGetValue(lbl, c, &val)); 1021 if (val == defval) continue; 1022 1023 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1024 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1025 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1026 } 1027 } 1028 } 1029 1030 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1031 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1032 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1033 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1034 \\documentclass[tikz]{standalone}\n\n\ 1035 \\usepackage{pgflibraryshapes}\n\ 1036 \\usetikzlibrary{backgrounds}\n\ 1037 \\usetikzlibrary{arrows}\n\ 1038 \\begin{document}\n")); 1039 if (size > 1) { 1040 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1041 for (p = 0; p < size; ++p) { 1042 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1043 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1044 } 1045 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1046 } 1047 if (drawHasse) { 1048 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1049 1050 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1058 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1060 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1062 } 1063 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1064 1065 /* Plot vertices */ 1066 PetscCall(VecGetArray(coordinates, &coords)); 1067 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1068 for (v = vStart; v < vEnd; ++v) { 1069 PetscInt off, dof, d; 1070 PetscBool isLabeled = PETSC_FALSE; 1071 1072 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1073 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1074 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1075 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1076 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1077 for (d = 0; d < dof; ++d) { 1078 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1079 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1080 } 1081 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1082 if (dim == 3) { 1083 PetscReal tmp = tcoords[1]; 1084 tcoords[1] = tcoords[2]; 1085 tcoords[2] = -tmp; 1086 } 1087 for (d = 0; d < dof; ++d) { 1088 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1089 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1090 } 1091 if (drawHasse) color = colors[0 % numColors]; 1092 else color = colors[rank % numColors]; 1093 for (l = 0; l < numLabels; ++l) { 1094 PetscInt val; 1095 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1096 if (val >= 0) { 1097 color = lcolors[l % numLColors]; 1098 isLabeled = PETSC_TRUE; 1099 break; 1100 } 1101 } 1102 if (drawNumbers[0]) { 1103 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1104 } else if (drawColors[0]) { 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1106 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1107 } 1108 PetscCall(VecRestoreArray(coordinates, &coords)); 1109 PetscCall(PetscViewerFlush(viewer)); 1110 /* Plot edges */ 1111 if (plotEdges) { 1112 PetscCall(VecGetArray(coordinates, &coords)); 1113 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1114 for (e = eStart; e < eEnd; ++e) { 1115 const PetscInt *cone; 1116 PetscInt coneSize, offA, offB, dof, d; 1117 1118 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1119 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1120 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1121 PetscCall(DMPlexGetCone(dm, e, &cone)); 1122 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1123 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1124 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1125 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1126 for (d = 0; d < dof; ++d) { 1127 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1128 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1129 } 1130 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1131 if (dim == 3) { 1132 PetscReal tmp = tcoords[1]; 1133 tcoords[1] = tcoords[2]; 1134 tcoords[2] = -tmp; 1135 } 1136 for (d = 0; d < dof; ++d) { 1137 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1138 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1139 } 1140 if (drawHasse) color = colors[1 % numColors]; 1141 else color = colors[rank % numColors]; 1142 for (l = 0; l < numLabels; ++l) { 1143 PetscInt val; 1144 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1145 if (val >= 0) { 1146 color = lcolors[l % numLColors]; 1147 break; 1148 } 1149 } 1150 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1151 } 1152 PetscCall(VecRestoreArray(coordinates, &coords)); 1153 PetscCall(PetscViewerFlush(viewer)); 1154 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1155 } 1156 /* Plot cells */ 1157 if (dim == 3 || !drawNumbers[1]) { 1158 for (e = eStart; e < eEnd; ++e) { 1159 const PetscInt *cone; 1160 1161 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1162 color = colors[rank % numColors]; 1163 for (l = 0; l < numLabels; ++l) { 1164 PetscInt val; 1165 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1166 if (val >= 0) { 1167 color = lcolors[l % numLColors]; 1168 break; 1169 } 1170 } 1171 PetscCall(DMPlexGetCone(dm, e, &cone)); 1172 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1173 } 1174 } else { 1175 DMPolytopeType ct; 1176 1177 /* Drawing a 2D polygon */ 1178 for (c = cStart; c < cEnd; ++c) { 1179 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1180 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1181 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1182 const PetscInt *cone; 1183 PetscInt coneSize, e; 1184 1185 PetscCall(DMPlexGetCone(dm, c, &cone)); 1186 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1187 for (e = 0; e < coneSize; ++e) { 1188 const PetscInt *econe; 1189 1190 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1191 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)); 1192 } 1193 } else { 1194 PetscInt *closure = NULL; 1195 PetscInt closureSize, Nv = 0, v; 1196 1197 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1198 for (p = 0; p < closureSize * 2; p += 2) { 1199 const PetscInt point = closure[p]; 1200 1201 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1202 } 1203 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1204 for (v = 0; v <= Nv; ++v) { 1205 const PetscInt vertex = closure[v % Nv]; 1206 1207 if (v > 0) { 1208 if (plotEdges) { 1209 const PetscInt *edge; 1210 PetscInt endpoints[2], ne; 1211 1212 endpoints[0] = closure[v - 1]; 1213 endpoints[1] = vertex; 1214 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1215 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1216 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1217 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1218 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1219 } 1220 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1221 } 1222 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1223 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1224 } 1225 } 1226 } 1227 for (c = cStart; c < cEnd; ++c) { 1228 double ccoords[3] = {0.0, 0.0, 0.0}; 1229 PetscBool isLabeled = PETSC_FALSE; 1230 PetscScalar *cellCoords = NULL; 1231 const PetscScalar *array; 1232 PetscInt numCoords, cdim, d; 1233 PetscBool isDG; 1234 1235 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1236 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1237 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1238 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1239 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1240 for (p = 0; p < numCoords / cdim; ++p) { 1241 for (d = 0; d < cdim; ++d) { 1242 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1243 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1244 } 1245 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1246 if (cdim == 3) { 1247 PetscReal tmp = tcoords[1]; 1248 tcoords[1] = tcoords[2]; 1249 tcoords[2] = -tmp; 1250 } 1251 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1252 } 1253 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1254 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1255 for (d = 0; d < cdim; ++d) { 1256 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1257 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1258 } 1259 if (drawHasse) color = colors[depth % numColors]; 1260 else color = colors[rank % numColors]; 1261 for (l = 0; l < numLabels; ++l) { 1262 PetscInt val; 1263 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1264 if (val >= 0) { 1265 color = lcolors[l % numLColors]; 1266 isLabeled = PETSC_TRUE; 1267 break; 1268 } 1269 } 1270 if (drawNumbers[dim]) { 1271 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1272 } else if (drawColors[dim]) { 1273 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1274 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1275 } 1276 if (drawHasse) { 1277 color = colors[depth % numColors]; 1278 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1279 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1280 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1281 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1282 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1283 1284 color = colors[1 % numColors]; 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1286 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1287 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1288 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1289 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1290 1291 color = colors[0 % numColors]; 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1293 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1294 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1295 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1296 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1297 1298 for (p = pStart; p < pEnd; ++p) { 1299 const PetscInt *cone; 1300 PetscInt coneSize, cp; 1301 1302 PetscCall(DMPlexGetCone(dm, p, &cone)); 1303 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1304 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1305 } 1306 } 1307 PetscCall(PetscViewerFlush(viewer)); 1308 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1309 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1310 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1311 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1312 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1313 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1314 PetscCall(PetscFree3(names, colors, lcolors)); 1315 PetscCall(PetscBTDestroy(&wp)); 1316 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1317 Vec cown, acown; 1318 VecScatter sct; 1319 ISLocalToGlobalMapping g2l; 1320 IS gid, acis; 1321 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1322 MPI_Group ggroup, ngroup; 1323 PetscScalar *array, nid; 1324 const PetscInt *idxs; 1325 PetscInt *idxs2, *start, *adjacency, *work; 1326 PetscInt64 lm[3], gm[3]; 1327 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1328 PetscMPIInt d1, d2, rank; 1329 1330 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1331 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1332 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1333 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1334 #endif 1335 if (ncomm != MPI_COMM_NULL) { 1336 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1337 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1338 d1 = 0; 1339 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1340 nid = d2; 1341 PetscCallMPI(MPI_Group_free(&ggroup)); 1342 PetscCallMPI(MPI_Group_free(&ngroup)); 1343 PetscCallMPI(MPI_Comm_free(&ncomm)); 1344 } else nid = 0.0; 1345 1346 /* Get connectivity */ 1347 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1348 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1349 1350 /* filter overlapped local cells */ 1351 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1352 PetscCall(ISGetIndices(gid, &idxs)); 1353 PetscCall(ISGetLocalSize(gid, &cum)); 1354 PetscCall(PetscMalloc1(cum, &idxs2)); 1355 for (c = cStart, cum = 0; c < cEnd; c++) { 1356 if (idxs[c - cStart] < 0) continue; 1357 idxs2[cum++] = idxs[c - cStart]; 1358 } 1359 PetscCall(ISRestoreIndices(gid, &idxs)); 1360 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1361 PetscCall(ISDestroy(&gid)); 1362 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1363 1364 /* support for node-aware cell locality */ 1365 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1366 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1367 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1368 PetscCall(VecGetArray(cown, &array)); 1369 for (c = 0; c < numVertices; c++) array[c] = nid; 1370 PetscCall(VecRestoreArray(cown, &array)); 1371 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1372 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1373 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1374 PetscCall(ISDestroy(&acis)); 1375 PetscCall(VecScatterDestroy(&sct)); 1376 PetscCall(VecDestroy(&cown)); 1377 1378 /* compute edgeCut */ 1379 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1380 PetscCall(PetscMalloc1(cum, &work)); 1381 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1382 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1383 PetscCall(ISDestroy(&gid)); 1384 PetscCall(VecGetArray(acown, &array)); 1385 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1386 PetscInt totl; 1387 1388 totl = start[c + 1] - start[c]; 1389 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1390 for (i = 0; i < totl; i++) { 1391 if (work[i] < 0) { 1392 ect += 1; 1393 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1394 } 1395 } 1396 } 1397 PetscCall(PetscFree(work)); 1398 PetscCall(VecRestoreArray(acown, &array)); 1399 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1400 lm[1] = -numVertices; 1401 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1403 lm[0] = ect; /* edgeCut */ 1404 lm[1] = ectn; /* node-aware edgeCut */ 1405 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1406 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1407 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1408 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1409 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1410 #else 1411 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1412 #endif 1413 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1414 PetscCall(PetscFree(start)); 1415 PetscCall(PetscFree(adjacency)); 1416 PetscCall(VecDestroy(&acown)); 1417 } else { 1418 const char *name; 1419 PetscInt *sizes, *hybsizes, *ghostsizes; 1420 PetscInt locDepth, depth, cellHeight, dim, d; 1421 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1422 PetscInt numLabels, l, maxSize = 17; 1423 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1424 MPI_Comm comm; 1425 PetscMPIInt size, rank; 1426 1427 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1428 PetscCallMPI(MPI_Comm_size(comm, &size)); 1429 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1430 PetscCall(DMGetDimension(dm, &dim)); 1431 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1432 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1433 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1434 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1435 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1436 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1437 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1438 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1439 gcNum = gcEnd - gcStart; 1440 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1441 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1442 for (d = 0; d <= depth; d++) { 1443 PetscInt Nc[2] = {0, 0}, ict; 1444 1445 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1446 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1447 ict = ct0; 1448 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1449 ct0 = (DMPolytopeType)ict; 1450 for (p = pStart; p < pEnd; ++p) { 1451 DMPolytopeType ct; 1452 1453 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1454 if (ct == ct0) ++Nc[0]; 1455 else ++Nc[1]; 1456 } 1457 if (size < maxSize) { 1458 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1459 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1460 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1461 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1462 for (p = 0; p < size; ++p) { 1463 if (rank == 0) { 1464 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1465 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1466 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1467 } 1468 } 1469 } else { 1470 PetscInt locMinMax[2]; 1471 1472 locMinMax[0] = Nc[0] + Nc[1]; 1473 locMinMax[1] = Nc[0] + Nc[1]; 1474 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1475 locMinMax[0] = Nc[1]; 1476 locMinMax[1] = Nc[1]; 1477 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1478 if (d == depth) { 1479 locMinMax[0] = gcNum; 1480 locMinMax[1] = gcNum; 1481 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1482 } 1483 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1484 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1485 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1486 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1487 } 1488 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1489 } 1490 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1491 { 1492 const PetscReal *maxCell; 1493 const PetscReal *L; 1494 PetscBool localized; 1495 1496 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1497 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1498 if (L || localized) { 1499 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1500 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1501 if (L) { 1502 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1503 for (d = 0; d < dim; ++d) { 1504 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1505 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1506 } 1507 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1508 } 1509 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1510 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1511 } 1512 } 1513 PetscCall(DMGetNumLabels(dm, &numLabels)); 1514 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1515 for (l = 0; l < numLabels; ++l) { 1516 DMLabel label; 1517 const char *name; 1518 IS valueIS; 1519 const PetscInt *values; 1520 PetscInt numValues, v; 1521 1522 PetscCall(DMGetLabelName(dm, l, &name)); 1523 PetscCall(DMGetLabel(dm, name, &label)); 1524 PetscCall(DMLabelGetNumValues(label, &numValues)); 1525 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1526 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1527 PetscCall(ISGetIndices(valueIS, &values)); 1528 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1529 for (v = 0; v < numValues; ++v) { 1530 PetscInt size; 1531 1532 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1533 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1534 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1535 } 1536 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1537 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1538 PetscCall(ISRestoreIndices(valueIS, &values)); 1539 PetscCall(ISDestroy(&valueIS)); 1540 } 1541 { 1542 char **labelNames; 1543 PetscInt Nl = numLabels; 1544 PetscBool flg; 1545 1546 PetscCall(PetscMalloc1(Nl, &labelNames)); 1547 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1548 for (l = 0; l < Nl; ++l) { 1549 DMLabel label; 1550 1551 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1552 if (flg) { 1553 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1554 PetscCall(DMLabelView(label, viewer)); 1555 } 1556 PetscCall(PetscFree(labelNames[l])); 1557 } 1558 PetscCall(PetscFree(labelNames)); 1559 } 1560 /* If no fields are specified, people do not want to see adjacency */ 1561 if (dm->Nf) { 1562 PetscInt f; 1563 1564 for (f = 0; f < dm->Nf; ++f) { 1565 const char *name; 1566 1567 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1568 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1569 PetscCall(PetscViewerASCIIPushTab(viewer)); 1570 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1571 if (dm->fields[f].adjacency[0]) { 1572 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1573 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1574 } else { 1575 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1576 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1577 } 1578 PetscCall(PetscViewerASCIIPopTab(viewer)); 1579 } 1580 } 1581 PetscCall(DMGetCoarseDM(dm, &cdm)); 1582 if (cdm) { 1583 PetscCall(PetscViewerASCIIPushTab(viewer)); 1584 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1585 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1586 PetscCall(PetscViewerASCIIPopTab(viewer)); 1587 } 1588 } 1589 PetscFunctionReturn(0); 1590 } 1591 1592 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1593 { 1594 DMPolytopeType ct; 1595 PetscMPIInt rank; 1596 PetscInt cdim; 1597 1598 PetscFunctionBegin; 1599 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1600 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1601 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1602 switch (ct) { 1603 case DM_POLYTOPE_SEGMENT: 1604 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1605 switch (cdim) { 1606 case 1: { 1607 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1608 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1609 1610 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1611 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1612 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1613 } break; 1614 case 2: { 1615 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1616 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1617 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1618 1619 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1620 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)); 1621 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)); 1622 } break; 1623 default: 1624 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1625 } 1626 break; 1627 case DM_POLYTOPE_TRIANGLE: 1628 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)); 1629 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1630 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1631 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1632 break; 1633 case DM_POLYTOPE_QUADRILATERAL: 1634 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)); 1635 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)); 1636 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1637 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1638 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1639 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1640 break; 1641 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1642 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)); 1643 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)); 1644 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1645 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1646 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1647 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1648 break; 1649 case DM_POLYTOPE_FV_GHOST: 1650 break; 1651 default: 1652 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1653 } 1654 PetscFunctionReturn(0); 1655 } 1656 1657 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1658 { 1659 DMPolytopeType ct; 1660 PetscReal centroid[2] = {0., 0.}; 1661 PetscMPIInt rank; 1662 PetscInt fillColor, v, e, d; 1663 1664 PetscFunctionBegin; 1665 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1666 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1667 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1668 switch (ct) { 1669 case DM_POLYTOPE_TRIANGLE: { 1670 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1671 1672 for (v = 0; v < 3; ++v) { 1673 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1674 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1675 } 1676 for (e = 0; e < 3; ++e) { 1677 refCoords[0] = refVertices[e * 2 + 0]; 1678 refCoords[1] = refVertices[e * 2 + 1]; 1679 for (d = 1; d <= edgeDiv; ++d) { 1680 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1681 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1682 } 1683 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1684 for (d = 0; d < edgeDiv; ++d) { 1685 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)); 1686 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1687 } 1688 } 1689 } break; 1690 default: 1691 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1692 } 1693 PetscFunctionReturn(0); 1694 } 1695 1696 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1697 { 1698 PetscDraw draw; 1699 DM cdm; 1700 PetscSection coordSection; 1701 Vec coordinates; 1702 const PetscScalar *coords; 1703 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1704 PetscReal *refCoords, *edgeCoords; 1705 PetscBool isnull, drawAffine = PETSC_TRUE; 1706 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1707 1708 PetscFunctionBegin; 1709 PetscCall(DMGetCoordinateDim(dm, &dim)); 1710 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1711 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1712 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1713 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1714 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1715 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1716 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1717 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1718 1719 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1720 PetscCall(PetscDrawIsNull(draw, &isnull)); 1721 if (isnull) PetscFunctionReturn(0); 1722 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1723 1724 PetscCall(VecGetLocalSize(coordinates, &N)); 1725 PetscCall(VecGetArrayRead(coordinates, &coords)); 1726 for (c = 0; c < N; c += dim) { 1727 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1728 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1729 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1730 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1731 } 1732 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1733 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1734 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1735 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1736 PetscCall(PetscDrawClear(draw)); 1737 1738 for (c = cStart; c < cEnd; ++c) { 1739 PetscScalar *coords = NULL; 1740 PetscInt numCoords; 1741 1742 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1743 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1744 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1745 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1746 } 1747 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1748 PetscCall(PetscDrawFlush(draw)); 1749 PetscCall(PetscDrawPause(draw)); 1750 PetscCall(PetscDrawSave(draw)); 1751 PetscFunctionReturn(0); 1752 } 1753 1754 #if defined(PETSC_HAVE_EXODUSII) 1755 #include <exodusII.h> 1756 #include <petscviewerexodusii.h> 1757 #endif 1758 1759 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1760 { 1761 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1762 char name[PETSC_MAX_PATH_LEN]; 1763 1764 PetscFunctionBegin; 1765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1766 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1767 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1768 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1769 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1770 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1771 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1774 if (iascii) { 1775 PetscViewerFormat format; 1776 PetscCall(PetscViewerGetFormat(viewer, &format)); 1777 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1778 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1779 } else if (ishdf5) { 1780 #if defined(PETSC_HAVE_HDF5) 1781 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1782 #else 1783 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1784 #endif 1785 } else if (isvtk) { 1786 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1787 } else if (isdraw) { 1788 PetscCall(DMPlexView_Draw(dm, viewer)); 1789 } else if (isglvis) { 1790 PetscCall(DMPlexView_GLVis(dm, viewer)); 1791 #if defined(PETSC_HAVE_EXODUSII) 1792 } else if (isexodus) { 1793 /* 1794 exodusII requires that all sets be part of exactly one cell set. 1795 If the dm does not have a "Cell Sets" label defined, we create one 1796 with ID 1, containig all cells. 1797 Note that if the Cell Sets label is defined but does not cover all cells, 1798 we may still have a problem. This should probably be checked here or in the viewer; 1799 */ 1800 PetscInt numCS; 1801 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1802 if (!numCS) { 1803 PetscInt cStart, cEnd, c; 1804 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1805 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1806 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1807 } 1808 PetscCall(DMView_PlexExodusII(dm, viewer)); 1809 #endif 1810 #if defined(PETSC_HAVE_CGNS) 1811 } else if (iscgns) { 1812 PetscCall(DMView_PlexCGNS(dm, viewer)); 1813 #endif 1814 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1815 /* Optionally view the partition */ 1816 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1817 if (flg) { 1818 Vec ranks; 1819 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1820 PetscCall(VecView(ranks, viewer)); 1821 PetscCall(VecDestroy(&ranks)); 1822 } 1823 /* Optionally view a label */ 1824 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1825 if (flg) { 1826 DMLabel label; 1827 Vec val; 1828 1829 PetscCall(DMGetLabel(dm, name, &label)); 1830 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1831 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1832 PetscCall(VecView(val, viewer)); 1833 PetscCall(VecDestroy(&val)); 1834 } 1835 PetscFunctionReturn(0); 1836 } 1837 1838 /*@ 1839 DMPlexTopologyView - Saves a DMPlex topology into a file 1840 1841 Collective on DM 1842 1843 Input Parameters: 1844 + dm - The DM whose topology is to be saved 1845 - viewer - The PetscViewer for saving 1846 1847 Level: advanced 1848 1849 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1850 @*/ 1851 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1852 { 1853 PetscBool ishdf5; 1854 1855 PetscFunctionBegin; 1856 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1857 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1858 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1859 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1860 if (ishdf5) { 1861 #if defined(PETSC_HAVE_HDF5) 1862 PetscViewerFormat format; 1863 PetscCall(PetscViewerGetFormat(viewer, &format)); 1864 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1865 IS globalPointNumbering; 1866 1867 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1868 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1869 PetscCall(ISDestroy(&globalPointNumbering)); 1870 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1871 #else 1872 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1873 #endif 1874 } 1875 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1876 PetscFunctionReturn(0); 1877 } 1878 1879 /*@ 1880 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1881 1882 Collective on DM 1883 1884 Input Parameters: 1885 + dm - The DM whose coordinates are to be saved 1886 - viewer - The PetscViewer for saving 1887 1888 Level: advanced 1889 1890 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1891 @*/ 1892 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1893 { 1894 PetscBool ishdf5; 1895 1896 PetscFunctionBegin; 1897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1898 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1899 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1900 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1901 if (ishdf5) { 1902 #if defined(PETSC_HAVE_HDF5) 1903 PetscViewerFormat format; 1904 PetscCall(PetscViewerGetFormat(viewer, &format)); 1905 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1906 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1907 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1908 #else 1909 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1910 #endif 1911 } 1912 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1913 PetscFunctionReturn(0); 1914 } 1915 1916 /*@ 1917 DMPlexLabelsView - Saves DMPlex labels into a file 1918 1919 Collective on DM 1920 1921 Input Parameters: 1922 + dm - The DM whose labels are to be saved 1923 - viewer - The PetscViewer for saving 1924 1925 Level: advanced 1926 1927 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1928 @*/ 1929 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1930 { 1931 PetscBool ishdf5; 1932 1933 PetscFunctionBegin; 1934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1935 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1936 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1937 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1938 if (ishdf5) { 1939 #if defined(PETSC_HAVE_HDF5) 1940 IS globalPointNumbering; 1941 PetscViewerFormat format; 1942 1943 PetscCall(PetscViewerGetFormat(viewer, &format)); 1944 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1945 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1946 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1947 PetscCall(ISDestroy(&globalPointNumbering)); 1948 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1949 #else 1950 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1951 #endif 1952 } 1953 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1954 PetscFunctionReturn(0); 1955 } 1956 1957 /*@ 1958 DMPlexSectionView - Saves a section associated with a DMPlex 1959 1960 Collective on DM 1961 1962 Input Parameters: 1963 + dm - The DM that contains the topology on which the section to be saved is defined 1964 . viewer - The PetscViewer for saving 1965 - sectiondm - The DM that contains the section to be saved 1966 1967 Level: advanced 1968 1969 Notes: 1970 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. 1971 1972 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. 1973 1974 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1975 @*/ 1976 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1977 { 1978 PetscBool ishdf5; 1979 1980 PetscFunctionBegin; 1981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1982 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1983 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1984 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1985 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1986 if (ishdf5) { 1987 #if defined(PETSC_HAVE_HDF5) 1988 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1989 #else 1990 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1991 #endif 1992 } 1993 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1994 PetscFunctionReturn(0); 1995 } 1996 1997 /*@ 1998 DMPlexGlobalVectorView - Saves a global vector 1999 2000 Collective on DM 2001 2002 Input Parameters: 2003 + dm - The DM that represents the topology 2004 . viewer - The PetscViewer to save data with 2005 . sectiondm - The DM that contains the global section on which vec is defined 2006 - vec - The global vector to be saved 2007 2008 Level: advanced 2009 2010 Notes: 2011 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. 2012 2013 Typical calling sequence 2014 $ DMCreate(PETSC_COMM_WORLD, &dm); 2015 $ DMSetType(dm, DMPLEX); 2016 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2017 $ DMClone(dm, §iondm); 2018 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2019 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2020 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2021 $ PetscSectionSetChart(section, pStart, pEnd); 2022 $ PetscSectionSetUp(section); 2023 $ DMSetLocalSection(sectiondm, section); 2024 $ PetscSectionDestroy(§ion); 2025 $ DMGetGlobalVector(sectiondm, &vec); 2026 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2027 $ DMPlexTopologyView(dm, viewer); 2028 $ DMPlexSectionView(dm, viewer, sectiondm); 2029 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2030 $ DMRestoreGlobalVector(sectiondm, &vec); 2031 $ DMDestroy(§iondm); 2032 $ DMDestroy(&dm); 2033 2034 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2035 @*/ 2036 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2037 { 2038 PetscBool ishdf5; 2039 2040 PetscFunctionBegin; 2041 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2042 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2043 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2044 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2045 /* Check consistency */ 2046 { 2047 PetscSection section; 2048 PetscBool includesConstraints; 2049 PetscInt m, m1; 2050 2051 PetscCall(VecGetLocalSize(vec, &m1)); 2052 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2053 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2054 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2055 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2056 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2057 } 2058 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2059 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2060 if (ishdf5) { 2061 #if defined(PETSC_HAVE_HDF5) 2062 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2063 #else 2064 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2065 #endif 2066 } 2067 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2068 PetscFunctionReturn(0); 2069 } 2070 2071 /*@ 2072 DMPlexLocalVectorView - Saves a local vector 2073 2074 Collective on DM 2075 2076 Input Parameters: 2077 + dm - The DM that represents the topology 2078 . viewer - The PetscViewer to save data with 2079 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2080 - vec - The local vector to be saved 2081 2082 Level: advanced 2083 2084 Notes: 2085 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. 2086 2087 Typical calling sequence 2088 $ DMCreate(PETSC_COMM_WORLD, &dm); 2089 $ DMSetType(dm, DMPLEX); 2090 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2091 $ DMClone(dm, §iondm); 2092 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2093 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2094 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2095 $ PetscSectionSetChart(section, pStart, pEnd); 2096 $ PetscSectionSetUp(section); 2097 $ DMSetLocalSection(sectiondm, section); 2098 $ DMGetLocalVector(sectiondm, &vec); 2099 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2100 $ DMPlexTopologyView(dm, viewer); 2101 $ DMPlexSectionView(dm, viewer, sectiondm); 2102 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2103 $ DMRestoreLocalVector(sectiondm, &vec); 2104 $ DMDestroy(§iondm); 2105 $ DMDestroy(&dm); 2106 2107 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2108 @*/ 2109 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2110 { 2111 PetscBool ishdf5; 2112 2113 PetscFunctionBegin; 2114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2115 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2116 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2117 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2118 /* Check consistency */ 2119 { 2120 PetscSection section; 2121 PetscBool includesConstraints; 2122 PetscInt m, m1; 2123 2124 PetscCall(VecGetLocalSize(vec, &m1)); 2125 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2126 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2127 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2128 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2129 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2130 } 2131 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2132 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2133 if (ishdf5) { 2134 #if defined(PETSC_HAVE_HDF5) 2135 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2136 #else 2137 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2138 #endif 2139 } 2140 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2141 PetscFunctionReturn(0); 2142 } 2143 2144 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2145 { 2146 PetscBool ishdf5; 2147 2148 PetscFunctionBegin; 2149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2150 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2151 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2152 if (ishdf5) { 2153 #if defined(PETSC_HAVE_HDF5) 2154 PetscViewerFormat format; 2155 PetscCall(PetscViewerGetFormat(viewer, &format)); 2156 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2157 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2158 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2159 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2160 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2161 PetscFunctionReturn(0); 2162 #else 2163 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2164 #endif 2165 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2166 } 2167 2168 /*@ 2169 DMPlexTopologyLoad - Loads a topology into a DMPlex 2170 2171 Collective on DM 2172 2173 Input Parameters: 2174 + dm - The DM into which the topology is loaded 2175 - viewer - The PetscViewer for the saved topology 2176 2177 Output Parameters: 2178 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2179 2180 Level: advanced 2181 2182 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2183 @*/ 2184 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2185 { 2186 PetscBool ishdf5; 2187 2188 PetscFunctionBegin; 2189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2190 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2191 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2192 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2193 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2194 if (ishdf5) { 2195 #if defined(PETSC_HAVE_HDF5) 2196 PetscViewerFormat format; 2197 PetscCall(PetscViewerGetFormat(viewer, &format)); 2198 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2199 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2200 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2201 #else 2202 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2203 #endif 2204 } 2205 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2206 PetscFunctionReturn(0); 2207 } 2208 2209 /*@ 2210 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2211 2212 Collective on DM 2213 2214 Input Parameters: 2215 + dm - The DM into which the coordinates are loaded 2216 . viewer - The PetscViewer for the saved coordinates 2217 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2218 2219 Level: advanced 2220 2221 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2222 @*/ 2223 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2224 { 2225 PetscBool ishdf5; 2226 2227 PetscFunctionBegin; 2228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2229 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2230 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2231 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2232 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2233 if (ishdf5) { 2234 #if defined(PETSC_HAVE_HDF5) 2235 PetscViewerFormat format; 2236 PetscCall(PetscViewerGetFormat(viewer, &format)); 2237 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2238 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2239 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2240 #else 2241 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2242 #endif 2243 } 2244 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2245 PetscFunctionReturn(0); 2246 } 2247 2248 /*@ 2249 DMPlexLabelsLoad - Loads labels into a DMPlex 2250 2251 Collective on DM 2252 2253 Input Parameters: 2254 + dm - The DM into which the labels are loaded 2255 . viewer - The PetscViewer for the saved labels 2256 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2257 2258 Level: advanced 2259 2260 Notes: 2261 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2262 2263 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2264 @*/ 2265 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2266 { 2267 PetscBool ishdf5; 2268 2269 PetscFunctionBegin; 2270 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2271 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2272 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2273 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2274 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2275 if (ishdf5) { 2276 #if defined(PETSC_HAVE_HDF5) 2277 PetscViewerFormat format; 2278 2279 PetscCall(PetscViewerGetFormat(viewer, &format)); 2280 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2281 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2282 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2283 #else 2284 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2285 #endif 2286 } 2287 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2288 PetscFunctionReturn(0); 2289 } 2290 2291 /*@ 2292 DMPlexSectionLoad - Loads section into a DMPlex 2293 2294 Collective on DM 2295 2296 Input Parameters: 2297 + dm - The DM that represents the topology 2298 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2299 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2300 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2301 2302 Output Parameters 2303 + globalDofSF - The SF 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) 2304 - localDofSF - The SF 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) 2305 2306 Level: advanced 2307 2308 Notes: 2309 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. 2310 2311 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. 2312 2313 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. 2314 2315 Example using 2 processes: 2316 $ NX (number of points on dm): 4 2317 $ sectionA : the on-disk section 2318 $ vecA : a vector associated with sectionA 2319 $ sectionB : sectiondm's local section constructed in this function 2320 $ vecB (local) : a vector associated with sectiondm's local section 2321 $ vecB (global) : a vector associated with sectiondm's global section 2322 $ 2323 $ rank 0 rank 1 2324 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2325 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2326 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2327 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2328 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2329 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2330 $ sectionB->atlasDof : 1 0 1 | 1 3 2331 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2332 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2333 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2334 $ 2335 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2336 2337 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2338 @*/ 2339 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2340 { 2341 PetscBool ishdf5; 2342 2343 PetscFunctionBegin; 2344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2345 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2346 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2347 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2348 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2349 if (localDofSF) PetscValidPointer(localDofSF, 6); 2350 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2351 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2352 if (ishdf5) { 2353 #if defined(PETSC_HAVE_HDF5) 2354 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2355 #else 2356 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2357 #endif 2358 } 2359 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2360 PetscFunctionReturn(0); 2361 } 2362 2363 /*@ 2364 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2365 2366 Collective on DM 2367 2368 Input Parameters: 2369 + dm - The DM that represents the topology 2370 . viewer - The PetscViewer that represents the on-disk vector data 2371 . sectiondm - The DM that contains the global section on which vec is defined 2372 . sf - The SF that migrates the on-disk vector data into vec 2373 - vec - The global vector to set values of 2374 2375 Level: advanced 2376 2377 Notes: 2378 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. 2379 2380 Typical calling sequence 2381 $ DMCreate(PETSC_COMM_WORLD, &dm); 2382 $ DMSetType(dm, DMPLEX); 2383 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2384 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2385 $ DMClone(dm, §iondm); 2386 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2387 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2388 $ DMGetGlobalVector(sectiondm, &vec); 2389 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2390 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2391 $ DMRestoreGlobalVector(sectiondm, &vec); 2392 $ PetscSFDestroy(&gsf); 2393 $ PetscSFDestroy(&sfX); 2394 $ DMDestroy(§iondm); 2395 $ DMDestroy(&dm); 2396 2397 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 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(0); 2433 } 2434 2435 /*@ 2436 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2437 2438 Collective on DM 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 SF 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 $ DMCreate(PETSC_COMM_WORLD, &dm); 2454 $ DMSetType(dm, DMPLEX); 2455 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2456 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2457 $ DMClone(dm, §iondm); 2458 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2459 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2460 $ DMGetLocalVector(sectiondm, &vec); 2461 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2462 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2463 $ DMRestoreLocalVector(sectiondm, &vec); 2464 $ PetscSFDestroy(&lsf); 2465 $ PetscSFDestroy(&sfX); 2466 $ DMDestroy(§iondm); 2467 $ DMDestroy(&dm); 2468 2469 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2470 @*/ 2471 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2472 { 2473 PetscBool ishdf5; 2474 2475 PetscFunctionBegin; 2476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2477 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2478 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2479 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2480 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2481 /* Check consistency */ 2482 { 2483 PetscSection section; 2484 PetscBool includesConstraints; 2485 PetscInt m, m1; 2486 2487 PetscCall(VecGetLocalSize(vec, &m1)); 2488 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2489 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2490 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2491 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2492 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2493 } 2494 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2495 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2496 if (ishdf5) { 2497 #if defined(PETSC_HAVE_HDF5) 2498 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2499 #else 2500 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2501 #endif 2502 } 2503 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2504 PetscFunctionReturn(0); 2505 } 2506 2507 PetscErrorCode DMDestroy_Plex(DM dm) 2508 { 2509 DM_Plex *mesh = (DM_Plex *)dm->data; 2510 2511 PetscFunctionBegin; 2512 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2513 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2514 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2515 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2516 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2517 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2518 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2519 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2520 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2521 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2522 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2523 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2524 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2525 if (--mesh->refct > 0) PetscFunctionReturn(0); 2526 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2527 PetscCall(PetscFree(mesh->cones)); 2528 PetscCall(PetscFree(mesh->coneOrientations)); 2529 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2530 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2531 PetscCall(PetscFree(mesh->supports)); 2532 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2533 PetscCall(PetscFree(mesh->facesTmp)); 2534 PetscCall(PetscFree(mesh->tetgenOpts)); 2535 PetscCall(PetscFree(mesh->triangleOpts)); 2536 PetscCall(PetscFree(mesh->transformType)); 2537 PetscCall(PetscFree(mesh->distributionName)); 2538 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2539 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2540 PetscCall(ISDestroy(&mesh->subpointIS)); 2541 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2542 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2543 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2544 PetscCall(ISDestroy(&mesh->anchorIS)); 2545 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2546 PetscCall(PetscFree(mesh->parents)); 2547 PetscCall(PetscFree(mesh->childIDs)); 2548 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2549 PetscCall(PetscFree(mesh->children)); 2550 PetscCall(DMDestroy(&mesh->referenceTree)); 2551 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2552 PetscCall(PetscFree(mesh->neighbors)); 2553 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2554 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2555 PetscCall(PetscFree(mesh)); 2556 PetscFunctionReturn(0); 2557 } 2558 2559 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2560 { 2561 PetscSection sectionGlobal; 2562 PetscInt bs = -1, mbs; 2563 PetscInt localSize, localStart = 0; 2564 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2565 MatType mtype; 2566 ISLocalToGlobalMapping ltog; 2567 2568 PetscFunctionBegin; 2569 PetscCall(MatInitializePackage()); 2570 mtype = dm->mattype; 2571 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2572 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2573 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2574 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2575 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2576 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2577 PetscCall(MatSetType(*J, mtype)); 2578 PetscCall(MatSetFromOptions(*J)); 2579 PetscCall(MatGetBlockSize(*J, &mbs)); 2580 if (mbs > 1) bs = mbs; 2581 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2582 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2583 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2584 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2585 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2586 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2587 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2588 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2589 if (!isShell) { 2590 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2591 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2592 PetscInt pStart, pEnd, p, dof, cdof; 2593 2594 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2595 2596 PetscCall(PetscCalloc1(localSize, &pblocks)); 2597 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2598 for (p = pStart; p < pEnd; ++p) { 2599 PetscInt bdof, offset; 2600 2601 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2602 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2603 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2604 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2605 dof = dof < 0 ? -(dof + 1) : dof; 2606 bdof = cdof && (dof - cdof) ? 1 : dof; 2607 if (dof) { 2608 if (bs < 0) { 2609 bs = bdof; 2610 } else if (bs != bdof) { 2611 bs = 1; 2612 } 2613 } 2614 } 2615 /* Must have same blocksize on all procs (some might have no points) */ 2616 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2617 bsLocal[1] = bs; 2618 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2619 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2620 else bs = bsMinMax[0]; 2621 bs = PetscMax(1, bs); 2622 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2623 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2624 PetscCall(MatSetBlockSize(*J, bs)); 2625 PetscCall(MatSetUp(*J)); 2626 } else { 2627 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2628 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2629 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2630 } 2631 { // Consolidate blocks 2632 PetscInt nblocks = 0; 2633 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2634 if (pblocks[i] == 0) continue; 2635 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2636 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]); 2637 } 2638 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2639 } 2640 PetscCall(PetscFree(pblocks)); 2641 } 2642 PetscCall(MatSetDM(*J, dm)); 2643 PetscFunctionReturn(0); 2644 } 2645 2646 /*@ 2647 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2648 2649 Not collective 2650 2651 Input Parameter: 2652 . mesh - The DMPlex 2653 2654 Output Parameters: 2655 . subsection - The subdomain section 2656 2657 Level: developer 2658 2659 .seealso: 2660 @*/ 2661 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2662 { 2663 DM_Plex *mesh = (DM_Plex *)dm->data; 2664 2665 PetscFunctionBegin; 2666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2667 if (!mesh->subdomainSection) { 2668 PetscSection section; 2669 PetscSF sf; 2670 2671 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2672 PetscCall(DMGetLocalSection(dm, §ion)); 2673 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2674 PetscCall(PetscSFDestroy(&sf)); 2675 } 2676 *subsection = mesh->subdomainSection; 2677 PetscFunctionReturn(0); 2678 } 2679 2680 /*@ 2681 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2682 2683 Not collective 2684 2685 Input Parameter: 2686 . mesh - The DMPlex 2687 2688 Output Parameters: 2689 + pStart - The first mesh point 2690 - pEnd - The upper bound for mesh points 2691 2692 Level: beginner 2693 2694 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2695 @*/ 2696 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2697 { 2698 DM_Plex *mesh = (DM_Plex *)dm->data; 2699 2700 PetscFunctionBegin; 2701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2702 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2703 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2704 PetscFunctionReturn(0); 2705 } 2706 2707 /*@ 2708 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2709 2710 Not collective 2711 2712 Input Parameters: 2713 + mesh - The DMPlex 2714 . pStart - The first mesh point 2715 - pEnd - The upper bound for mesh points 2716 2717 Output Parameters: 2718 2719 Level: beginner 2720 2721 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2722 @*/ 2723 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2724 { 2725 DM_Plex *mesh = (DM_Plex *)dm->data; 2726 2727 PetscFunctionBegin; 2728 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2729 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2730 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2731 PetscFunctionReturn(0); 2732 } 2733 2734 /*@ 2735 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2736 2737 Not collective 2738 2739 Input Parameters: 2740 + mesh - The DMPlex 2741 - p - The point, which must lie in the chart set with DMPlexSetChart() 2742 2743 Output Parameter: 2744 . size - The cone size for point p 2745 2746 Level: beginner 2747 2748 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2749 @*/ 2750 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2751 { 2752 DM_Plex *mesh = (DM_Plex *)dm->data; 2753 2754 PetscFunctionBegin; 2755 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2756 PetscValidIntPointer(size, 3); 2757 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2758 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2759 PetscFunctionReturn(0); 2760 } 2761 2762 /*@ 2763 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2764 2765 Not collective 2766 2767 Input Parameters: 2768 + mesh - The DMPlex 2769 . p - The point, which must lie in the chart set with DMPlexSetChart() 2770 - size - The cone size for point p 2771 2772 Output Parameter: 2773 2774 Note: 2775 This should be called after DMPlexSetChart(). 2776 2777 Level: beginner 2778 2779 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2780 @*/ 2781 PetscErrorCode DMPlexSetConeSize(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 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2788 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2789 PetscFunctionReturn(0); 2790 } 2791 2792 /*@C 2793 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2794 2795 Not collective 2796 2797 Input Parameters: 2798 + dm - The DMPlex 2799 - p - The point, which must lie in the chart set with DMPlexSetChart() 2800 2801 Output Parameter: 2802 . cone - An array of points which are on the in-edges for point p 2803 2804 Level: beginner 2805 2806 Fortran Notes: 2807 Since it returns an array, this routine is only available in Fortran 90, and you must 2808 include petsc.h90 in your code. 2809 You must also call DMPlexRestoreCone() after you finish using the returned array. 2810 DMPlexRestoreCone() is not needed/available in C. 2811 2812 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2813 @*/ 2814 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2815 { 2816 DM_Plex *mesh = (DM_Plex *)dm->data; 2817 PetscInt off; 2818 2819 PetscFunctionBegin; 2820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2821 PetscValidPointer(cone, 3); 2822 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2823 *cone = &mesh->cones[off]; 2824 PetscFunctionReturn(0); 2825 } 2826 2827 /*@C 2828 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2829 2830 Not collective 2831 2832 Input Parameters: 2833 + dm - The DMPlex 2834 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2835 2836 Output Parameters: 2837 + pConesSection - PetscSection describing the layout of pCones 2838 - pCones - An array of points which are on the in-edges for the point set p 2839 2840 Level: intermediate 2841 2842 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2843 @*/ 2844 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2845 { 2846 PetscSection cs, newcs; 2847 PetscInt *cones; 2848 PetscInt *newarr = NULL; 2849 PetscInt n; 2850 2851 PetscFunctionBegin; 2852 PetscCall(DMPlexGetCones(dm, &cones)); 2853 PetscCall(DMPlexGetConeSection(dm, &cs)); 2854 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2855 if (pConesSection) *pConesSection = newcs; 2856 if (pCones) { 2857 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2858 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2859 } 2860 PetscFunctionReturn(0); 2861 } 2862 2863 /*@ 2864 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2865 2866 Not collective 2867 2868 Input Parameters: 2869 + dm - The DMPlex 2870 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2871 2872 Output Parameter: 2873 . expandedPoints - An array of vertices recursively expanded from input points 2874 2875 Level: advanced 2876 2877 Notes: 2878 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2879 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2880 2881 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2882 @*/ 2883 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2884 { 2885 IS *expandedPointsAll; 2886 PetscInt depth; 2887 2888 PetscFunctionBegin; 2889 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2890 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2891 PetscValidPointer(expandedPoints, 3); 2892 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2893 *expandedPoints = expandedPointsAll[0]; 2894 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2895 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2896 PetscFunctionReturn(0); 2897 } 2898 2899 /*@ 2900 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). 2901 2902 Not collective 2903 2904 Input Parameters: 2905 + dm - The DMPlex 2906 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2907 2908 Output Parameters: 2909 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2910 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2911 - sections - (optional) An array of sections which describe mappings from points to their cone points 2912 2913 Level: advanced 2914 2915 Notes: 2916 Like DMPlexGetConeTuple() but recursive. 2917 2918 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. 2919 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2920 2921 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: 2922 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2923 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2924 2925 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2926 @*/ 2927 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2928 { 2929 const PetscInt *arr0 = NULL, *cone = NULL; 2930 PetscInt *arr = NULL, *newarr = NULL; 2931 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2932 IS *expandedPoints_; 2933 PetscSection *sections_; 2934 2935 PetscFunctionBegin; 2936 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2937 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2938 if (depth) PetscValidIntPointer(depth, 3); 2939 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2940 if (sections) PetscValidPointer(sections, 5); 2941 PetscCall(ISGetLocalSize(points, &n)); 2942 PetscCall(ISGetIndices(points, &arr0)); 2943 PetscCall(DMPlexGetDepth(dm, &depth_)); 2944 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2945 PetscCall(PetscCalloc1(depth_, §ions_)); 2946 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2947 for (d = depth_ - 1; d >= 0; d--) { 2948 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2949 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2950 for (i = 0; i < n; i++) { 2951 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2952 if (arr[i] >= start && arr[i] < end) { 2953 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2954 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2955 } else { 2956 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2957 } 2958 } 2959 PetscCall(PetscSectionSetUp(sections_[d])); 2960 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2961 PetscCall(PetscMalloc1(newn, &newarr)); 2962 for (i = 0; i < n; i++) { 2963 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2964 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2965 if (cn > 1) { 2966 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2967 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2968 } else { 2969 newarr[co] = arr[i]; 2970 } 2971 } 2972 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2973 arr = newarr; 2974 n = newn; 2975 } 2976 PetscCall(ISRestoreIndices(points, &arr0)); 2977 *depth = depth_; 2978 if (expandedPoints) *expandedPoints = expandedPoints_; 2979 else { 2980 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2981 PetscCall(PetscFree(expandedPoints_)); 2982 } 2983 if (sections) *sections = sections_; 2984 else { 2985 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2986 PetscCall(PetscFree(sections_)); 2987 } 2988 PetscFunctionReturn(0); 2989 } 2990 2991 /*@ 2992 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2993 2994 Not collective 2995 2996 Input Parameters: 2997 + dm - The DMPlex 2998 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2999 3000 Output Parameters: 3001 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 3002 . expandedPoints - (optional) An array of recursively expanded cones 3003 - sections - (optional) An array of sections which describe mappings from points to their cone points 3004 3005 Level: advanced 3006 3007 Notes: 3008 See DMPlexGetConeRecursive() for details. 3009 3010 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 3011 @*/ 3012 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3013 { 3014 PetscInt d, depth_; 3015 3016 PetscFunctionBegin; 3017 PetscCall(DMPlexGetDepth(dm, &depth_)); 3018 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3019 if (depth) *depth = 0; 3020 if (expandedPoints) { 3021 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3022 PetscCall(PetscFree(*expandedPoints)); 3023 } 3024 if (sections) { 3025 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3026 PetscCall(PetscFree(*sections)); 3027 } 3028 PetscFunctionReturn(0); 3029 } 3030 3031 /*@ 3032 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 3033 3034 Not collective 3035 3036 Input Parameters: 3037 + mesh - The DMPlex 3038 . p - The point, which must lie in the chart set with DMPlexSetChart() 3039 - cone - An array of points which are on the in-edges for point p 3040 3041 Output Parameter: 3042 3043 Note: 3044 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3045 3046 Level: beginner 3047 3048 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3049 @*/ 3050 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3051 { 3052 DM_Plex *mesh = (DM_Plex *)dm->data; 3053 PetscInt pStart, pEnd; 3054 PetscInt dof, off, c; 3055 3056 PetscFunctionBegin; 3057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3058 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3059 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3060 if (dof) PetscValidIntPointer(cone, 3); 3061 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3062 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); 3063 for (c = 0; c < dof; ++c) { 3064 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); 3065 mesh->cones[off + c] = cone[c]; 3066 } 3067 PetscFunctionReturn(0); 3068 } 3069 3070 /*@C 3071 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3072 3073 Not collective 3074 3075 Input Parameters: 3076 + mesh - The DMPlex 3077 - p - The point, which must lie in the chart set with DMPlexSetChart() 3078 3079 Output Parameter: 3080 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3081 integer giving the prescription for cone traversal. 3082 3083 Level: beginner 3084 3085 Notes: 3086 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3087 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3088 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3089 with the identity. 3090 3091 Fortran Notes: 3092 Since it returns an array, this routine is only available in Fortran 90, and you must 3093 include petsc.h90 in your code. 3094 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3095 DMPlexRestoreConeOrientation() is not needed/available in C. 3096 3097 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3098 @*/ 3099 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3100 { 3101 DM_Plex *mesh = (DM_Plex *)dm->data; 3102 PetscInt off; 3103 3104 PetscFunctionBegin; 3105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3106 if (PetscDefined(USE_DEBUG)) { 3107 PetscInt dof; 3108 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3109 if (dof) PetscValidPointer(coneOrientation, 3); 3110 } 3111 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3112 3113 *coneOrientation = &mesh->coneOrientations[off]; 3114 PetscFunctionReturn(0); 3115 } 3116 3117 /*@ 3118 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3119 3120 Not collective 3121 3122 Input Parameters: 3123 + mesh - The DMPlex 3124 . p - The point, which must lie in the chart set with DMPlexSetChart() 3125 - coneOrientation - An array of orientations 3126 Output Parameter: 3127 3128 Notes: 3129 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3130 3131 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3132 3133 Level: beginner 3134 3135 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3136 @*/ 3137 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3138 { 3139 DM_Plex *mesh = (DM_Plex *)dm->data; 3140 PetscInt pStart, pEnd; 3141 PetscInt dof, off, c; 3142 3143 PetscFunctionBegin; 3144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3145 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3146 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3147 if (dof) PetscValidIntPointer(coneOrientation, 3); 3148 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3149 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); 3150 for (c = 0; c < dof; ++c) { 3151 PetscInt cdof, o = coneOrientation[c]; 3152 3153 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3154 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); 3155 mesh->coneOrientations[off + c] = o; 3156 } 3157 PetscFunctionReturn(0); 3158 } 3159 3160 /*@ 3161 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3162 3163 Not collective 3164 3165 Input Parameters: 3166 + mesh - The DMPlex 3167 . p - The point, which must lie in the chart set with DMPlexSetChart() 3168 . conePos - The local index in the cone where the point should be put 3169 - conePoint - The mesh point to insert 3170 3171 Level: beginner 3172 3173 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3174 @*/ 3175 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3176 { 3177 DM_Plex *mesh = (DM_Plex *)dm->data; 3178 PetscInt pStart, pEnd; 3179 PetscInt dof, off; 3180 3181 PetscFunctionBegin; 3182 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3183 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3184 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3185 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); 3186 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3187 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3188 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); 3189 mesh->cones[off + conePos] = conePoint; 3190 PetscFunctionReturn(0); 3191 } 3192 3193 /*@ 3194 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3195 3196 Not collective 3197 3198 Input Parameters: 3199 + mesh - The DMPlex 3200 . p - The point, which must lie in the chart set with DMPlexSetChart() 3201 . conePos - The local index in the cone where the point should be put 3202 - coneOrientation - The point orientation to insert 3203 3204 Level: beginner 3205 3206 Notes: 3207 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3208 3209 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3210 @*/ 3211 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3212 { 3213 DM_Plex *mesh = (DM_Plex *)dm->data; 3214 PetscInt pStart, pEnd; 3215 PetscInt dof, off; 3216 3217 PetscFunctionBegin; 3218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3219 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3220 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); 3221 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3222 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3223 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); 3224 mesh->coneOrientations[off + conePos] = coneOrientation; 3225 PetscFunctionReturn(0); 3226 } 3227 3228 /*@C 3229 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3230 3231 Not collective 3232 3233 Input Parameters: 3234 + dm - The DMPlex 3235 - p - The point, which must lie in the chart set with DMPlexSetChart() 3236 3237 Output Parameters: 3238 + cone - An array of points which are on the in-edges for point p 3239 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3240 integer giving the prescription for cone traversal. 3241 3242 Level: beginner 3243 3244 Notes: 3245 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3246 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3247 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3248 with the identity. 3249 3250 Fortran Notes: 3251 Since it returns an array, this routine is only available in Fortran 90, and you must 3252 include petsc.h90 in your code. 3253 You must also call DMPlexRestoreCone() after you finish using the returned array. 3254 DMPlexRestoreCone() is not needed/available in C. 3255 3256 .seealso: `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3257 @*/ 3258 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3259 { 3260 DM_Plex *mesh = (DM_Plex *)dm->data; 3261 3262 PetscFunctionBegin; 3263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3264 if (mesh->tr) { 3265 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3266 } else { 3267 PetscInt off; 3268 if (PetscDefined(USE_DEBUG)) { 3269 PetscInt dof; 3270 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3271 if (dof) { 3272 if (cone) PetscValidPointer(cone, 3); 3273 if (ornt) PetscValidPointer(ornt, 4); 3274 } 3275 } 3276 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3277 if (cone) *cone = &mesh->cones[off]; 3278 if (ornt) *ornt = &mesh->coneOrientations[off]; 3279 } 3280 PetscFunctionReturn(0); 3281 } 3282 3283 /*@C 3284 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3285 3286 Not collective 3287 3288 Input Parameters: 3289 + dm - The DMPlex 3290 . p - The point, which must lie in the chart set with DMPlexSetChart() 3291 . cone - An array of points which are on the in-edges for point p 3292 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3293 integer giving the prescription for cone traversal. 3294 3295 Level: beginner 3296 3297 Notes: 3298 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3299 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3300 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3301 with the identity. 3302 3303 Fortran Notes: 3304 Since it returns an array, this routine is only available in Fortran 90, and you must 3305 include petsc.h90 in your code. 3306 You must also call DMPlexRestoreCone() after you finish using the returned array. 3307 DMPlexRestoreCone() is not needed/available in C. 3308 3309 .seealso: `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3310 @*/ 3311 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3312 { 3313 DM_Plex *mesh = (DM_Plex *)dm->data; 3314 3315 PetscFunctionBegin; 3316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3317 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3318 PetscFunctionReturn(0); 3319 } 3320 3321 /*@ 3322 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3323 3324 Not collective 3325 3326 Input Parameters: 3327 + mesh - The DMPlex 3328 - p - The point, which must lie in the chart set with DMPlexSetChart() 3329 3330 Output Parameter: 3331 . size - The support size for point p 3332 3333 Level: beginner 3334 3335 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3336 @*/ 3337 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3338 { 3339 DM_Plex *mesh = (DM_Plex *)dm->data; 3340 3341 PetscFunctionBegin; 3342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3343 PetscValidIntPointer(size, 3); 3344 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3345 PetscFunctionReturn(0); 3346 } 3347 3348 /*@ 3349 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3350 3351 Not collective 3352 3353 Input Parameters: 3354 + mesh - The DMPlex 3355 . p - The point, which must lie in the chart set with DMPlexSetChart() 3356 - size - The support size for point p 3357 3358 Output Parameter: 3359 3360 Note: 3361 This should be called after DMPlexSetChart(). 3362 3363 Level: beginner 3364 3365 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3366 @*/ 3367 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3368 { 3369 DM_Plex *mesh = (DM_Plex *)dm->data; 3370 3371 PetscFunctionBegin; 3372 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3373 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3374 PetscFunctionReturn(0); 3375 } 3376 3377 /*@C 3378 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3379 3380 Not collective 3381 3382 Input Parameters: 3383 + mesh - The DMPlex 3384 - p - The point, which must lie in the chart set with DMPlexSetChart() 3385 3386 Output Parameter: 3387 . support - An array of points which are on the out-edges for point p 3388 3389 Level: beginner 3390 3391 Fortran Notes: 3392 Since it returns an array, this routine is only available in Fortran 90, and you must 3393 include petsc.h90 in your code. 3394 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3395 DMPlexRestoreSupport() is not needed/available in C. 3396 3397 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3398 @*/ 3399 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3400 { 3401 DM_Plex *mesh = (DM_Plex *)dm->data; 3402 PetscInt off; 3403 3404 PetscFunctionBegin; 3405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3406 PetscValidPointer(support, 3); 3407 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3408 *support = &mesh->supports[off]; 3409 PetscFunctionReturn(0); 3410 } 3411 3412 /*@ 3413 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3414 3415 Not collective 3416 3417 Input Parameters: 3418 + mesh - The DMPlex 3419 . p - The point, which must lie in the chart set with DMPlexSetChart() 3420 - support - An array of points which are on the out-edges for point p 3421 3422 Output Parameter: 3423 3424 Note: 3425 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3426 3427 Level: beginner 3428 3429 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3430 @*/ 3431 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3432 { 3433 DM_Plex *mesh = (DM_Plex *)dm->data; 3434 PetscInt pStart, pEnd; 3435 PetscInt dof, off, c; 3436 3437 PetscFunctionBegin; 3438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3439 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3440 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3441 if (dof) PetscValidIntPointer(support, 3); 3442 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3443 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); 3444 for (c = 0; c < dof; ++c) { 3445 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); 3446 mesh->supports[off + c] = support[c]; 3447 } 3448 PetscFunctionReturn(0); 3449 } 3450 3451 /*@ 3452 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3453 3454 Not collective 3455 3456 Input Parameters: 3457 + mesh - The DMPlex 3458 . p - The point, which must lie in the chart set with DMPlexSetChart() 3459 . supportPos - The local index in the cone where the point should be put 3460 - supportPoint - The mesh point to insert 3461 3462 Level: beginner 3463 3464 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3465 @*/ 3466 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3467 { 3468 DM_Plex *mesh = (DM_Plex *)dm->data; 3469 PetscInt pStart, pEnd; 3470 PetscInt dof, off; 3471 3472 PetscFunctionBegin; 3473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3474 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3475 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3476 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3477 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); 3478 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); 3479 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); 3480 mesh->supports[off + supportPos] = supportPoint; 3481 PetscFunctionReturn(0); 3482 } 3483 3484 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3485 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3486 { 3487 switch (ct) { 3488 case DM_POLYTOPE_SEGMENT: 3489 if (o == -1) return -2; 3490 break; 3491 case DM_POLYTOPE_TRIANGLE: 3492 if (o == -3) return -1; 3493 if (o == -2) return -3; 3494 if (o == -1) return -2; 3495 break; 3496 case DM_POLYTOPE_QUADRILATERAL: 3497 if (o == -4) return -2; 3498 if (o == -3) return -1; 3499 if (o == -2) return -4; 3500 if (o == -1) return -3; 3501 break; 3502 default: 3503 return o; 3504 } 3505 return o; 3506 } 3507 3508 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3509 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3510 { 3511 switch (ct) { 3512 case DM_POLYTOPE_SEGMENT: 3513 if ((o == -2) || (o == 1)) return -1; 3514 if (o == -1) return 0; 3515 break; 3516 case DM_POLYTOPE_TRIANGLE: 3517 if (o == -3) return -2; 3518 if (o == -2) return -1; 3519 if (o == -1) return -3; 3520 break; 3521 case DM_POLYTOPE_QUADRILATERAL: 3522 if (o == -4) return -2; 3523 if (o == -3) return -1; 3524 if (o == -2) return -4; 3525 if (o == -1) return -3; 3526 break; 3527 default: 3528 return o; 3529 } 3530 return o; 3531 } 3532 3533 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3534 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3535 { 3536 PetscInt pStart, pEnd, p; 3537 3538 PetscFunctionBegin; 3539 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3540 for (p = pStart; p < pEnd; ++p) { 3541 const PetscInt *cone, *ornt; 3542 PetscInt coneSize, c; 3543 3544 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3545 PetscCall(DMPlexGetCone(dm, p, &cone)); 3546 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3547 for (c = 0; c < coneSize; ++c) { 3548 DMPolytopeType ct; 3549 const PetscInt o = ornt[c]; 3550 3551 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3552 switch (ct) { 3553 case DM_POLYTOPE_SEGMENT: 3554 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3555 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3556 break; 3557 case DM_POLYTOPE_TRIANGLE: 3558 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3559 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3560 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3561 break; 3562 case DM_POLYTOPE_QUADRILATERAL: 3563 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3564 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3565 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3566 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3567 break; 3568 default: 3569 break; 3570 } 3571 } 3572 } 3573 PetscFunctionReturn(0); 3574 } 3575 3576 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3577 { 3578 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3579 PetscInt *closure; 3580 const PetscInt *tmp = NULL, *tmpO = NULL; 3581 PetscInt off = 0, tmpSize, t; 3582 3583 PetscFunctionBeginHot; 3584 if (ornt) { 3585 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3586 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3587 } 3588 if (*points) { 3589 closure = *points; 3590 } else { 3591 PetscInt maxConeSize, maxSupportSize; 3592 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3593 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3594 } 3595 if (useCone) { 3596 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3597 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3598 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3599 } else { 3600 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3601 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3602 } 3603 if (ct == DM_POLYTOPE_UNKNOWN) { 3604 closure[off++] = p; 3605 closure[off++] = 0; 3606 for (t = 0; t < tmpSize; ++t) { 3607 closure[off++] = tmp[t]; 3608 closure[off++] = tmpO ? tmpO[t] : 0; 3609 } 3610 } else { 3611 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3612 3613 /* We assume that cells with a valid type have faces with a valid type */ 3614 closure[off++] = p; 3615 closure[off++] = ornt; 3616 for (t = 0; t < tmpSize; ++t) { 3617 DMPolytopeType ft; 3618 3619 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3620 closure[off++] = tmp[arr[t]]; 3621 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3622 } 3623 } 3624 if (numPoints) *numPoints = tmpSize + 1; 3625 if (points) *points = closure; 3626 PetscFunctionReturn(0); 3627 } 3628 3629 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3630 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3631 { 3632 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3633 const PetscInt *cone, *ornt; 3634 PetscInt *pts, *closure = NULL; 3635 DMPolytopeType ft; 3636 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3637 PetscInt dim, coneSize, c, d, clSize, cl; 3638 3639 PetscFunctionBeginHot; 3640 PetscCall(DMGetDimension(dm, &dim)); 3641 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3642 PetscCall(DMPlexGetCone(dm, point, &cone)); 3643 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3644 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3645 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3646 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3647 maxSize = PetscMax(coneSeries, supportSeries); 3648 if (*points) { 3649 pts = *points; 3650 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3651 c = 0; 3652 pts[c++] = point; 3653 pts[c++] = o; 3654 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3655 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3656 for (cl = 0; cl < clSize * 2; cl += 2) { 3657 pts[c++] = closure[cl]; 3658 pts[c++] = closure[cl + 1]; 3659 } 3660 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3661 for (cl = 0; cl < clSize * 2; cl += 2) { 3662 pts[c++] = closure[cl]; 3663 pts[c++] = closure[cl + 1]; 3664 } 3665 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3666 for (d = 2; d < coneSize; ++d) { 3667 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3668 pts[c++] = cone[arr[d * 2 + 0]]; 3669 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3670 } 3671 if (dim >= 3) { 3672 for (d = 2; d < coneSize; ++d) { 3673 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3674 const PetscInt *fcone, *fornt; 3675 PetscInt fconeSize, fc, i; 3676 3677 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3678 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3679 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3680 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3681 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3682 for (fc = 0; fc < fconeSize; ++fc) { 3683 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3684 const PetscInt co = farr[fc * 2 + 1]; 3685 3686 for (i = 0; i < c; i += 2) 3687 if (pts[i] == cp) break; 3688 if (i == c) { 3689 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3690 pts[c++] = cp; 3691 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3692 } 3693 } 3694 } 3695 } 3696 *numPoints = c / 2; 3697 *points = pts; 3698 PetscFunctionReturn(0); 3699 } 3700 3701 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3702 { 3703 DMPolytopeType ct; 3704 PetscInt *closure, *fifo; 3705 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3706 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3707 PetscInt depth, maxSize; 3708 3709 PetscFunctionBeginHot; 3710 PetscCall(DMPlexGetDepth(dm, &depth)); 3711 if (depth == 1) { 3712 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3713 PetscFunctionReturn(0); 3714 } 3715 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3716 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3717 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3718 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3719 PetscFunctionReturn(0); 3720 } 3721 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3722 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3723 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3724 maxSize = PetscMax(coneSeries, supportSeries); 3725 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3726 if (*points) { 3727 closure = *points; 3728 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3729 closure[closureSize++] = p; 3730 closure[closureSize++] = ornt; 3731 fifo[fifoSize++] = p; 3732 fifo[fifoSize++] = ornt; 3733 fifo[fifoSize++] = ct; 3734 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3735 while (fifoSize - fifoStart) { 3736 const PetscInt q = fifo[fifoStart++]; 3737 const PetscInt o = fifo[fifoStart++]; 3738 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3739 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3740 const PetscInt *tmp, *tmpO; 3741 PetscInt tmpSize, t; 3742 3743 if (PetscDefined(USE_DEBUG)) { 3744 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3745 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); 3746 } 3747 if (useCone) { 3748 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3749 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3750 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3751 } else { 3752 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3753 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3754 tmpO = NULL; 3755 } 3756 for (t = 0; t < tmpSize; ++t) { 3757 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3758 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3759 const PetscInt cp = tmp[ip]; 3760 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3761 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3762 PetscInt c; 3763 3764 /* Check for duplicate */ 3765 for (c = 0; c < closureSize; c += 2) { 3766 if (closure[c] == cp) break; 3767 } 3768 if (c == closureSize) { 3769 closure[closureSize++] = cp; 3770 closure[closureSize++] = co; 3771 fifo[fifoSize++] = cp; 3772 fifo[fifoSize++] = co; 3773 fifo[fifoSize++] = ct; 3774 } 3775 } 3776 } 3777 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3778 if (numPoints) *numPoints = closureSize / 2; 3779 if (points) *points = closure; 3780 PetscFunctionReturn(0); 3781 } 3782 3783 /*@C 3784 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3785 3786 Not collective 3787 3788 Input Parameters: 3789 + dm - The DMPlex 3790 . p - The mesh point 3791 - useCone - PETSC_TRUE for the closure, otherwise return the star 3792 3793 Input/Output Parameter: 3794 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3795 if NULL on input, internal storage will be returned, otherwise the provided array is used 3796 3797 Output Parameter: 3798 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3799 3800 Note: 3801 If using internal storage (points is NULL on input), each call overwrites the last output. 3802 3803 Fortran Note: 3804 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3805 3806 Level: beginner 3807 3808 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3809 @*/ 3810 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3811 { 3812 PetscFunctionBeginHot; 3813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3814 if (numPoints) PetscValidIntPointer(numPoints, 4); 3815 if (points) PetscValidPointer(points, 5); 3816 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3817 PetscFunctionReturn(0); 3818 } 3819 3820 /*@C 3821 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3822 3823 Not collective 3824 3825 Input Parameters: 3826 + dm - The DMPlex 3827 . p - The mesh point 3828 . useCone - PETSC_TRUE for the closure, otherwise return the star 3829 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3830 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3831 3832 Note: 3833 If not using internal storage (points is not NULL on input), this call is unnecessary 3834 3835 Level: beginner 3836 3837 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3838 @*/ 3839 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3840 { 3841 PetscFunctionBeginHot; 3842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3843 if (numPoints) *numPoints = 0; 3844 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3845 PetscFunctionReturn(0); 3846 } 3847 3848 /*@ 3849 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3850 3851 Not collective 3852 3853 Input Parameter: 3854 . mesh - The DMPlex 3855 3856 Output Parameters: 3857 + maxConeSize - The maximum number of in-edges 3858 - maxSupportSize - The maximum number of out-edges 3859 3860 Level: beginner 3861 3862 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3863 @*/ 3864 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3865 { 3866 DM_Plex *mesh = (DM_Plex *)dm->data; 3867 3868 PetscFunctionBegin; 3869 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3870 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3871 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3872 PetscFunctionReturn(0); 3873 } 3874 3875 PetscErrorCode DMSetUp_Plex(DM dm) 3876 { 3877 DM_Plex *mesh = (DM_Plex *)dm->data; 3878 PetscInt size, maxSupportSize; 3879 3880 PetscFunctionBegin; 3881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3882 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3883 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3884 PetscCall(PetscMalloc1(size, &mesh->cones)); 3885 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3886 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3887 if (maxSupportSize) { 3888 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3889 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3890 PetscCall(PetscMalloc1(size, &mesh->supports)); 3891 } 3892 PetscFunctionReturn(0); 3893 } 3894 3895 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3896 { 3897 PetscFunctionBegin; 3898 if (subdm) PetscCall(DMClone(dm, subdm)); 3899 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3900 if (subdm) (*subdm)->useNatural = dm->useNatural; 3901 if (dm->useNatural && dm->sfMigration) { 3902 PetscSF sfNatural; 3903 3904 (*subdm)->sfMigration = dm->sfMigration; 3905 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3906 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3907 (*subdm)->sfNatural = sfNatural; 3908 } 3909 PetscFunctionReturn(0); 3910 } 3911 3912 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3913 { 3914 PetscInt i = 0; 3915 3916 PetscFunctionBegin; 3917 PetscCall(DMClone(dms[0], superdm)); 3918 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3919 (*superdm)->useNatural = PETSC_FALSE; 3920 for (i = 0; i < len; i++) { 3921 if (dms[i]->useNatural && dms[i]->sfMigration) { 3922 PetscSF sfNatural; 3923 3924 (*superdm)->sfMigration = dms[i]->sfMigration; 3925 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3926 (*superdm)->useNatural = PETSC_TRUE; 3927 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3928 (*superdm)->sfNatural = sfNatural; 3929 break; 3930 } 3931 } 3932 PetscFunctionReturn(0); 3933 } 3934 3935 /*@ 3936 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3937 3938 Not collective 3939 3940 Input Parameter: 3941 . mesh - The DMPlex 3942 3943 Output Parameter: 3944 3945 Note: 3946 This should be called after all calls to DMPlexSetCone() 3947 3948 Level: beginner 3949 3950 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3951 @*/ 3952 PetscErrorCode DMPlexSymmetrize(DM dm) 3953 { 3954 DM_Plex *mesh = (DM_Plex *)dm->data; 3955 PetscInt *offsets; 3956 PetscInt supportSize; 3957 PetscInt pStart, pEnd, p; 3958 3959 PetscFunctionBegin; 3960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3961 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3962 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3963 /* Calculate support sizes */ 3964 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3965 for (p = pStart; p < pEnd; ++p) { 3966 PetscInt dof, off, c; 3967 3968 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3969 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3970 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3971 } 3972 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3973 /* Calculate supports */ 3974 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3975 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3976 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3977 for (p = pStart; p < pEnd; ++p) { 3978 PetscInt dof, off, c; 3979 3980 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3981 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3982 for (c = off; c < off + dof; ++c) { 3983 const PetscInt q = mesh->cones[c]; 3984 PetscInt offS; 3985 3986 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3987 3988 mesh->supports[offS + offsets[q]] = p; 3989 ++offsets[q]; 3990 } 3991 } 3992 PetscCall(PetscFree(offsets)); 3993 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3994 PetscFunctionReturn(0); 3995 } 3996 3997 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3998 { 3999 IS stratumIS; 4000 4001 PetscFunctionBegin; 4002 if (pStart >= pEnd) PetscFunctionReturn(0); 4003 if (PetscDefined(USE_DEBUG)) { 4004 PetscInt qStart, qEnd, numLevels, level; 4005 PetscBool overlap = PETSC_FALSE; 4006 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4007 for (level = 0; level < numLevels; level++) { 4008 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4009 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4010 overlap = PETSC_TRUE; 4011 break; 4012 } 4013 } 4014 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); 4015 } 4016 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4017 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4018 PetscCall(ISDestroy(&stratumIS)); 4019 PetscFunctionReturn(0); 4020 } 4021 4022 /*@ 4023 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4024 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 4025 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 4026 the DAG. 4027 4028 Collective on dm 4029 4030 Input Parameter: 4031 . mesh - The DMPlex 4032 4033 Output Parameter: 4034 4035 Notes: 4036 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4037 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4038 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 4039 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 4040 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 4041 4042 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4043 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4044 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 4045 to interpolate only that one (e0), so that 4046 $ cone(c0) = {e0, v2} 4047 $ cone(e0) = {v0, v1} 4048 If DMPlexStratify() is run on this mesh, it will give depths 4049 $ depth 0 = {v0, v1, v2} 4050 $ depth 1 = {e0, c0} 4051 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4052 4053 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 4054 4055 Level: beginner 4056 4057 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4058 @*/ 4059 PetscErrorCode DMPlexStratify(DM dm) 4060 { 4061 DM_Plex *mesh = (DM_Plex *)dm->data; 4062 DMLabel label; 4063 PetscInt pStart, pEnd, p; 4064 PetscInt numRoots = 0, numLeaves = 0; 4065 4066 PetscFunctionBegin; 4067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4068 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4069 4070 /* Create depth label */ 4071 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4072 PetscCall(DMCreateLabel(dm, "depth")); 4073 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4074 4075 { 4076 /* Initialize roots and count leaves */ 4077 PetscInt sMin = PETSC_MAX_INT; 4078 PetscInt sMax = PETSC_MIN_INT; 4079 PetscInt coneSize, supportSize; 4080 4081 for (p = pStart; p < pEnd; ++p) { 4082 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4083 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4084 if (!coneSize && supportSize) { 4085 sMin = PetscMin(p, sMin); 4086 sMax = PetscMax(p, sMax); 4087 ++numRoots; 4088 } else if (!supportSize && coneSize) { 4089 ++numLeaves; 4090 } else if (!supportSize && !coneSize) { 4091 /* Isolated points */ 4092 sMin = PetscMin(p, sMin); 4093 sMax = PetscMax(p, sMax); 4094 } 4095 } 4096 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4097 } 4098 4099 if (numRoots + numLeaves == (pEnd - pStart)) { 4100 PetscInt sMin = PETSC_MAX_INT; 4101 PetscInt sMax = PETSC_MIN_INT; 4102 PetscInt coneSize, supportSize; 4103 4104 for (p = pStart; p < pEnd; ++p) { 4105 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4106 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4107 if (!supportSize && coneSize) { 4108 sMin = PetscMin(p, sMin); 4109 sMax = PetscMax(p, sMax); 4110 } 4111 } 4112 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4113 } else { 4114 PetscInt level = 0; 4115 PetscInt qStart, qEnd, q; 4116 4117 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4118 while (qEnd > qStart) { 4119 PetscInt sMin = PETSC_MAX_INT; 4120 PetscInt sMax = PETSC_MIN_INT; 4121 4122 for (q = qStart; q < qEnd; ++q) { 4123 const PetscInt *support; 4124 PetscInt supportSize, s; 4125 4126 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4127 PetscCall(DMPlexGetSupport(dm, q, &support)); 4128 for (s = 0; s < supportSize; ++s) { 4129 sMin = PetscMin(support[s], sMin); 4130 sMax = PetscMax(support[s], sMax); 4131 } 4132 } 4133 PetscCall(DMLabelGetNumValues(label, &level)); 4134 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4135 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4136 } 4137 } 4138 { /* just in case there is an empty process */ 4139 PetscInt numValues, maxValues = 0, v; 4140 4141 PetscCall(DMLabelGetNumValues(label, &numValues)); 4142 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4143 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4144 } 4145 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4146 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4147 PetscFunctionReturn(0); 4148 } 4149 4150 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4151 { 4152 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4153 PetscInt dim, depth, pheight, coneSize; 4154 4155 PetscFunctionBeginHot; 4156 PetscCall(DMGetDimension(dm, &dim)); 4157 PetscCall(DMPlexGetDepth(dm, &depth)); 4158 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4159 pheight = depth - pdepth; 4160 if (depth <= 1) { 4161 switch (pdepth) { 4162 case 0: 4163 ct = DM_POLYTOPE_POINT; 4164 break; 4165 case 1: 4166 switch (coneSize) { 4167 case 2: 4168 ct = DM_POLYTOPE_SEGMENT; 4169 break; 4170 case 3: 4171 ct = DM_POLYTOPE_TRIANGLE; 4172 break; 4173 case 4: 4174 switch (dim) { 4175 case 2: 4176 ct = DM_POLYTOPE_QUADRILATERAL; 4177 break; 4178 case 3: 4179 ct = DM_POLYTOPE_TETRAHEDRON; 4180 break; 4181 default: 4182 break; 4183 } 4184 break; 4185 case 5: 4186 ct = DM_POLYTOPE_PYRAMID; 4187 break; 4188 case 6: 4189 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4190 break; 4191 case 8: 4192 ct = DM_POLYTOPE_HEXAHEDRON; 4193 break; 4194 default: 4195 break; 4196 } 4197 } 4198 } else { 4199 if (pdepth == 0) { 4200 ct = DM_POLYTOPE_POINT; 4201 } else if (pheight == 0) { 4202 switch (dim) { 4203 case 1: 4204 switch (coneSize) { 4205 case 2: 4206 ct = DM_POLYTOPE_SEGMENT; 4207 break; 4208 default: 4209 break; 4210 } 4211 break; 4212 case 2: 4213 switch (coneSize) { 4214 case 3: 4215 ct = DM_POLYTOPE_TRIANGLE; 4216 break; 4217 case 4: 4218 ct = DM_POLYTOPE_QUADRILATERAL; 4219 break; 4220 default: 4221 break; 4222 } 4223 break; 4224 case 3: 4225 switch (coneSize) { 4226 case 4: 4227 ct = DM_POLYTOPE_TETRAHEDRON; 4228 break; 4229 case 5: { 4230 const PetscInt *cone; 4231 PetscInt faceConeSize; 4232 4233 PetscCall(DMPlexGetCone(dm, p, &cone)); 4234 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4235 switch (faceConeSize) { 4236 case 3: 4237 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4238 break; 4239 case 4: 4240 ct = DM_POLYTOPE_PYRAMID; 4241 break; 4242 } 4243 } break; 4244 case 6: 4245 ct = DM_POLYTOPE_HEXAHEDRON; 4246 break; 4247 default: 4248 break; 4249 } 4250 break; 4251 default: 4252 break; 4253 } 4254 } else if (pheight > 0) { 4255 switch (coneSize) { 4256 case 2: 4257 ct = DM_POLYTOPE_SEGMENT; 4258 break; 4259 case 3: 4260 ct = DM_POLYTOPE_TRIANGLE; 4261 break; 4262 case 4: 4263 ct = DM_POLYTOPE_QUADRILATERAL; 4264 break; 4265 default: 4266 break; 4267 } 4268 } 4269 } 4270 *pt = ct; 4271 PetscFunctionReturn(0); 4272 } 4273 4274 /*@ 4275 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4276 4277 Collective on dm 4278 4279 Input Parameter: 4280 . mesh - The DMPlex 4281 4282 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4283 4284 Level: developer 4285 4286 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4287 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4288 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4289 4290 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4291 @*/ 4292 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4293 { 4294 DM_Plex *mesh; 4295 DMLabel ctLabel; 4296 PetscInt pStart, pEnd, p; 4297 4298 PetscFunctionBegin; 4299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4300 mesh = (DM_Plex *)dm->data; 4301 PetscCall(DMCreateLabel(dm, "celltype")); 4302 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4303 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4304 for (p = pStart; p < pEnd; ++p) { 4305 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4306 PetscInt pdepth; 4307 4308 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4309 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4310 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4311 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4312 } 4313 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4314 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4315 PetscFunctionReturn(0); 4316 } 4317 4318 /*@C 4319 DMPlexGetJoin - Get an array for the join of the set of points 4320 4321 Not Collective 4322 4323 Input Parameters: 4324 + dm - The DMPlex object 4325 . numPoints - The number of input points for the join 4326 - points - The input points 4327 4328 Output Parameters: 4329 + numCoveredPoints - The number of points in the join 4330 - coveredPoints - The points in the join 4331 4332 Level: intermediate 4333 4334 Note: Currently, this is restricted to a single level join 4335 4336 Fortran Notes: 4337 Since it returns an array, this routine is only available in Fortran 90, and you must 4338 include petsc.h90 in your code. 4339 4340 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4341 4342 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4343 @*/ 4344 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4345 { 4346 DM_Plex *mesh = (DM_Plex *)dm->data; 4347 PetscInt *join[2]; 4348 PetscInt joinSize, i = 0; 4349 PetscInt dof, off, p, c, m; 4350 PetscInt maxSupportSize; 4351 4352 PetscFunctionBegin; 4353 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4354 PetscValidIntPointer(points, 3); 4355 PetscValidIntPointer(numCoveredPoints, 4); 4356 PetscValidPointer(coveredPoints, 5); 4357 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4358 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4359 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4360 /* Copy in support of first point */ 4361 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4362 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4363 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4364 /* Check each successive support */ 4365 for (p = 1; p < numPoints; ++p) { 4366 PetscInt newJoinSize = 0; 4367 4368 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4369 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4370 for (c = 0; c < dof; ++c) { 4371 const PetscInt point = mesh->supports[off + c]; 4372 4373 for (m = 0; m < joinSize; ++m) { 4374 if (point == join[i][m]) { 4375 join[1 - i][newJoinSize++] = point; 4376 break; 4377 } 4378 } 4379 } 4380 joinSize = newJoinSize; 4381 i = 1 - i; 4382 } 4383 *numCoveredPoints = joinSize; 4384 *coveredPoints = join[i]; 4385 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4386 PetscFunctionReturn(0); 4387 } 4388 4389 /*@C 4390 DMPlexRestoreJoin - Restore an array for the join of the set of points 4391 4392 Not Collective 4393 4394 Input Parameters: 4395 + dm - The DMPlex object 4396 . numPoints - The number of input points for the join 4397 - points - The input points 4398 4399 Output Parameters: 4400 + numCoveredPoints - The number of points in the join 4401 - coveredPoints - The points in the join 4402 4403 Fortran Notes: 4404 Since it returns an array, this routine is only available in Fortran 90, and you must 4405 include petsc.h90 in your code. 4406 4407 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4408 4409 Level: intermediate 4410 4411 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4412 @*/ 4413 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4414 { 4415 PetscFunctionBegin; 4416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4417 if (points) PetscValidIntPointer(points, 3); 4418 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4419 PetscValidPointer(coveredPoints, 5); 4420 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4421 if (numCoveredPoints) *numCoveredPoints = 0; 4422 PetscFunctionReturn(0); 4423 } 4424 4425 /*@C 4426 DMPlexGetFullJoin - Get an array for the join of the set of points 4427 4428 Not Collective 4429 4430 Input Parameters: 4431 + dm - The DMPlex object 4432 . numPoints - The number of input points for the join 4433 - points - The input points 4434 4435 Output Parameters: 4436 + numCoveredPoints - The number of points in the join 4437 - coveredPoints - The points in the join 4438 4439 Fortran Notes: 4440 Since it returns an array, this routine is only available in Fortran 90, and you must 4441 include petsc.h90 in your code. 4442 4443 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4444 4445 Level: intermediate 4446 4447 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4448 @*/ 4449 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4450 { 4451 PetscInt *offsets, **closures; 4452 PetscInt *join[2]; 4453 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4454 PetscInt p, d, c, m, ms; 4455 4456 PetscFunctionBegin; 4457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4458 PetscValidIntPointer(points, 3); 4459 PetscValidIntPointer(numCoveredPoints, 4); 4460 PetscValidPointer(coveredPoints, 5); 4461 4462 PetscCall(DMPlexGetDepth(dm, &depth)); 4463 PetscCall(PetscCalloc1(numPoints, &closures)); 4464 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4465 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4466 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4467 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4468 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4469 4470 for (p = 0; p < numPoints; ++p) { 4471 PetscInt closureSize; 4472 4473 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4474 4475 offsets[p * (depth + 2) + 0] = 0; 4476 for (d = 0; d < depth + 1; ++d) { 4477 PetscInt pStart, pEnd, i; 4478 4479 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4480 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4481 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4482 offsets[p * (depth + 2) + d + 1] = i; 4483 break; 4484 } 4485 } 4486 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4487 } 4488 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); 4489 } 4490 for (d = 0; d < depth + 1; ++d) { 4491 PetscInt dof; 4492 4493 /* Copy in support of first point */ 4494 dof = offsets[d + 1] - offsets[d]; 4495 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4496 /* Check each successive cone */ 4497 for (p = 1; p < numPoints && joinSize; ++p) { 4498 PetscInt newJoinSize = 0; 4499 4500 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4501 for (c = 0; c < dof; ++c) { 4502 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4503 4504 for (m = 0; m < joinSize; ++m) { 4505 if (point == join[i][m]) { 4506 join[1 - i][newJoinSize++] = point; 4507 break; 4508 } 4509 } 4510 } 4511 joinSize = newJoinSize; 4512 i = 1 - i; 4513 } 4514 if (joinSize) break; 4515 } 4516 *numCoveredPoints = joinSize; 4517 *coveredPoints = join[i]; 4518 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4519 PetscCall(PetscFree(closures)); 4520 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4521 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4522 PetscFunctionReturn(0); 4523 } 4524 4525 /*@C 4526 DMPlexGetMeet - Get an array for the meet of the set of points 4527 4528 Not Collective 4529 4530 Input Parameters: 4531 + dm - The DMPlex object 4532 . numPoints - The number of input points for the meet 4533 - points - The input points 4534 4535 Output Parameters: 4536 + numCoveredPoints - The number of points in the meet 4537 - coveredPoints - The points in the meet 4538 4539 Level: intermediate 4540 4541 Note: Currently, this is restricted to a single level meet 4542 4543 Fortran Notes: 4544 Since it returns an array, this routine is only available in Fortran 90, and you must 4545 include petsc.h90 in your code. 4546 4547 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4548 4549 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4550 @*/ 4551 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4552 { 4553 DM_Plex *mesh = (DM_Plex *)dm->data; 4554 PetscInt *meet[2]; 4555 PetscInt meetSize, i = 0; 4556 PetscInt dof, off, p, c, m; 4557 PetscInt maxConeSize; 4558 4559 PetscFunctionBegin; 4560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4561 PetscValidIntPointer(points, 3); 4562 PetscValidIntPointer(numCoveringPoints, 4); 4563 PetscValidPointer(coveringPoints, 5); 4564 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4565 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4566 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4567 /* Copy in cone of first point */ 4568 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4569 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4570 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4571 /* Check each successive cone */ 4572 for (p = 1; p < numPoints; ++p) { 4573 PetscInt newMeetSize = 0; 4574 4575 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4576 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4577 for (c = 0; c < dof; ++c) { 4578 const PetscInt point = mesh->cones[off + c]; 4579 4580 for (m = 0; m < meetSize; ++m) { 4581 if (point == meet[i][m]) { 4582 meet[1 - i][newMeetSize++] = point; 4583 break; 4584 } 4585 } 4586 } 4587 meetSize = newMeetSize; 4588 i = 1 - i; 4589 } 4590 *numCoveringPoints = meetSize; 4591 *coveringPoints = meet[i]; 4592 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4593 PetscFunctionReturn(0); 4594 } 4595 4596 /*@C 4597 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4598 4599 Not Collective 4600 4601 Input Parameters: 4602 + dm - The DMPlex object 4603 . numPoints - The number of input points for the meet 4604 - points - The input points 4605 4606 Output Parameters: 4607 + numCoveredPoints - The number of points in the meet 4608 - coveredPoints - The points in the meet 4609 4610 Level: intermediate 4611 4612 Fortran Notes: 4613 Since it returns an array, this routine is only available in Fortran 90, and you must 4614 include petsc.h90 in your code. 4615 4616 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4617 4618 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4619 @*/ 4620 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4621 { 4622 PetscFunctionBegin; 4623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4624 if (points) PetscValidIntPointer(points, 3); 4625 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4626 PetscValidPointer(coveredPoints, 5); 4627 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4628 if (numCoveredPoints) *numCoveredPoints = 0; 4629 PetscFunctionReturn(0); 4630 } 4631 4632 /*@C 4633 DMPlexGetFullMeet - Get an array for the meet of the set of points 4634 4635 Not Collective 4636 4637 Input Parameters: 4638 + dm - The DMPlex object 4639 . numPoints - The number of input points for the meet 4640 - points - The input points 4641 4642 Output Parameters: 4643 + numCoveredPoints - The number of points in the meet 4644 - coveredPoints - The points in the meet 4645 4646 Level: intermediate 4647 4648 Fortran Notes: 4649 Since it returns an array, this routine is only available in Fortran 90, and you must 4650 include petsc.h90 in your code. 4651 4652 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4653 4654 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4655 @*/ 4656 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4657 { 4658 PetscInt *offsets, **closures; 4659 PetscInt *meet[2]; 4660 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4661 PetscInt p, h, c, m, mc; 4662 4663 PetscFunctionBegin; 4664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4665 PetscValidIntPointer(points, 3); 4666 PetscValidIntPointer(numCoveredPoints, 4); 4667 PetscValidPointer(coveredPoints, 5); 4668 4669 PetscCall(DMPlexGetDepth(dm, &height)); 4670 PetscCall(PetscMalloc1(numPoints, &closures)); 4671 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4672 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4673 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4674 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4675 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4676 4677 for (p = 0; p < numPoints; ++p) { 4678 PetscInt closureSize; 4679 4680 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4681 4682 offsets[p * (height + 2) + 0] = 0; 4683 for (h = 0; h < height + 1; ++h) { 4684 PetscInt pStart, pEnd, i; 4685 4686 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4687 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4688 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4689 offsets[p * (height + 2) + h + 1] = i; 4690 break; 4691 } 4692 } 4693 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4694 } 4695 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); 4696 } 4697 for (h = 0; h < height + 1; ++h) { 4698 PetscInt dof; 4699 4700 /* Copy in cone of first point */ 4701 dof = offsets[h + 1] - offsets[h]; 4702 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4703 /* Check each successive cone */ 4704 for (p = 1; p < numPoints && meetSize; ++p) { 4705 PetscInt newMeetSize = 0; 4706 4707 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4708 for (c = 0; c < dof; ++c) { 4709 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4710 4711 for (m = 0; m < meetSize; ++m) { 4712 if (point == meet[i][m]) { 4713 meet[1 - i][newMeetSize++] = point; 4714 break; 4715 } 4716 } 4717 } 4718 meetSize = newMeetSize; 4719 i = 1 - i; 4720 } 4721 if (meetSize) break; 4722 } 4723 *numCoveredPoints = meetSize; 4724 *coveredPoints = meet[i]; 4725 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4726 PetscCall(PetscFree(closures)); 4727 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4728 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4729 PetscFunctionReturn(0); 4730 } 4731 4732 /*@C 4733 DMPlexEqual - Determine if two DMs have the same topology 4734 4735 Not Collective 4736 4737 Input Parameters: 4738 + dmA - A DMPlex object 4739 - dmB - A DMPlex object 4740 4741 Output Parameters: 4742 . equal - PETSC_TRUE if the topologies are identical 4743 4744 Level: intermediate 4745 4746 Notes: 4747 We are not solving graph isomorphism, so we do not permutation. 4748 4749 .seealso: `DMPlexGetCone()` 4750 @*/ 4751 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4752 { 4753 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4754 4755 PetscFunctionBegin; 4756 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4757 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4758 PetscValidBoolPointer(equal, 3); 4759 4760 *equal = PETSC_FALSE; 4761 PetscCall(DMPlexGetDepth(dmA, &depth)); 4762 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4763 if (depth != depthB) PetscFunctionReturn(0); 4764 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4765 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4766 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4767 for (p = pStart; p < pEnd; ++p) { 4768 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4769 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4770 4771 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4772 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4773 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4774 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4775 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4776 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4777 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4778 for (c = 0; c < coneSize; ++c) { 4779 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4780 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4781 } 4782 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4783 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4784 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4785 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4786 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4787 for (s = 0; s < supportSize; ++s) { 4788 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4789 } 4790 } 4791 *equal = PETSC_TRUE; 4792 PetscFunctionReturn(0); 4793 } 4794 4795 /*@C 4796 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4797 4798 Not Collective 4799 4800 Input Parameters: 4801 + dm - The DMPlex 4802 . cellDim - The cell dimension 4803 - numCorners - The number of vertices on a cell 4804 4805 Output Parameters: 4806 . numFaceVertices - The number of vertices on a face 4807 4808 Level: developer 4809 4810 Notes: 4811 Of course this can only work for a restricted set of symmetric shapes 4812 4813 .seealso: `DMPlexGetCone()` 4814 @*/ 4815 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4816 { 4817 MPI_Comm comm; 4818 4819 PetscFunctionBegin; 4820 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4821 PetscValidIntPointer(numFaceVertices, 4); 4822 switch (cellDim) { 4823 case 0: 4824 *numFaceVertices = 0; 4825 break; 4826 case 1: 4827 *numFaceVertices = 1; 4828 break; 4829 case 2: 4830 switch (numCorners) { 4831 case 3: /* triangle */ 4832 *numFaceVertices = 2; /* Edge has 2 vertices */ 4833 break; 4834 case 4: /* quadrilateral */ 4835 *numFaceVertices = 2; /* Edge has 2 vertices */ 4836 break; 4837 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4838 *numFaceVertices = 3; /* Edge has 3 vertices */ 4839 break; 4840 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4841 *numFaceVertices = 3; /* Edge has 3 vertices */ 4842 break; 4843 default: 4844 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4845 } 4846 break; 4847 case 3: 4848 switch (numCorners) { 4849 case 4: /* tetradehdron */ 4850 *numFaceVertices = 3; /* Face has 3 vertices */ 4851 break; 4852 case 6: /* tet cohesive cells */ 4853 *numFaceVertices = 4; /* Face has 4 vertices */ 4854 break; 4855 case 8: /* hexahedron */ 4856 *numFaceVertices = 4; /* Face has 4 vertices */ 4857 break; 4858 case 9: /* tet cohesive Lagrange cells */ 4859 *numFaceVertices = 6; /* Face has 6 vertices */ 4860 break; 4861 case 10: /* quadratic tetrahedron */ 4862 *numFaceVertices = 6; /* Face has 6 vertices */ 4863 break; 4864 case 12: /* hex cohesive Lagrange cells */ 4865 *numFaceVertices = 6; /* Face has 6 vertices */ 4866 break; 4867 case 18: /* quadratic tet cohesive Lagrange cells */ 4868 *numFaceVertices = 6; /* Face has 6 vertices */ 4869 break; 4870 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4871 *numFaceVertices = 9; /* Face has 9 vertices */ 4872 break; 4873 default: 4874 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4875 } 4876 break; 4877 default: 4878 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4879 } 4880 PetscFunctionReturn(0); 4881 } 4882 4883 /*@ 4884 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4885 4886 Not Collective 4887 4888 Input Parameter: 4889 . dm - The DMPlex object 4890 4891 Output Parameter: 4892 . depthLabel - The DMLabel recording point depth 4893 4894 Level: developer 4895 4896 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4897 @*/ 4898 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4899 { 4900 PetscFunctionBegin; 4901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4902 PetscValidPointer(depthLabel, 2); 4903 *depthLabel = dm->depthLabel; 4904 PetscFunctionReturn(0); 4905 } 4906 4907 /*@ 4908 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4909 4910 Not Collective 4911 4912 Input Parameter: 4913 . dm - The DMPlex object 4914 4915 Output Parameter: 4916 . depth - The number of strata (breadth first levels) in the DAG 4917 4918 Level: developer 4919 4920 Notes: 4921 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4922 The point depth is described more in detail in DMPlexGetDepthStratum(). 4923 An empty mesh gives -1. 4924 4925 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4926 @*/ 4927 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4928 { 4929 DM_Plex *mesh = (DM_Plex *)dm->data; 4930 DMLabel label; 4931 PetscInt d = 0; 4932 4933 PetscFunctionBegin; 4934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4935 PetscValidIntPointer(depth, 2); 4936 if (mesh->tr) { 4937 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 4938 } else { 4939 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4940 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4941 *depth = d - 1; 4942 } 4943 PetscFunctionReturn(0); 4944 } 4945 4946 /*@ 4947 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4948 4949 Not Collective 4950 4951 Input Parameters: 4952 + dm - The DMPlex object 4953 - depth - The requested depth 4954 4955 Output Parameters: 4956 + start - The first point at this depth 4957 - end - One beyond the last point at this depth 4958 4959 Notes: 4960 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4961 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4962 higher dimension, e.g., "edges". 4963 4964 Level: developer 4965 4966 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4967 @*/ 4968 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4969 { 4970 DM_Plex *mesh = (DM_Plex *)dm->data; 4971 DMLabel label; 4972 PetscInt pStart, pEnd; 4973 4974 PetscFunctionBegin; 4975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4976 if (start) { 4977 PetscValidIntPointer(start, 3); 4978 *start = 0; 4979 } 4980 if (end) { 4981 PetscValidIntPointer(end, 4); 4982 *end = 0; 4983 } 4984 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4985 if (pStart == pEnd) PetscFunctionReturn(0); 4986 if (depth < 0) { 4987 if (start) *start = pStart; 4988 if (end) *end = pEnd; 4989 PetscFunctionReturn(0); 4990 } 4991 if (mesh->tr) { 4992 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 4993 } else { 4994 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4995 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4996 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4997 } 4998 PetscFunctionReturn(0); 4999 } 5000 5001 /*@ 5002 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 5003 5004 Not Collective 5005 5006 Input Parameters: 5007 + dm - The DMPlex object 5008 - height - The requested height 5009 5010 Output Parameters: 5011 + start - The first point at this height 5012 - end - One beyond the last point at this height 5013 5014 Notes: 5015 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5016 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 5017 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5018 5019 Level: developer 5020 5021 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5022 @*/ 5023 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5024 { 5025 DMLabel label; 5026 PetscInt depth, pStart, pEnd; 5027 5028 PetscFunctionBegin; 5029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5030 if (start) { 5031 PetscValidIntPointer(start, 3); 5032 *start = 0; 5033 } 5034 if (end) { 5035 PetscValidIntPointer(end, 4); 5036 *end = 0; 5037 } 5038 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5039 if (pStart == pEnd) PetscFunctionReturn(0); 5040 if (height < 0) { 5041 if (start) *start = pStart; 5042 if (end) *end = pEnd; 5043 PetscFunctionReturn(0); 5044 } 5045 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5046 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5047 PetscCall(DMLabelGetNumValues(label, &depth)); 5048 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 5049 PetscFunctionReturn(0); 5050 } 5051 5052 /*@ 5053 DMPlexGetPointDepth - Get the depth of a given point 5054 5055 Not Collective 5056 5057 Input Parameters: 5058 + dm - The DMPlex object 5059 - point - The point 5060 5061 Output Parameter: 5062 . depth - The depth of the point 5063 5064 Level: intermediate 5065 5066 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5067 @*/ 5068 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5069 { 5070 PetscFunctionBegin; 5071 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5072 PetscValidIntPointer(depth, 3); 5073 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5074 PetscFunctionReturn(0); 5075 } 5076 5077 /*@ 5078 DMPlexGetPointHeight - Get the height of a given point 5079 5080 Not Collective 5081 5082 Input Parameters: 5083 + dm - The DMPlex object 5084 - point - The point 5085 5086 Output Parameter: 5087 . height - The height of the point 5088 5089 Level: intermediate 5090 5091 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5092 @*/ 5093 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5094 { 5095 PetscInt n, pDepth; 5096 5097 PetscFunctionBegin; 5098 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5099 PetscValidIntPointer(height, 3); 5100 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5101 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5102 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5103 PetscFunctionReturn(0); 5104 } 5105 5106 /*@ 5107 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 5108 5109 Not Collective 5110 5111 Input Parameter: 5112 . dm - The DMPlex object 5113 5114 Output Parameter: 5115 . celltypeLabel - The DMLabel recording cell polytope type 5116 5117 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 5118 DMCreateLabel(dm, "celltype") beforehand. 5119 5120 Level: developer 5121 5122 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5123 @*/ 5124 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5125 { 5126 PetscFunctionBegin; 5127 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5128 PetscValidPointer(celltypeLabel, 2); 5129 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5130 *celltypeLabel = dm->celltypeLabel; 5131 PetscFunctionReturn(0); 5132 } 5133 5134 /*@ 5135 DMPlexGetCellType - Get the polytope type of a given cell 5136 5137 Not Collective 5138 5139 Input Parameters: 5140 + dm - The DMPlex object 5141 - cell - The cell 5142 5143 Output Parameter: 5144 . celltype - The polytope type of the cell 5145 5146 Level: intermediate 5147 5148 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5149 @*/ 5150 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5151 { 5152 DM_Plex *mesh = (DM_Plex *)dm->data; 5153 DMLabel label; 5154 PetscInt ct; 5155 5156 PetscFunctionBegin; 5157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5158 PetscValidPointer(celltype, 3); 5159 if (mesh->tr) { 5160 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5161 } else { 5162 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5163 PetscCall(DMLabelGetValue(label, cell, &ct)); 5164 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5165 *celltype = (DMPolytopeType)ct; 5166 } 5167 PetscFunctionReturn(0); 5168 } 5169 5170 /*@ 5171 DMPlexSetCellType - Set the polytope type of a given cell 5172 5173 Not Collective 5174 5175 Input Parameters: 5176 + dm - The DMPlex object 5177 . cell - The cell 5178 - celltype - The polytope type of the cell 5179 5180 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5181 is executed. This function will override the computed type. However, if automatic classification will not succeed 5182 and a user wants to manually specify all types, the classification must be disabled by calling 5183 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5184 5185 Level: advanced 5186 5187 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5188 @*/ 5189 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5190 { 5191 DMLabel label; 5192 5193 PetscFunctionBegin; 5194 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5195 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5196 PetscCall(DMLabelSetValue(label, cell, celltype)); 5197 PetscFunctionReturn(0); 5198 } 5199 5200 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5201 { 5202 PetscSection section, s; 5203 Mat m; 5204 PetscInt maxHeight; 5205 const char *prefix; 5206 5207 PetscFunctionBegin; 5208 PetscCall(DMClone(dm, cdm)); 5209 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5210 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5211 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5212 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5213 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5214 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5215 PetscCall(DMSetLocalSection(*cdm, section)); 5216 PetscCall(PetscSectionDestroy(§ion)); 5217 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5218 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5219 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5220 PetscCall(PetscSectionDestroy(&s)); 5221 PetscCall(MatDestroy(&m)); 5222 5223 PetscCall(DMSetNumFields(*cdm, 1)); 5224 PetscCall(DMCreateDS(*cdm)); 5225 (*cdm)->cloneOpts = PETSC_TRUE; 5226 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5227 PetscFunctionReturn(0); 5228 } 5229 5230 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5231 { 5232 Vec coordsLocal, cellCoordsLocal; 5233 DM coordsDM, cellCoordsDM; 5234 5235 PetscFunctionBegin; 5236 *field = NULL; 5237 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5238 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5239 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5240 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5241 if (coordsLocal && coordsDM) { 5242 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5243 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5244 } 5245 PetscFunctionReturn(0); 5246 } 5247 5248 /*@C 5249 DMPlexGetConeSection - Return a section which describes the layout of cone data 5250 5251 Not Collective 5252 5253 Input Parameters: 5254 . dm - The DMPlex object 5255 5256 Output Parameter: 5257 . section - The PetscSection object 5258 5259 Level: developer 5260 5261 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5262 @*/ 5263 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5264 { 5265 DM_Plex *mesh = (DM_Plex *)dm->data; 5266 5267 PetscFunctionBegin; 5268 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5269 if (section) *section = mesh->coneSection; 5270 PetscFunctionReturn(0); 5271 } 5272 5273 /*@C 5274 DMPlexGetSupportSection - Return a section which describes the layout of support data 5275 5276 Not Collective 5277 5278 Input Parameters: 5279 . dm - The DMPlex object 5280 5281 Output Parameter: 5282 . section - The PetscSection object 5283 5284 Level: developer 5285 5286 .seealso: `DMPlexGetConeSection()` 5287 @*/ 5288 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5289 { 5290 DM_Plex *mesh = (DM_Plex *)dm->data; 5291 5292 PetscFunctionBegin; 5293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5294 if (section) *section = mesh->supportSection; 5295 PetscFunctionReturn(0); 5296 } 5297 5298 /*@C 5299 DMPlexGetCones - Return cone data 5300 5301 Not Collective 5302 5303 Input Parameters: 5304 . dm - The DMPlex object 5305 5306 Output Parameter: 5307 . cones - The cone for each point 5308 5309 Level: developer 5310 5311 .seealso: `DMPlexGetConeSection()` 5312 @*/ 5313 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5314 { 5315 DM_Plex *mesh = (DM_Plex *)dm->data; 5316 5317 PetscFunctionBegin; 5318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5319 if (cones) *cones = mesh->cones; 5320 PetscFunctionReturn(0); 5321 } 5322 5323 /*@C 5324 DMPlexGetConeOrientations - Return cone orientation data 5325 5326 Not Collective 5327 5328 Input Parameters: 5329 . dm - The DMPlex object 5330 5331 Output Parameter: 5332 . coneOrientations - The array of cone orientations for all points 5333 5334 Level: developer 5335 5336 Notes: 5337 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5338 5339 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5340 5341 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5342 @*/ 5343 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5344 { 5345 DM_Plex *mesh = (DM_Plex *)dm->data; 5346 5347 PetscFunctionBegin; 5348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5349 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5350 PetscFunctionReturn(0); 5351 } 5352 5353 /******************************** FEM Support **********************************/ 5354 5355 /* 5356 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5357 representing a line in the section. 5358 */ 5359 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5360 { 5361 PetscFunctionBeginHot; 5362 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5363 if (line < 0) { 5364 *k = 0; 5365 *Nc = 0; 5366 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5367 *k = 1; 5368 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5369 /* An order k SEM disc has k-1 dofs on an edge */ 5370 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5371 *k = *k / *Nc + 1; 5372 } 5373 PetscFunctionReturn(0); 5374 } 5375 5376 /*@ 5377 5378 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5379 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5380 section provided (or the section of the DM). 5381 5382 Input Parameters: 5383 + dm - The DM 5384 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5385 - section - The PetscSection to reorder, or NULL for the default section 5386 5387 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5388 degree of the basis. 5389 5390 Example: 5391 A typical interpolated single-quad mesh might order points as 5392 .vb 5393 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5394 5395 v4 -- e6 -- v3 5396 | | 5397 e7 c0 e8 5398 | | 5399 v1 -- e5 -- v2 5400 .ve 5401 5402 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5403 dofs in the order of points, e.g., 5404 .vb 5405 c0 -> [0,1,2,3] 5406 v1 -> [4] 5407 ... 5408 e5 -> [8, 9] 5409 .ve 5410 5411 which corresponds to the dofs 5412 .vb 5413 6 10 11 7 5414 13 2 3 15 5415 12 0 1 14 5416 4 8 9 5 5417 .ve 5418 5419 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5420 .vb 5421 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5422 .ve 5423 5424 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5425 .vb 5426 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5427 .ve 5428 5429 Level: developer 5430 5431 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5432 @*/ 5433 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5434 { 5435 DMLabel label; 5436 PetscInt dim, depth = -1, eStart = -1, Nf; 5437 PetscBool vertexchart; 5438 5439 PetscFunctionBegin; 5440 PetscCall(DMGetDimension(dm, &dim)); 5441 if (dim < 1) PetscFunctionReturn(0); 5442 if (point < 0) { 5443 PetscInt sStart, sEnd; 5444 5445 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5446 point = sEnd - sStart ? sStart : point; 5447 } 5448 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5449 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5450 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5451 if (depth == 1) { 5452 eStart = point; 5453 } else if (depth == dim) { 5454 const PetscInt *cone; 5455 5456 PetscCall(DMPlexGetCone(dm, point, &cone)); 5457 if (dim == 2) eStart = cone[0]; 5458 else if (dim == 3) { 5459 const PetscInt *cone2; 5460 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5461 eStart = cone2[0]; 5462 } 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); 5463 } 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); 5464 { /* Determine whether the chart covers all points or just vertices. */ 5465 PetscInt pStart, pEnd, cStart, cEnd; 5466 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5467 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5468 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5469 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5470 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5471 } 5472 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5473 for (PetscInt d = 1; d <= dim; d++) { 5474 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5475 PetscInt *perm; 5476 5477 for (f = 0; f < Nf; ++f) { 5478 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5479 size += PetscPowInt(k + 1, d) * Nc; 5480 } 5481 PetscCall(PetscMalloc1(size, &perm)); 5482 for (f = 0; f < Nf; ++f) { 5483 switch (d) { 5484 case 1: 5485 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5486 /* 5487 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5488 We want [ vtx0; edge of length k-1; vtx1 ] 5489 */ 5490 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5491 for (i = 0; i < k - 1; i++) 5492 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5493 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5494 foffset = offset; 5495 break; 5496 case 2: 5497 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5498 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5499 /* The SEM order is 5500 5501 v_lb, {e_b}, v_rb, 5502 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5503 v_lt, reverse {e_t}, v_rt 5504 */ 5505 { 5506 const PetscInt of = 0; 5507 const PetscInt oeb = of + PetscSqr(k - 1); 5508 const PetscInt oer = oeb + (k - 1); 5509 const PetscInt oet = oer + (k - 1); 5510 const PetscInt oel = oet + (k - 1); 5511 const PetscInt ovlb = oel + (k - 1); 5512 const PetscInt ovrb = ovlb + 1; 5513 const PetscInt ovrt = ovrb + 1; 5514 const PetscInt ovlt = ovrt + 1; 5515 PetscInt o; 5516 5517 /* bottom */ 5518 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5519 for (o = oeb; o < oer; ++o) 5520 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5521 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5522 /* middle */ 5523 for (i = 0; i < k - 1; ++i) { 5524 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5525 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5526 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5527 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5528 } 5529 /* top */ 5530 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5531 for (o = oel - 1; o >= oet; --o) 5532 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5533 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5534 foffset = offset; 5535 } 5536 break; 5537 case 3: 5538 /* The original hex closure is 5539 5540 {c, 5541 f_b, f_t, f_f, f_b, f_r, f_l, 5542 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5543 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5544 */ 5545 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5546 /* The SEM order is 5547 Bottom Slice 5548 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5549 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5550 v_blb, {e_bb}, v_brb, 5551 5552 Middle Slice (j) 5553 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5554 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5555 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5556 5557 Top Slice 5558 v_tlf, {e_tf}, v_trf, 5559 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5560 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5561 */ 5562 { 5563 const PetscInt oc = 0; 5564 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5565 const PetscInt oft = ofb + PetscSqr(k - 1); 5566 const PetscInt off = oft + PetscSqr(k - 1); 5567 const PetscInt ofk = off + PetscSqr(k - 1); 5568 const PetscInt ofr = ofk + PetscSqr(k - 1); 5569 const PetscInt ofl = ofr + PetscSqr(k - 1); 5570 const PetscInt oebl = ofl + PetscSqr(k - 1); 5571 const PetscInt oebb = oebl + (k - 1); 5572 const PetscInt oebr = oebb + (k - 1); 5573 const PetscInt oebf = oebr + (k - 1); 5574 const PetscInt oetf = oebf + (k - 1); 5575 const PetscInt oetr = oetf + (k - 1); 5576 const PetscInt oetb = oetr + (k - 1); 5577 const PetscInt oetl = oetb + (k - 1); 5578 const PetscInt oerf = oetl + (k - 1); 5579 const PetscInt oelf = oerf + (k - 1); 5580 const PetscInt oelb = oelf + (k - 1); 5581 const PetscInt oerb = oelb + (k - 1); 5582 const PetscInt ovblf = oerb + (k - 1); 5583 const PetscInt ovblb = ovblf + 1; 5584 const PetscInt ovbrb = ovblb + 1; 5585 const PetscInt ovbrf = ovbrb + 1; 5586 const PetscInt ovtlf = ovbrf + 1; 5587 const PetscInt ovtrf = ovtlf + 1; 5588 const PetscInt ovtrb = ovtrf + 1; 5589 const PetscInt ovtlb = ovtrb + 1; 5590 PetscInt o, n; 5591 5592 /* Bottom Slice */ 5593 /* bottom */ 5594 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5595 for (o = oetf - 1; o >= oebf; --o) 5596 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5597 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5598 /* middle */ 5599 for (i = 0; i < k - 1; ++i) { 5600 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5601 for (n = 0; n < k - 1; ++n) { 5602 o = ofb + n * (k - 1) + i; 5603 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5604 } 5605 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5606 } 5607 /* top */ 5608 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5609 for (o = oebb; o < oebr; ++o) 5610 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5611 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5612 5613 /* Middle Slice */ 5614 for (j = 0; j < k - 1; ++j) { 5615 /* bottom */ 5616 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5617 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5618 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5619 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5620 /* middle */ 5621 for (i = 0; i < k - 1; ++i) { 5622 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5623 for (n = 0; n < k - 1; ++n) 5624 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5625 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5626 } 5627 /* top */ 5628 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5629 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5630 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5631 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5632 } 5633 5634 /* Top Slice */ 5635 /* bottom */ 5636 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5637 for (o = oetf; o < oetr; ++o) 5638 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5639 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5640 /* middle */ 5641 for (i = 0; i < k - 1; ++i) { 5642 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5643 for (n = 0; n < k - 1; ++n) 5644 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5645 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5646 } 5647 /* top */ 5648 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5649 for (o = oetl - 1; o >= oetb; --o) 5650 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5651 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5652 5653 foffset = offset; 5654 } 5655 break; 5656 default: 5657 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5658 } 5659 } 5660 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5661 /* Check permutation */ 5662 { 5663 PetscInt *check; 5664 5665 PetscCall(PetscMalloc1(size, &check)); 5666 for (i = 0; i < size; ++i) { 5667 check[i] = -1; 5668 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5669 } 5670 for (i = 0; i < size; ++i) check[perm[i]] = i; 5671 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5672 PetscCall(PetscFree(check)); 5673 } 5674 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5675 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5676 PetscInt *loc_perm; 5677 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5678 for (PetscInt i = 0; i < size; i++) { 5679 loc_perm[i] = perm[i]; 5680 loc_perm[size + i] = size + perm[i]; 5681 } 5682 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5683 } 5684 } 5685 PetscFunctionReturn(0); 5686 } 5687 5688 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5689 { 5690 PetscDS prob; 5691 PetscInt depth, Nf, h; 5692 DMLabel label; 5693 5694 PetscFunctionBeginHot; 5695 PetscCall(DMGetDS(dm, &prob)); 5696 Nf = prob->Nf; 5697 label = dm->depthLabel; 5698 *dspace = NULL; 5699 if (field < Nf) { 5700 PetscObject disc = prob->disc[field]; 5701 5702 if (disc->classid == PETSCFE_CLASSID) { 5703 PetscDualSpace dsp; 5704 5705 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5706 PetscCall(DMLabelGetNumValues(label, &depth)); 5707 PetscCall(DMLabelGetValue(label, point, &h)); 5708 h = depth - 1 - h; 5709 if (h) { 5710 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5711 } else { 5712 *dspace = dsp; 5713 } 5714 } 5715 } 5716 PetscFunctionReturn(0); 5717 } 5718 5719 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5720 { 5721 PetscScalar *array; 5722 const PetscScalar *vArray; 5723 const PetscInt *cone, *coneO; 5724 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5725 5726 PetscFunctionBeginHot; 5727 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5728 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5729 PetscCall(DMPlexGetCone(dm, point, &cone)); 5730 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5731 if (!values || !*values) { 5732 if ((point >= pStart) && (point < pEnd)) { 5733 PetscInt dof; 5734 5735 PetscCall(PetscSectionGetDof(section, point, &dof)); 5736 size += dof; 5737 } 5738 for (p = 0; p < numPoints; ++p) { 5739 const PetscInt cp = cone[p]; 5740 PetscInt dof; 5741 5742 if ((cp < pStart) || (cp >= pEnd)) continue; 5743 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5744 size += dof; 5745 } 5746 if (!values) { 5747 if (csize) *csize = size; 5748 PetscFunctionReturn(0); 5749 } 5750 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5751 } else { 5752 array = *values; 5753 } 5754 size = 0; 5755 PetscCall(VecGetArrayRead(v, &vArray)); 5756 if ((point >= pStart) && (point < pEnd)) { 5757 PetscInt dof, off, d; 5758 const PetscScalar *varr; 5759 5760 PetscCall(PetscSectionGetDof(section, point, &dof)); 5761 PetscCall(PetscSectionGetOffset(section, point, &off)); 5762 varr = &vArray[off]; 5763 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5764 size += dof; 5765 } 5766 for (p = 0; p < numPoints; ++p) { 5767 const PetscInt cp = cone[p]; 5768 PetscInt o = coneO[p]; 5769 PetscInt dof, off, d; 5770 const PetscScalar *varr; 5771 5772 if ((cp < pStart) || (cp >= pEnd)) continue; 5773 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5774 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5775 varr = &vArray[off]; 5776 if (o >= 0) { 5777 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5778 } else { 5779 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5780 } 5781 size += dof; 5782 } 5783 PetscCall(VecRestoreArrayRead(v, &vArray)); 5784 if (!*values) { 5785 if (csize) *csize = size; 5786 *values = array; 5787 } else { 5788 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5789 *csize = size; 5790 } 5791 PetscFunctionReturn(0); 5792 } 5793 5794 /* Compress out points not in the section */ 5795 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5796 { 5797 const PetscInt np = *numPoints; 5798 PetscInt pStart, pEnd, p, q; 5799 5800 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5801 for (p = 0, q = 0; p < np; ++p) { 5802 const PetscInt r = points[p * 2]; 5803 if ((r >= pStart) && (r < pEnd)) { 5804 points[q * 2] = r; 5805 points[q * 2 + 1] = points[p * 2 + 1]; 5806 ++q; 5807 } 5808 } 5809 *numPoints = q; 5810 return 0; 5811 } 5812 5813 /* Compressed closure does not apply closure permutation */ 5814 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5815 { 5816 const PetscInt *cla = NULL; 5817 PetscInt np, *pts = NULL; 5818 5819 PetscFunctionBeginHot; 5820 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5821 if (*clPoints) { 5822 PetscInt dof, off; 5823 5824 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5825 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5826 PetscCall(ISGetIndices(*clPoints, &cla)); 5827 np = dof / 2; 5828 pts = (PetscInt *)&cla[off]; 5829 } else { 5830 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5831 PetscCall(CompressPoints_Private(section, &np, pts)); 5832 } 5833 *numPoints = np; 5834 *points = pts; 5835 *clp = cla; 5836 PetscFunctionReturn(0); 5837 } 5838 5839 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5840 { 5841 PetscFunctionBeginHot; 5842 if (!*clPoints) { 5843 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5844 } else { 5845 PetscCall(ISRestoreIndices(*clPoints, clp)); 5846 } 5847 *numPoints = 0; 5848 *points = NULL; 5849 *clSec = NULL; 5850 *clPoints = NULL; 5851 *clp = NULL; 5852 PetscFunctionReturn(0); 5853 } 5854 5855 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5856 { 5857 PetscInt offset = 0, p; 5858 const PetscInt **perms = NULL; 5859 const PetscScalar **flips = NULL; 5860 5861 PetscFunctionBeginHot; 5862 *size = 0; 5863 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5864 for (p = 0; p < numPoints; p++) { 5865 const PetscInt point = points[2 * p]; 5866 const PetscInt *perm = perms ? perms[p] : NULL; 5867 const PetscScalar *flip = flips ? flips[p] : NULL; 5868 PetscInt dof, off, d; 5869 const PetscScalar *varr; 5870 5871 PetscCall(PetscSectionGetDof(section, point, &dof)); 5872 PetscCall(PetscSectionGetOffset(section, point, &off)); 5873 varr = &vArray[off]; 5874 if (clperm) { 5875 if (perm) { 5876 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5877 } else { 5878 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5879 } 5880 if (flip) { 5881 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5882 } 5883 } else { 5884 if (perm) { 5885 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5886 } else { 5887 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5888 } 5889 if (flip) { 5890 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5891 } 5892 } 5893 offset += dof; 5894 } 5895 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5896 *size = offset; 5897 PetscFunctionReturn(0); 5898 } 5899 5900 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[]) 5901 { 5902 PetscInt offset = 0, f; 5903 5904 PetscFunctionBeginHot; 5905 *size = 0; 5906 for (f = 0; f < numFields; ++f) { 5907 PetscInt p; 5908 const PetscInt **perms = NULL; 5909 const PetscScalar **flips = NULL; 5910 5911 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5912 for (p = 0; p < numPoints; p++) { 5913 const PetscInt point = points[2 * p]; 5914 PetscInt fdof, foff, b; 5915 const PetscScalar *varr; 5916 const PetscInt *perm = perms ? perms[p] : NULL; 5917 const PetscScalar *flip = flips ? flips[p] : NULL; 5918 5919 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5920 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5921 varr = &vArray[foff]; 5922 if (clperm) { 5923 if (perm) { 5924 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5925 } else { 5926 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5927 } 5928 if (flip) { 5929 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5930 } 5931 } else { 5932 if (perm) { 5933 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5934 } else { 5935 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5936 } 5937 if (flip) { 5938 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5939 } 5940 } 5941 offset += fdof; 5942 } 5943 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5944 } 5945 *size = offset; 5946 PetscFunctionReturn(0); 5947 } 5948 5949 /*@C 5950 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5951 5952 Not collective 5953 5954 Input Parameters: 5955 + dm - The DM 5956 . section - The section describing the layout in v, or NULL to use the default section 5957 . v - The local vector 5958 - point - The point in the DM 5959 5960 Input/Output Parameters: 5961 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5962 - values - An array to use for the values, or NULL to have it allocated automatically; 5963 if the user provided NULL, it is a borrowed array and should not be freed 5964 5965 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5966 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5967 $ assembly function, and a user may already have allocated storage for this operation. 5968 $ 5969 $ A typical use could be 5970 $ 5971 $ values = NULL; 5972 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5973 $ for (cl = 0; cl < clSize; ++cl) { 5974 $ <Compute on closure> 5975 $ } 5976 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5977 $ 5978 $ or 5979 $ 5980 $ PetscMalloc1(clMaxSize, &values); 5981 $ for (p = pStart; p < pEnd; ++p) { 5982 $ clSize = clMaxSize; 5983 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5984 $ for (cl = 0; cl < clSize; ++cl) { 5985 $ <Compute on closure> 5986 $ } 5987 $ } 5988 $ PetscFree(values); 5989 5990 Fortran Notes: 5991 Since it returns an array, this routine is only available in Fortran 90, and you must 5992 include petsc.h90 in your code. 5993 5994 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5995 5996 Level: intermediate 5997 5998 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5999 @*/ 6000 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6001 { 6002 PetscSection clSection; 6003 IS clPoints; 6004 PetscInt *points = NULL; 6005 const PetscInt *clp, *perm; 6006 PetscInt depth, numFields, numPoints, asize; 6007 6008 PetscFunctionBeginHot; 6009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6010 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6011 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6012 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6013 PetscCall(DMPlexGetDepth(dm, &depth)); 6014 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6015 if (depth == 1 && numFields < 2) { 6016 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6017 PetscFunctionReturn(0); 6018 } 6019 /* Get points */ 6020 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6021 /* Get sizes */ 6022 asize = 0; 6023 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6024 PetscInt dof; 6025 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6026 asize += dof; 6027 } 6028 if (values) { 6029 const PetscScalar *vArray; 6030 PetscInt size; 6031 6032 if (*values) { 6033 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); 6034 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6035 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6036 PetscCall(VecGetArrayRead(v, &vArray)); 6037 /* Get values */ 6038 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6039 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6040 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6041 /* Cleanup array */ 6042 PetscCall(VecRestoreArrayRead(v, &vArray)); 6043 } 6044 if (csize) *csize = asize; 6045 /* Cleanup points */ 6046 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6047 PetscFunctionReturn(0); 6048 } 6049 6050 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6051 { 6052 DMLabel depthLabel; 6053 PetscSection clSection; 6054 IS clPoints; 6055 PetscScalar *array; 6056 const PetscScalar *vArray; 6057 PetscInt *points = NULL; 6058 const PetscInt *clp, *perm = NULL; 6059 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6060 6061 PetscFunctionBeginHot; 6062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6063 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6064 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6065 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6066 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6067 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6068 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6069 if (mdepth == 1 && numFields < 2) { 6070 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6071 PetscFunctionReturn(0); 6072 } 6073 /* Get points */ 6074 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6075 for (clsize = 0, p = 0; p < Np; p++) { 6076 PetscInt dof; 6077 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6078 clsize += dof; 6079 } 6080 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6081 /* Filter points */ 6082 for (p = 0; p < numPoints * 2; p += 2) { 6083 PetscInt dep; 6084 6085 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6086 if (dep != depth) continue; 6087 points[Np * 2 + 0] = points[p]; 6088 points[Np * 2 + 1] = points[p + 1]; 6089 ++Np; 6090 } 6091 /* Get array */ 6092 if (!values || !*values) { 6093 PetscInt asize = 0, dof; 6094 6095 for (p = 0; p < Np * 2; p += 2) { 6096 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6097 asize += dof; 6098 } 6099 if (!values) { 6100 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6101 if (csize) *csize = asize; 6102 PetscFunctionReturn(0); 6103 } 6104 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6105 } else { 6106 array = *values; 6107 } 6108 PetscCall(VecGetArrayRead(v, &vArray)); 6109 /* Get values */ 6110 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6111 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6112 /* Cleanup points */ 6113 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6114 /* Cleanup array */ 6115 PetscCall(VecRestoreArrayRead(v, &vArray)); 6116 if (!*values) { 6117 if (csize) *csize = size; 6118 *values = array; 6119 } else { 6120 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6121 *csize = size; 6122 } 6123 PetscFunctionReturn(0); 6124 } 6125 6126 /*@C 6127 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6128 6129 Not collective 6130 6131 Input Parameters: 6132 + dm - The DM 6133 . section - The section describing the layout in v, or NULL to use the default section 6134 . v - The local vector 6135 . point - The point in the DM 6136 . csize - The number of values in the closure, or NULL 6137 - values - The array of values, which is a borrowed array and should not be freed 6138 6139 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 6140 6141 Fortran Notes: 6142 Since it returns an array, this routine is only available in Fortran 90, and you must 6143 include petsc.h90 in your code. 6144 6145 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 6146 6147 Level: intermediate 6148 6149 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6150 @*/ 6151 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6152 { 6153 PetscInt size = 0; 6154 6155 PetscFunctionBegin; 6156 /* Should work without recalculating size */ 6157 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6158 *values = NULL; 6159 PetscFunctionReturn(0); 6160 } 6161 6162 static inline void add(PetscScalar *x, PetscScalar y) 6163 { 6164 *x += y; 6165 } 6166 static inline void insert(PetscScalar *x, PetscScalar y) 6167 { 6168 *x = y; 6169 } 6170 6171 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[]) 6172 { 6173 PetscInt cdof; /* The number of constraints on this point */ 6174 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6175 PetscScalar *a; 6176 PetscInt off, cind = 0, k; 6177 6178 PetscFunctionBegin; 6179 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6180 PetscCall(PetscSectionGetOffset(section, point, &off)); 6181 a = &array[off]; 6182 if (!cdof || setBC) { 6183 if (clperm) { 6184 if (perm) { 6185 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6186 } else { 6187 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6188 } 6189 } else { 6190 if (perm) { 6191 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6192 } else { 6193 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6194 } 6195 } 6196 } else { 6197 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6198 if (clperm) { 6199 if (perm) { 6200 for (k = 0; k < dof; ++k) { 6201 if ((cind < cdof) && (k == cdofs[cind])) { 6202 ++cind; 6203 continue; 6204 } 6205 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6206 } 6207 } else { 6208 for (k = 0; k < dof; ++k) { 6209 if ((cind < cdof) && (k == cdofs[cind])) { 6210 ++cind; 6211 continue; 6212 } 6213 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6214 } 6215 } 6216 } else { 6217 if (perm) { 6218 for (k = 0; k < dof; ++k) { 6219 if ((cind < cdof) && (k == cdofs[cind])) { 6220 ++cind; 6221 continue; 6222 } 6223 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6224 } 6225 } else { 6226 for (k = 0; k < dof; ++k) { 6227 if ((cind < cdof) && (k == cdofs[cind])) { 6228 ++cind; 6229 continue; 6230 } 6231 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6232 } 6233 } 6234 } 6235 } 6236 PetscFunctionReturn(0); 6237 } 6238 6239 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[]) 6240 { 6241 PetscInt cdof; /* The number of constraints on this point */ 6242 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6243 PetscScalar *a; 6244 PetscInt off, cind = 0, k; 6245 6246 PetscFunctionBegin; 6247 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6248 PetscCall(PetscSectionGetOffset(section, point, &off)); 6249 a = &array[off]; 6250 if (cdof) { 6251 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6252 if (clperm) { 6253 if (perm) { 6254 for (k = 0; k < dof; ++k) { 6255 if ((cind < cdof) && (k == cdofs[cind])) { 6256 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6257 cind++; 6258 } 6259 } 6260 } else { 6261 for (k = 0; k < dof; ++k) { 6262 if ((cind < cdof) && (k == cdofs[cind])) { 6263 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6264 cind++; 6265 } 6266 } 6267 } 6268 } else { 6269 if (perm) { 6270 for (k = 0; k < dof; ++k) { 6271 if ((cind < cdof) && (k == cdofs[cind])) { 6272 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6273 cind++; 6274 } 6275 } 6276 } else { 6277 for (k = 0; k < dof; ++k) { 6278 if ((cind < cdof) && (k == cdofs[cind])) { 6279 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6280 cind++; 6281 } 6282 } 6283 } 6284 } 6285 } 6286 PetscFunctionReturn(0); 6287 } 6288 6289 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[]) 6290 { 6291 PetscScalar *a; 6292 PetscInt fdof, foff, fcdof, foffset = *offset; 6293 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6294 PetscInt cind = 0, b; 6295 6296 PetscFunctionBegin; 6297 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6298 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6299 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6300 a = &array[foff]; 6301 if (!fcdof || setBC) { 6302 if (clperm) { 6303 if (perm) { 6304 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6305 } else { 6306 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6307 } 6308 } else { 6309 if (perm) { 6310 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6311 } else { 6312 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6313 } 6314 } 6315 } else { 6316 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6317 if (clperm) { 6318 if (perm) { 6319 for (b = 0; b < fdof; b++) { 6320 if ((cind < fcdof) && (b == fcdofs[cind])) { 6321 ++cind; 6322 continue; 6323 } 6324 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6325 } 6326 } else { 6327 for (b = 0; b < fdof; b++) { 6328 if ((cind < fcdof) && (b == fcdofs[cind])) { 6329 ++cind; 6330 continue; 6331 } 6332 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6333 } 6334 } 6335 } else { 6336 if (perm) { 6337 for (b = 0; b < fdof; b++) { 6338 if ((cind < fcdof) && (b == fcdofs[cind])) { 6339 ++cind; 6340 continue; 6341 } 6342 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6343 } 6344 } else { 6345 for (b = 0; b < fdof; b++) { 6346 if ((cind < fcdof) && (b == fcdofs[cind])) { 6347 ++cind; 6348 continue; 6349 } 6350 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6351 } 6352 } 6353 } 6354 } 6355 *offset += fdof; 6356 PetscFunctionReturn(0); 6357 } 6358 6359 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[]) 6360 { 6361 PetscScalar *a; 6362 PetscInt fdof, foff, fcdof, foffset = *offset; 6363 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6364 PetscInt Nc, cind = 0, ncind = 0, b; 6365 PetscBool ncSet, fcSet; 6366 6367 PetscFunctionBegin; 6368 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6369 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6370 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6371 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6372 a = &array[foff]; 6373 if (fcdof) { 6374 /* We just override fcdof and fcdofs with Ncc and comps */ 6375 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6376 if (clperm) { 6377 if (perm) { 6378 if (comps) { 6379 for (b = 0; b < fdof; b++) { 6380 ncSet = fcSet = PETSC_FALSE; 6381 if (b % Nc == comps[ncind]) { 6382 ncind = (ncind + 1) % Ncc; 6383 ncSet = PETSC_TRUE; 6384 } 6385 if ((cind < fcdof) && (b == fcdofs[cind])) { 6386 ++cind; 6387 fcSet = PETSC_TRUE; 6388 } 6389 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6390 } 6391 } else { 6392 for (b = 0; b < fdof; b++) { 6393 if ((cind < fcdof) && (b == fcdofs[cind])) { 6394 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6395 ++cind; 6396 } 6397 } 6398 } 6399 } else { 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 + b]] * (flip ? flip[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 + b]] * (flip ? flip[b] : 1.)); 6417 ++cind; 6418 } 6419 } 6420 } 6421 } 6422 } else { 6423 if (perm) { 6424 if (comps) { 6425 for (b = 0; b < fdof; b++) { 6426 ncSet = fcSet = PETSC_FALSE; 6427 if (b % Nc == comps[ncind]) { 6428 ncind = (ncind + 1) % Ncc; 6429 ncSet = PETSC_TRUE; 6430 } 6431 if ((cind < fcdof) && (b == fcdofs[cind])) { 6432 ++cind; 6433 fcSet = PETSC_TRUE; 6434 } 6435 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6436 } 6437 } else { 6438 for (b = 0; b < fdof; b++) { 6439 if ((cind < fcdof) && (b == fcdofs[cind])) { 6440 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6441 ++cind; 6442 } 6443 } 6444 } 6445 } else { 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 + b] * (flip ? flip[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 + b] * (flip ? flip[b] : 1.)); 6463 ++cind; 6464 } 6465 } 6466 } 6467 } 6468 } 6469 } 6470 *offset += fdof; 6471 PetscFunctionReturn(0); 6472 } 6473 6474 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6475 { 6476 PetscScalar *array; 6477 const PetscInt *cone, *coneO; 6478 PetscInt pStart, pEnd, p, numPoints, off, dof; 6479 6480 PetscFunctionBeginHot; 6481 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6482 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6483 PetscCall(DMPlexGetCone(dm, point, &cone)); 6484 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6485 PetscCall(VecGetArray(v, &array)); 6486 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6487 const PetscInt cp = !p ? point : cone[p - 1]; 6488 const PetscInt o = !p ? 0 : coneO[p - 1]; 6489 6490 if ((cp < pStart) || (cp >= pEnd)) { 6491 dof = 0; 6492 continue; 6493 } 6494 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6495 /* ADD_VALUES */ 6496 { 6497 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6498 PetscScalar *a; 6499 PetscInt cdof, coff, cind = 0, k; 6500 6501 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6502 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6503 a = &array[coff]; 6504 if (!cdof) { 6505 if (o >= 0) { 6506 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6507 } else { 6508 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6509 } 6510 } else { 6511 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6512 if (o >= 0) { 6513 for (k = 0; k < dof; ++k) { 6514 if ((cind < cdof) && (k == cdofs[cind])) { 6515 ++cind; 6516 continue; 6517 } 6518 a[k] += values[off + k]; 6519 } 6520 } else { 6521 for (k = 0; k < dof; ++k) { 6522 if ((cind < cdof) && (k == cdofs[cind])) { 6523 ++cind; 6524 continue; 6525 } 6526 a[k] += values[off + dof - k - 1]; 6527 } 6528 } 6529 } 6530 } 6531 } 6532 PetscCall(VecRestoreArray(v, &array)); 6533 PetscFunctionReturn(0); 6534 } 6535 6536 /*@C 6537 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6538 6539 Not collective 6540 6541 Input Parameters: 6542 + dm - The DM 6543 . section - The section describing the layout in v, or NULL to use the default section 6544 . v - The local vector 6545 . point - The point in the DM 6546 . values - The array of values 6547 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6548 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6549 6550 Fortran Notes: 6551 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6552 6553 Level: intermediate 6554 6555 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6556 @*/ 6557 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6558 { 6559 PetscSection clSection; 6560 IS clPoints; 6561 PetscScalar *array; 6562 PetscInt *points = NULL; 6563 const PetscInt *clp, *clperm = NULL; 6564 PetscInt depth, numFields, numPoints, p, clsize; 6565 6566 PetscFunctionBeginHot; 6567 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6568 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6569 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6570 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6571 PetscCall(DMPlexGetDepth(dm, &depth)); 6572 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6573 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6574 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6575 PetscFunctionReturn(0); 6576 } 6577 /* Get points */ 6578 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6579 for (clsize = 0, p = 0; p < numPoints; p++) { 6580 PetscInt dof; 6581 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6582 clsize += dof; 6583 } 6584 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6585 /* Get array */ 6586 PetscCall(VecGetArray(v, &array)); 6587 /* Get values */ 6588 if (numFields > 0) { 6589 PetscInt offset = 0, f; 6590 for (f = 0; f < numFields; ++f) { 6591 const PetscInt **perms = NULL; 6592 const PetscScalar **flips = NULL; 6593 6594 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6595 switch (mode) { 6596 case INSERT_VALUES: 6597 for (p = 0; p < numPoints; p++) { 6598 const PetscInt point = points[2 * p]; 6599 const PetscInt *perm = perms ? perms[p] : NULL; 6600 const PetscScalar *flip = flips ? flips[p] : NULL; 6601 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6602 } 6603 break; 6604 case INSERT_ALL_VALUES: 6605 for (p = 0; p < numPoints; p++) { 6606 const PetscInt point = points[2 * p]; 6607 const PetscInt *perm = perms ? perms[p] : NULL; 6608 const PetscScalar *flip = flips ? flips[p] : NULL; 6609 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6610 } 6611 break; 6612 case INSERT_BC_VALUES: 6613 for (p = 0; p < numPoints; p++) { 6614 const PetscInt point = points[2 * p]; 6615 const PetscInt *perm = perms ? perms[p] : NULL; 6616 const PetscScalar *flip = flips ? flips[p] : NULL; 6617 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6618 } 6619 break; 6620 case ADD_VALUES: 6621 for (p = 0; p < numPoints; p++) { 6622 const PetscInt point = points[2 * p]; 6623 const PetscInt *perm = perms ? perms[p] : NULL; 6624 const PetscScalar *flip = flips ? flips[p] : NULL; 6625 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6626 } 6627 break; 6628 case ADD_ALL_VALUES: 6629 for (p = 0; p < numPoints; p++) { 6630 const PetscInt point = points[2 * p]; 6631 const PetscInt *perm = perms ? perms[p] : NULL; 6632 const PetscScalar *flip = flips ? flips[p] : NULL; 6633 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6634 } 6635 break; 6636 case ADD_BC_VALUES: 6637 for (p = 0; p < numPoints; p++) { 6638 const PetscInt point = points[2 * p]; 6639 const PetscInt *perm = perms ? perms[p] : NULL; 6640 const PetscScalar *flip = flips ? flips[p] : NULL; 6641 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6642 } 6643 break; 6644 default: 6645 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6646 } 6647 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6648 } 6649 } else { 6650 PetscInt dof, off; 6651 const PetscInt **perms = NULL; 6652 const PetscScalar **flips = NULL; 6653 6654 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6655 switch (mode) { 6656 case INSERT_VALUES: 6657 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6658 const PetscInt point = points[2 * p]; 6659 const PetscInt *perm = perms ? perms[p] : NULL; 6660 const PetscScalar *flip = flips ? flips[p] : NULL; 6661 PetscCall(PetscSectionGetDof(section, point, &dof)); 6662 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6663 } 6664 break; 6665 case INSERT_ALL_VALUES: 6666 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6667 const PetscInt point = points[2 * p]; 6668 const PetscInt *perm = perms ? perms[p] : NULL; 6669 const PetscScalar *flip = flips ? flips[p] : NULL; 6670 PetscCall(PetscSectionGetDof(section, point, &dof)); 6671 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6672 } 6673 break; 6674 case INSERT_BC_VALUES: 6675 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6676 const PetscInt point = points[2 * p]; 6677 const PetscInt *perm = perms ? perms[p] : NULL; 6678 const PetscScalar *flip = flips ? flips[p] : NULL; 6679 PetscCall(PetscSectionGetDof(section, point, &dof)); 6680 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6681 } 6682 break; 6683 case ADD_VALUES: 6684 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6685 const PetscInt point = points[2 * p]; 6686 const PetscInt *perm = perms ? perms[p] : NULL; 6687 const PetscScalar *flip = flips ? flips[p] : NULL; 6688 PetscCall(PetscSectionGetDof(section, point, &dof)); 6689 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6690 } 6691 break; 6692 case ADD_ALL_VALUES: 6693 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6694 const PetscInt point = points[2 * p]; 6695 const PetscInt *perm = perms ? perms[p] : NULL; 6696 const PetscScalar *flip = flips ? flips[p] : NULL; 6697 PetscCall(PetscSectionGetDof(section, point, &dof)); 6698 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6699 } 6700 break; 6701 case ADD_BC_VALUES: 6702 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6703 const PetscInt point = points[2 * p]; 6704 const PetscInt *perm = perms ? perms[p] : NULL; 6705 const PetscScalar *flip = flips ? flips[p] : NULL; 6706 PetscCall(PetscSectionGetDof(section, point, &dof)); 6707 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6708 } 6709 break; 6710 default: 6711 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6712 } 6713 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6714 } 6715 /* Cleanup points */ 6716 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6717 /* Cleanup array */ 6718 PetscCall(VecRestoreArray(v, &array)); 6719 PetscFunctionReturn(0); 6720 } 6721 6722 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6723 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6724 { 6725 PetscFunctionBegin; 6726 *contains = PETSC_TRUE; 6727 if (label) { 6728 PetscInt fdof; 6729 6730 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6731 if (!*contains) { 6732 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6733 *offset += fdof; 6734 PetscFunctionReturn(0); 6735 } 6736 } 6737 PetscFunctionReturn(0); 6738 } 6739 6740 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6741 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) 6742 { 6743 PetscSection clSection; 6744 IS clPoints; 6745 PetscScalar *array; 6746 PetscInt *points = NULL; 6747 const PetscInt *clp; 6748 PetscInt numFields, numPoints, p; 6749 PetscInt offset = 0, f; 6750 6751 PetscFunctionBeginHot; 6752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6753 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6754 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6755 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6756 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6757 /* Get points */ 6758 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6759 /* Get array */ 6760 PetscCall(VecGetArray(v, &array)); 6761 /* Get values */ 6762 for (f = 0; f < numFields; ++f) { 6763 const PetscInt **perms = NULL; 6764 const PetscScalar **flips = NULL; 6765 PetscBool contains; 6766 6767 if (!fieldActive[f]) { 6768 for (p = 0; p < numPoints * 2; p += 2) { 6769 PetscInt fdof; 6770 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6771 offset += fdof; 6772 } 6773 continue; 6774 } 6775 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6776 switch (mode) { 6777 case INSERT_VALUES: 6778 for (p = 0; p < numPoints; p++) { 6779 const PetscInt point = points[2 * p]; 6780 const PetscInt *perm = perms ? perms[p] : NULL; 6781 const PetscScalar *flip = flips ? flips[p] : NULL; 6782 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6783 if (!contains) continue; 6784 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6785 } 6786 break; 6787 case INSERT_ALL_VALUES: 6788 for (p = 0; p < numPoints; p++) { 6789 const PetscInt point = points[2 * p]; 6790 const PetscInt *perm = perms ? perms[p] : NULL; 6791 const PetscScalar *flip = flips ? flips[p] : NULL; 6792 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6793 if (!contains) continue; 6794 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6795 } 6796 break; 6797 case INSERT_BC_VALUES: 6798 for (p = 0; p < numPoints; p++) { 6799 const PetscInt point = points[2 * p]; 6800 const PetscInt *perm = perms ? perms[p] : NULL; 6801 const PetscScalar *flip = flips ? flips[p] : NULL; 6802 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6803 if (!contains) continue; 6804 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6805 } 6806 break; 6807 case ADD_VALUES: 6808 for (p = 0; p < numPoints; p++) { 6809 const PetscInt point = points[2 * p]; 6810 const PetscInt *perm = perms ? perms[p] : NULL; 6811 const PetscScalar *flip = flips ? flips[p] : NULL; 6812 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6813 if (!contains) continue; 6814 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6815 } 6816 break; 6817 case ADD_ALL_VALUES: 6818 for (p = 0; p < numPoints; p++) { 6819 const PetscInt point = points[2 * p]; 6820 const PetscInt *perm = perms ? perms[p] : NULL; 6821 const PetscScalar *flip = flips ? flips[p] : NULL; 6822 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6823 if (!contains) continue; 6824 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6825 } 6826 break; 6827 default: 6828 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6829 } 6830 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6831 } 6832 /* Cleanup points */ 6833 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6834 /* Cleanup array */ 6835 PetscCall(VecRestoreArray(v, &array)); 6836 PetscFunctionReturn(0); 6837 } 6838 6839 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6840 { 6841 PetscMPIInt rank; 6842 PetscInt i, j; 6843 6844 PetscFunctionBegin; 6845 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6846 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6847 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6848 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6849 numCIndices = numCIndices ? numCIndices : numRIndices; 6850 if (!values) PetscFunctionReturn(0); 6851 for (i = 0; i < numRIndices; i++) { 6852 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6853 for (j = 0; j < numCIndices; j++) { 6854 #if defined(PETSC_USE_COMPLEX) 6855 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6856 #else 6857 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6858 #endif 6859 } 6860 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6861 } 6862 PetscFunctionReturn(0); 6863 } 6864 6865 /* 6866 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6867 6868 Input Parameters: 6869 + section - The section for this data layout 6870 . islocal - Is the section (and thus indices being requested) local or global? 6871 . point - The point contributing dofs with these indices 6872 . off - The global offset of this point 6873 . loff - The local offset of each field 6874 . setBC - The flag determining whether to include indices of boundary values 6875 . perm - A permutation of the dofs on this point, or NULL 6876 - indperm - A permutation of the entire indices array, or NULL 6877 6878 Output Parameter: 6879 . indices - Indices for dofs on this point 6880 6881 Level: developer 6882 6883 Note: The indices could be local or global, depending on the value of 'off'. 6884 */ 6885 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6886 { 6887 PetscInt dof; /* The number of unknowns on this point */ 6888 PetscInt cdof; /* The number of constraints on this point */ 6889 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6890 PetscInt cind = 0, k; 6891 6892 PetscFunctionBegin; 6893 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6894 PetscCall(PetscSectionGetDof(section, point, &dof)); 6895 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6896 if (!cdof || setBC) { 6897 for (k = 0; k < dof; ++k) { 6898 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6899 const PetscInt ind = indperm ? indperm[preind] : preind; 6900 6901 indices[ind] = off + k; 6902 } 6903 } else { 6904 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6905 for (k = 0; k < dof; ++k) { 6906 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6907 const PetscInt ind = indperm ? indperm[preind] : preind; 6908 6909 if ((cind < cdof) && (k == cdofs[cind])) { 6910 /* Insert check for returning constrained indices */ 6911 indices[ind] = -(off + k + 1); 6912 ++cind; 6913 } else { 6914 indices[ind] = off + k - (islocal ? 0 : cind); 6915 } 6916 } 6917 } 6918 *loff += dof; 6919 PetscFunctionReturn(0); 6920 } 6921 6922 /* 6923 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6924 6925 Input Parameters: 6926 + section - a section (global or local) 6927 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6928 . point - point within section 6929 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6930 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6931 . setBC - identify constrained (boundary condition) points via involution. 6932 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6933 . permsoff - offset 6934 - indperm - index permutation 6935 6936 Output Parameter: 6937 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6938 . indices - array to hold indices (as defined by section) of each dof associated with point 6939 6940 Notes: 6941 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6942 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6943 in the local vector. 6944 6945 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6946 significant). It is invalid to call with a global section and setBC=true. 6947 6948 Developer Note: 6949 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6950 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6951 offset could be obtained from the section instead of passing it explicitly as we do now. 6952 6953 Example: 6954 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6955 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6956 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6957 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. 6958 6959 Level: developer 6960 */ 6961 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[]) 6962 { 6963 PetscInt numFields, foff, f; 6964 6965 PetscFunctionBegin; 6966 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6967 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6968 for (f = 0, foff = 0; f < numFields; ++f) { 6969 PetscInt fdof, cfdof; 6970 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6971 PetscInt cind = 0, b; 6972 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6973 6974 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6975 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6976 if (!cfdof || setBC) { 6977 for (b = 0; b < fdof; ++b) { 6978 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6979 const PetscInt ind = indperm ? indperm[preind] : preind; 6980 6981 indices[ind] = off + foff + b; 6982 } 6983 } else { 6984 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6985 for (b = 0; b < fdof; ++b) { 6986 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6987 const PetscInt ind = indperm ? indperm[preind] : preind; 6988 6989 if ((cind < cfdof) && (b == fcdofs[cind])) { 6990 indices[ind] = -(off + foff + b + 1); 6991 ++cind; 6992 } else { 6993 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6994 } 6995 } 6996 } 6997 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6998 foffs[f] += fdof; 6999 } 7000 PetscFunctionReturn(0); 7001 } 7002 7003 /* 7004 This version believes the globalSection offsets for each field, rather than just the point offset 7005 7006 . foffs - The offset into 'indices' for each field, since it is segregated by field 7007 7008 Notes: 7009 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7010 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7011 */ 7012 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7013 { 7014 PetscInt numFields, foff, f; 7015 7016 PetscFunctionBegin; 7017 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7018 for (f = 0; f < numFields; ++f) { 7019 PetscInt fdof, cfdof; 7020 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7021 PetscInt cind = 0, b; 7022 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7023 7024 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7025 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7026 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7027 if (!cfdof) { 7028 for (b = 0; b < fdof; ++b) { 7029 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7030 const PetscInt ind = indperm ? indperm[preind] : preind; 7031 7032 indices[ind] = foff + b; 7033 } 7034 } else { 7035 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7036 for (b = 0; b < fdof; ++b) { 7037 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7038 const PetscInt ind = indperm ? indperm[preind] : preind; 7039 7040 if ((cind < cfdof) && (b == fcdofs[cind])) { 7041 indices[ind] = -(foff + b + 1); 7042 ++cind; 7043 } else { 7044 indices[ind] = foff + b - cind; 7045 } 7046 } 7047 } 7048 foffs[f] += fdof; 7049 } 7050 PetscFunctionReturn(0); 7051 } 7052 7053 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) 7054 { 7055 Mat cMat; 7056 PetscSection aSec, cSec; 7057 IS aIS; 7058 PetscInt aStart = -1, aEnd = -1; 7059 const PetscInt *anchors; 7060 PetscInt numFields, f, p, q, newP = 0; 7061 PetscInt newNumPoints = 0, newNumIndices = 0; 7062 PetscInt *newPoints, *indices, *newIndices; 7063 PetscInt maxAnchor, maxDof; 7064 PetscInt newOffsets[32]; 7065 PetscInt *pointMatOffsets[32]; 7066 PetscInt *newPointOffsets[32]; 7067 PetscScalar *pointMat[32]; 7068 PetscScalar *newValues = NULL, *tmpValues; 7069 PetscBool anyConstrained = PETSC_FALSE; 7070 7071 PetscFunctionBegin; 7072 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7073 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7074 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7075 7076 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7077 /* if there are point-to-point constraints */ 7078 if (aSec) { 7079 PetscCall(PetscArrayzero(newOffsets, 32)); 7080 PetscCall(ISGetIndices(aIS, &anchors)); 7081 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7082 /* figure out how many points are going to be in the new element matrix 7083 * (we allow double counting, because it's all just going to be summed 7084 * into the global matrix anyway) */ 7085 for (p = 0; p < 2 * numPoints; p += 2) { 7086 PetscInt b = points[p]; 7087 PetscInt bDof = 0, bSecDof; 7088 7089 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7090 if (!bSecDof) continue; 7091 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7092 if (bDof) { 7093 /* this point is constrained */ 7094 /* it is going to be replaced by its anchors */ 7095 PetscInt bOff, q; 7096 7097 anyConstrained = PETSC_TRUE; 7098 newNumPoints += bDof; 7099 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7100 for (q = 0; q < bDof; q++) { 7101 PetscInt a = anchors[bOff + q]; 7102 PetscInt aDof; 7103 7104 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7105 newNumIndices += aDof; 7106 for (f = 0; f < numFields; ++f) { 7107 PetscInt fDof; 7108 7109 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7110 newOffsets[f + 1] += fDof; 7111 } 7112 } 7113 } else { 7114 /* this point is not constrained */ 7115 newNumPoints++; 7116 newNumIndices += bSecDof; 7117 for (f = 0; f < numFields; ++f) { 7118 PetscInt fDof; 7119 7120 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7121 newOffsets[f + 1] += fDof; 7122 } 7123 } 7124 } 7125 } 7126 if (!anyConstrained) { 7127 if (outNumPoints) *outNumPoints = 0; 7128 if (outNumIndices) *outNumIndices = 0; 7129 if (outPoints) *outPoints = NULL; 7130 if (outValues) *outValues = NULL; 7131 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7132 PetscFunctionReturn(0); 7133 } 7134 7135 if (outNumPoints) *outNumPoints = newNumPoints; 7136 if (outNumIndices) *outNumIndices = newNumIndices; 7137 7138 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7139 7140 if (!outPoints && !outValues) { 7141 if (offsets) { 7142 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7143 } 7144 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7145 PetscFunctionReturn(0); 7146 } 7147 7148 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7149 7150 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7151 7152 /* workspaces */ 7153 if (numFields) { 7154 for (f = 0; f < numFields; f++) { 7155 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7156 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7157 } 7158 } else { 7159 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7160 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7161 } 7162 7163 /* get workspaces for the point-to-point matrices */ 7164 if (numFields) { 7165 PetscInt totalOffset, totalMatOffset; 7166 7167 for (p = 0; p < numPoints; p++) { 7168 PetscInt b = points[2 * p]; 7169 PetscInt bDof = 0, bSecDof; 7170 7171 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7172 if (!bSecDof) { 7173 for (f = 0; f < numFields; f++) { 7174 newPointOffsets[f][p + 1] = 0; 7175 pointMatOffsets[f][p + 1] = 0; 7176 } 7177 continue; 7178 } 7179 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7180 if (bDof) { 7181 for (f = 0; f < numFields; f++) { 7182 PetscInt fDof, q, bOff, allFDof = 0; 7183 7184 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7185 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7186 for (q = 0; q < bDof; q++) { 7187 PetscInt a = anchors[bOff + q]; 7188 PetscInt aFDof; 7189 7190 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7191 allFDof += aFDof; 7192 } 7193 newPointOffsets[f][p + 1] = allFDof; 7194 pointMatOffsets[f][p + 1] = fDof * allFDof; 7195 } 7196 } else { 7197 for (f = 0; f < numFields; f++) { 7198 PetscInt fDof; 7199 7200 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7201 newPointOffsets[f][p + 1] = fDof; 7202 pointMatOffsets[f][p + 1] = 0; 7203 } 7204 } 7205 } 7206 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7207 newPointOffsets[f][0] = totalOffset; 7208 pointMatOffsets[f][0] = totalMatOffset; 7209 for (p = 0; p < numPoints; p++) { 7210 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7211 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7212 } 7213 totalOffset = newPointOffsets[f][numPoints]; 7214 totalMatOffset = pointMatOffsets[f][numPoints]; 7215 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7216 } 7217 } else { 7218 for (p = 0; p < numPoints; p++) { 7219 PetscInt b = points[2 * p]; 7220 PetscInt bDof = 0, bSecDof; 7221 7222 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7223 if (!bSecDof) { 7224 newPointOffsets[0][p + 1] = 0; 7225 pointMatOffsets[0][p + 1] = 0; 7226 continue; 7227 } 7228 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7229 if (bDof) { 7230 PetscInt bOff, q, allDof = 0; 7231 7232 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7233 for (q = 0; q < bDof; q++) { 7234 PetscInt a = anchors[bOff + q], aDof; 7235 7236 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7237 allDof += aDof; 7238 } 7239 newPointOffsets[0][p + 1] = allDof; 7240 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7241 } else { 7242 newPointOffsets[0][p + 1] = bSecDof; 7243 pointMatOffsets[0][p + 1] = 0; 7244 } 7245 } 7246 newPointOffsets[0][0] = 0; 7247 pointMatOffsets[0][0] = 0; 7248 for (p = 0; p < numPoints; p++) { 7249 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7250 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7251 } 7252 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7253 } 7254 7255 /* output arrays */ 7256 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7257 7258 /* get the point-to-point matrices; construct newPoints */ 7259 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7260 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7261 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7262 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7263 if (numFields) { 7264 for (p = 0, newP = 0; p < numPoints; p++) { 7265 PetscInt b = points[2 * p]; 7266 PetscInt o = points[2 * p + 1]; 7267 PetscInt bDof = 0, bSecDof; 7268 7269 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7270 if (!bSecDof) continue; 7271 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7272 if (bDof) { 7273 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7274 7275 fStart[0] = 0; 7276 fEnd[0] = 0; 7277 for (f = 0; f < numFields; f++) { 7278 PetscInt fDof; 7279 7280 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7281 fStart[f + 1] = fStart[f] + fDof; 7282 fEnd[f + 1] = fStart[f + 1]; 7283 } 7284 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7285 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7286 7287 fAnchorStart[0] = 0; 7288 fAnchorEnd[0] = 0; 7289 for (f = 0; f < numFields; f++) { 7290 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7291 7292 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7293 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7294 } 7295 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7296 for (q = 0; q < bDof; q++) { 7297 PetscInt a = anchors[bOff + q], aOff; 7298 7299 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7300 newPoints[2 * (newP + q)] = a; 7301 newPoints[2 * (newP + q) + 1] = 0; 7302 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7303 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7304 } 7305 newP += bDof; 7306 7307 if (outValues) { 7308 /* get the point-to-point submatrix */ 7309 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])); 7310 } 7311 } else { 7312 newPoints[2 * newP] = b; 7313 newPoints[2 * newP + 1] = o; 7314 newP++; 7315 } 7316 } 7317 } else { 7318 for (p = 0; p < numPoints; p++) { 7319 PetscInt b = points[2 * p]; 7320 PetscInt o = points[2 * p + 1]; 7321 PetscInt bDof = 0, bSecDof; 7322 7323 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7324 if (!bSecDof) continue; 7325 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7326 if (bDof) { 7327 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7328 7329 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7330 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7331 7332 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7333 for (q = 0; q < bDof; q++) { 7334 PetscInt a = anchors[bOff + q], aOff; 7335 7336 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7337 7338 newPoints[2 * (newP + q)] = a; 7339 newPoints[2 * (newP + q) + 1] = 0; 7340 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7341 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7342 } 7343 newP += bDof; 7344 7345 /* get the point-to-point submatrix */ 7346 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7347 } else { 7348 newPoints[2 * newP] = b; 7349 newPoints[2 * newP + 1] = o; 7350 newP++; 7351 } 7352 } 7353 } 7354 7355 if (outValues) { 7356 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7357 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7358 /* multiply constraints on the right */ 7359 if (numFields) { 7360 for (f = 0; f < numFields; f++) { 7361 PetscInt oldOff = offsets[f]; 7362 7363 for (p = 0; p < numPoints; p++) { 7364 PetscInt cStart = newPointOffsets[f][p]; 7365 PetscInt b = points[2 * p]; 7366 PetscInt c, r, k; 7367 PetscInt dof; 7368 7369 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7370 if (!dof) continue; 7371 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7372 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7373 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7374 7375 for (r = 0; r < numIndices; r++) { 7376 for (c = 0; c < nCols; c++) { 7377 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7378 } 7379 } 7380 } else { 7381 /* copy this column as is */ 7382 for (r = 0; r < numIndices; r++) { 7383 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7384 } 7385 } 7386 oldOff += dof; 7387 } 7388 } 7389 } else { 7390 PetscInt oldOff = 0; 7391 for (p = 0; p < numPoints; p++) { 7392 PetscInt cStart = newPointOffsets[0][p]; 7393 PetscInt b = points[2 * p]; 7394 PetscInt c, r, k; 7395 PetscInt dof; 7396 7397 PetscCall(PetscSectionGetDof(section, b, &dof)); 7398 if (!dof) continue; 7399 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7400 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7401 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7402 7403 for (r = 0; r < numIndices; r++) { 7404 for (c = 0; c < nCols; c++) { 7405 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7406 } 7407 } 7408 } else { 7409 /* copy this column as is */ 7410 for (r = 0; r < numIndices; r++) { 7411 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7412 } 7413 } 7414 oldOff += dof; 7415 } 7416 } 7417 7418 if (multiplyLeft) { 7419 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7420 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7421 /* multiply constraints transpose on the left */ 7422 if (numFields) { 7423 for (f = 0; f < numFields; f++) { 7424 PetscInt oldOff = offsets[f]; 7425 7426 for (p = 0; p < numPoints; p++) { 7427 PetscInt rStart = newPointOffsets[f][p]; 7428 PetscInt b = points[2 * p]; 7429 PetscInt c, r, k; 7430 PetscInt dof; 7431 7432 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7433 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7434 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7435 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7436 7437 for (r = 0; r < nRows; r++) { 7438 for (c = 0; c < newNumIndices; c++) { 7439 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7440 } 7441 } 7442 } else { 7443 /* copy this row as is */ 7444 for (r = 0; r < dof; r++) { 7445 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7446 } 7447 } 7448 oldOff += dof; 7449 } 7450 } 7451 } else { 7452 PetscInt oldOff = 0; 7453 7454 for (p = 0; p < numPoints; p++) { 7455 PetscInt rStart = newPointOffsets[0][p]; 7456 PetscInt b = points[2 * p]; 7457 PetscInt c, r, k; 7458 PetscInt dof; 7459 7460 PetscCall(PetscSectionGetDof(section, b, &dof)); 7461 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7462 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7463 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7464 7465 for (r = 0; r < nRows; r++) { 7466 for (c = 0; c < newNumIndices; c++) { 7467 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7468 } 7469 } 7470 } else { 7471 /* copy this row as is */ 7472 for (r = 0; r < dof; r++) { 7473 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7474 } 7475 } 7476 oldOff += dof; 7477 } 7478 } 7479 7480 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7481 } else { 7482 newValues = tmpValues; 7483 } 7484 } 7485 7486 /* clean up */ 7487 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7488 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7489 7490 if (numFields) { 7491 for (f = 0; f < numFields; f++) { 7492 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7493 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7494 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7495 } 7496 } else { 7497 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7498 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7499 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7500 } 7501 PetscCall(ISRestoreIndices(aIS, &anchors)); 7502 7503 /* output */ 7504 if (outPoints) { 7505 *outPoints = newPoints; 7506 } else { 7507 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7508 } 7509 if (outValues) *outValues = newValues; 7510 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7511 PetscFunctionReturn(0); 7512 } 7513 7514 /*@C 7515 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7516 7517 Not collective 7518 7519 Input Parameters: 7520 + dm - The DM 7521 . section - The PetscSection describing the points (a local section) 7522 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7523 . point - The point defining the closure 7524 - useClPerm - Use the closure point permutation if available 7525 7526 Output Parameters: 7527 + numIndices - The number of dof indices in the closure of point with the input sections 7528 . indices - The dof indices 7529 . outOffsets - Array to write the field offsets into, or NULL 7530 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7531 7532 Notes: 7533 Must call DMPlexRestoreClosureIndices() to free allocated memory 7534 7535 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7536 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7537 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7538 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7539 indices (with the above semantics) are implied. 7540 7541 Level: advanced 7542 7543 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7544 @*/ 7545 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7546 { 7547 /* Closure ordering */ 7548 PetscSection clSection; 7549 IS clPoints; 7550 const PetscInt *clp; 7551 PetscInt *points; 7552 const PetscInt *clperm = NULL; 7553 /* Dof permutation and sign flips */ 7554 const PetscInt **perms[32] = {NULL}; 7555 const PetscScalar **flips[32] = {NULL}; 7556 PetscScalar *valCopy = NULL; 7557 /* Hanging node constraints */ 7558 PetscInt *pointsC = NULL; 7559 PetscScalar *valuesC = NULL; 7560 PetscInt NclC, NiC; 7561 7562 PetscInt *idx; 7563 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7564 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7565 7566 PetscFunctionBeginHot; 7567 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7568 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7569 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7570 if (numIndices) PetscValidIntPointer(numIndices, 6); 7571 if (indices) PetscValidPointer(indices, 7); 7572 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7573 if (values) PetscValidPointer(values, 9); 7574 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7575 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7576 PetscCall(PetscArrayzero(offsets, 32)); 7577 /* 1) Get points in closure */ 7578 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7579 if (useClPerm) { 7580 PetscInt depth, clsize; 7581 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7582 for (clsize = 0, p = 0; p < Ncl; p++) { 7583 PetscInt dof; 7584 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7585 clsize += dof; 7586 } 7587 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7588 } 7589 /* 2) Get number of indices on these points and field offsets from section */ 7590 for (p = 0; p < Ncl * 2; p += 2) { 7591 PetscInt dof, fdof; 7592 7593 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7594 for (f = 0; f < Nf; ++f) { 7595 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7596 offsets[f + 1] += fdof; 7597 } 7598 Ni += dof; 7599 } 7600 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7601 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7602 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7603 for (f = 0; f < PetscMax(1, Nf); ++f) { 7604 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7605 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7606 /* may need to apply sign changes to the element matrix */ 7607 if (values && flips[f]) { 7608 PetscInt foffset = offsets[f]; 7609 7610 for (p = 0; p < Ncl; ++p) { 7611 PetscInt pnt = points[2 * p], fdof; 7612 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7613 7614 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7615 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7616 if (flip) { 7617 PetscInt i, j, k; 7618 7619 if (!valCopy) { 7620 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7621 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7622 *values = valCopy; 7623 } 7624 for (i = 0; i < fdof; ++i) { 7625 PetscScalar fval = flip[i]; 7626 7627 for (k = 0; k < Ni; ++k) { 7628 valCopy[Ni * (foffset + i) + k] *= fval; 7629 valCopy[Ni * k + (foffset + i)] *= fval; 7630 } 7631 } 7632 } 7633 foffset += fdof; 7634 } 7635 } 7636 } 7637 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7638 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7639 if (NclC) { 7640 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7641 for (f = 0; f < PetscMax(1, Nf); ++f) { 7642 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7643 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7644 } 7645 for (f = 0; f < PetscMax(1, Nf); ++f) { 7646 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7647 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7648 } 7649 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7650 Ncl = NclC; 7651 Ni = NiC; 7652 points = pointsC; 7653 if (values) *values = valuesC; 7654 } 7655 /* 5) Calculate indices */ 7656 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7657 if (Nf) { 7658 PetscInt idxOff; 7659 PetscBool useFieldOffsets; 7660 7661 if (outOffsets) { 7662 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7663 } 7664 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7665 if (useFieldOffsets) { 7666 for (p = 0; p < Ncl; ++p) { 7667 const PetscInt pnt = points[p * 2]; 7668 7669 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7670 } 7671 } else { 7672 for (p = 0; p < Ncl; ++p) { 7673 const PetscInt pnt = points[p * 2]; 7674 7675 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7676 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7677 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7678 * global section. */ 7679 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7680 } 7681 } 7682 } else { 7683 PetscInt off = 0, idxOff; 7684 7685 for (p = 0; p < Ncl; ++p) { 7686 const PetscInt pnt = points[p * 2]; 7687 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7688 7689 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7690 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7691 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7692 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7693 } 7694 } 7695 /* 6) Cleanup */ 7696 for (f = 0; f < PetscMax(1, Nf); ++f) { 7697 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7698 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7699 } 7700 if (NclC) { 7701 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7702 } else { 7703 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7704 } 7705 7706 if (numIndices) *numIndices = Ni; 7707 if (indices) *indices = idx; 7708 PetscFunctionReturn(0); 7709 } 7710 7711 /*@C 7712 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7713 7714 Not collective 7715 7716 Input Parameters: 7717 + dm - The DM 7718 . section - The PetscSection describing the points (a local section) 7719 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7720 . point - The point defining the closure 7721 - useClPerm - Use the closure point permutation if available 7722 7723 Output Parameters: 7724 + numIndices - The number of dof indices in the closure of point with the input sections 7725 . indices - The dof indices 7726 . outOffsets - Array to write the field offsets into, or NULL 7727 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7728 7729 Notes: 7730 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7731 7732 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7733 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7734 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7735 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7736 indices (with the above semantics) are implied. 7737 7738 Level: advanced 7739 7740 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7741 @*/ 7742 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7743 { 7744 PetscFunctionBegin; 7745 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7746 PetscValidPointer(indices, 7); 7747 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7748 PetscFunctionReturn(0); 7749 } 7750 7751 /*@C 7752 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7753 7754 Not collective 7755 7756 Input Parameters: 7757 + dm - The DM 7758 . section - The section describing the layout in v, or NULL to use the default section 7759 . globalSection - The section describing the layout in v, or NULL to use the default global section 7760 . A - The matrix 7761 . point - The point in the DM 7762 . values - The array of values 7763 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7764 7765 Fortran Notes: 7766 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7767 7768 Level: intermediate 7769 7770 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7771 @*/ 7772 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7773 { 7774 DM_Plex *mesh = (DM_Plex *)dm->data; 7775 PetscInt *indices; 7776 PetscInt numIndices; 7777 const PetscScalar *valuesOrig = values; 7778 PetscErrorCode ierr; 7779 7780 PetscFunctionBegin; 7781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7782 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7783 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7784 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7785 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7786 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7787 7788 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7789 7790 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7791 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7792 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7793 if (ierr) { 7794 PetscMPIInt rank; 7795 7796 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7797 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7798 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7799 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7800 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7801 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7802 } 7803 if (mesh->printFEM > 1) { 7804 PetscInt i; 7805 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7806 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7807 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7808 } 7809 7810 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7811 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7812 PetscFunctionReturn(0); 7813 } 7814 7815 /*@C 7816 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7817 7818 Not collective 7819 7820 Input Parameters: 7821 + dmRow - The DM for the row fields 7822 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7823 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7824 . dmCol - The DM for the column fields 7825 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7826 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7827 . A - The matrix 7828 . point - The point in the DMs 7829 . values - The array of values 7830 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7831 7832 Level: intermediate 7833 7834 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7835 @*/ 7836 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7837 { 7838 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7839 PetscInt *indicesRow, *indicesCol; 7840 PetscInt numIndicesRow, numIndicesCol; 7841 const PetscScalar *valuesOrig = values; 7842 PetscErrorCode ierr; 7843 7844 PetscFunctionBegin; 7845 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7846 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7847 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7848 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7849 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7850 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7851 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7852 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7853 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7854 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7855 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7856 7857 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7858 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7859 7860 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7861 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7862 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7863 if (ierr) { 7864 PetscMPIInt rank; 7865 7866 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7867 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7868 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7869 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7870 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7871 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7872 } 7873 7874 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7875 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7876 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7877 PetscFunctionReturn(0); 7878 } 7879 7880 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7881 { 7882 DM_Plex *mesh = (DM_Plex *)dmf->data; 7883 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7884 PetscInt *cpoints = NULL; 7885 PetscInt *findices, *cindices; 7886 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7887 PetscInt foffsets[32], coffsets[32]; 7888 DMPolytopeType ct; 7889 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7890 PetscErrorCode ierr; 7891 7892 PetscFunctionBegin; 7893 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7894 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7895 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7896 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7897 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7898 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7899 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7900 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7901 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7902 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7903 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7904 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7905 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7906 PetscCall(PetscArrayzero(foffsets, 32)); 7907 PetscCall(PetscArrayzero(coffsets, 32)); 7908 /* Column indices */ 7909 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7910 maxFPoints = numCPoints; 7911 /* Compress out points not in the section */ 7912 /* TODO: Squeeze out points with 0 dof as well */ 7913 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7914 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7915 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7916 cpoints[q * 2] = cpoints[p]; 7917 cpoints[q * 2 + 1] = cpoints[p + 1]; 7918 ++q; 7919 } 7920 } 7921 numCPoints = q; 7922 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7923 PetscInt fdof; 7924 7925 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7926 if (!dof) continue; 7927 for (f = 0; f < numFields; ++f) { 7928 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7929 coffsets[f + 1] += fdof; 7930 } 7931 numCIndices += dof; 7932 } 7933 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7934 /* Row indices */ 7935 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7936 { 7937 DMPlexTransform tr; 7938 DMPolytopeType *rct; 7939 PetscInt *rsize, *rcone, *rornt, Nt; 7940 7941 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7942 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7943 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7944 numSubcells = rsize[Nt - 1]; 7945 PetscCall(DMPlexTransformDestroy(&tr)); 7946 } 7947 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7948 for (r = 0, q = 0; r < numSubcells; ++r) { 7949 /* TODO Map from coarse to fine cells */ 7950 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7951 /* Compress out points not in the section */ 7952 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7953 for (p = 0; p < numFPoints * 2; p += 2) { 7954 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7955 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7956 if (!dof) continue; 7957 for (s = 0; s < q; ++s) 7958 if (fpoints[p] == ftotpoints[s * 2]) break; 7959 if (s < q) continue; 7960 ftotpoints[q * 2] = fpoints[p]; 7961 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7962 ++q; 7963 } 7964 } 7965 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7966 } 7967 numFPoints = q; 7968 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7969 PetscInt fdof; 7970 7971 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7972 if (!dof) continue; 7973 for (f = 0; f < numFields; ++f) { 7974 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7975 foffsets[f + 1] += fdof; 7976 } 7977 numFIndices += dof; 7978 } 7979 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7980 7981 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7982 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7983 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7984 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7985 if (numFields) { 7986 const PetscInt **permsF[32] = {NULL}; 7987 const PetscInt **permsC[32] = {NULL}; 7988 7989 for (f = 0; f < numFields; f++) { 7990 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7991 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7992 } 7993 for (p = 0; p < numFPoints; p++) { 7994 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7995 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7996 } 7997 for (p = 0; p < numCPoints; p++) { 7998 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7999 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8000 } 8001 for (f = 0; f < numFields; f++) { 8002 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8003 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8004 } 8005 } else { 8006 const PetscInt **permsF = NULL; 8007 const PetscInt **permsC = NULL; 8008 8009 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8010 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8011 for (p = 0, off = 0; p < numFPoints; p++) { 8012 const PetscInt *perm = permsF ? permsF[p] : NULL; 8013 8014 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8015 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8016 } 8017 for (p = 0, off = 0; p < numCPoints; p++) { 8018 const PetscInt *perm = permsC ? permsC[p] : NULL; 8019 8020 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8021 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8022 } 8023 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8024 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8025 } 8026 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8027 /* TODO: flips */ 8028 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8029 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8030 if (ierr) { 8031 PetscMPIInt rank; 8032 8033 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8034 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8035 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8036 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8037 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8038 } 8039 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8040 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8041 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8042 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8043 PetscFunctionReturn(0); 8044 } 8045 8046 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8047 { 8048 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8049 PetscInt *cpoints = NULL; 8050 PetscInt foffsets[32], coffsets[32]; 8051 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8052 DMPolytopeType ct; 8053 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8054 8055 PetscFunctionBegin; 8056 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8057 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8058 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8059 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8060 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8061 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8062 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8063 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8064 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8065 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8066 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8067 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8068 PetscCall(PetscArrayzero(foffsets, 32)); 8069 PetscCall(PetscArrayzero(coffsets, 32)); 8070 /* Column indices */ 8071 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8072 maxFPoints = numCPoints; 8073 /* Compress out points not in the section */ 8074 /* TODO: Squeeze out points with 0 dof as well */ 8075 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8076 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8077 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8078 cpoints[q * 2] = cpoints[p]; 8079 cpoints[q * 2 + 1] = cpoints[p + 1]; 8080 ++q; 8081 } 8082 } 8083 numCPoints = q; 8084 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8085 PetscInt fdof; 8086 8087 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8088 if (!dof) continue; 8089 for (f = 0; f < numFields; ++f) { 8090 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8091 coffsets[f + 1] += fdof; 8092 } 8093 numCIndices += dof; 8094 } 8095 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8096 /* Row indices */ 8097 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8098 { 8099 DMPlexTransform tr; 8100 DMPolytopeType *rct; 8101 PetscInt *rsize, *rcone, *rornt, Nt; 8102 8103 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8104 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8105 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8106 numSubcells = rsize[Nt - 1]; 8107 PetscCall(DMPlexTransformDestroy(&tr)); 8108 } 8109 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8110 for (r = 0, q = 0; r < numSubcells; ++r) { 8111 /* TODO Map from coarse to fine cells */ 8112 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8113 /* Compress out points not in the section */ 8114 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8115 for (p = 0; p < numFPoints * 2; p += 2) { 8116 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8117 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8118 if (!dof) continue; 8119 for (s = 0; s < q; ++s) 8120 if (fpoints[p] == ftotpoints[s * 2]) break; 8121 if (s < q) continue; 8122 ftotpoints[q * 2] = fpoints[p]; 8123 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8124 ++q; 8125 } 8126 } 8127 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8128 } 8129 numFPoints = q; 8130 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8131 PetscInt fdof; 8132 8133 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8134 if (!dof) continue; 8135 for (f = 0; f < numFields; ++f) { 8136 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8137 foffsets[f + 1] += fdof; 8138 } 8139 numFIndices += dof; 8140 } 8141 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8142 8143 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8144 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8145 if (numFields) { 8146 const PetscInt **permsF[32] = {NULL}; 8147 const PetscInt **permsC[32] = {NULL}; 8148 8149 for (f = 0; f < numFields; f++) { 8150 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8151 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8152 } 8153 for (p = 0; p < numFPoints; p++) { 8154 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8155 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8156 } 8157 for (p = 0; p < numCPoints; p++) { 8158 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8159 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8160 } 8161 for (f = 0; f < numFields; f++) { 8162 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8163 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8164 } 8165 } else { 8166 const PetscInt **permsF = NULL; 8167 const PetscInt **permsC = NULL; 8168 8169 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8170 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8171 for (p = 0, off = 0; p < numFPoints; p++) { 8172 const PetscInt *perm = permsF ? permsF[p] : NULL; 8173 8174 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8175 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8176 } 8177 for (p = 0, off = 0; p < numCPoints; p++) { 8178 const PetscInt *perm = permsC ? permsC[p] : NULL; 8179 8180 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8181 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8182 } 8183 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8184 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8185 } 8186 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8187 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8188 PetscFunctionReturn(0); 8189 } 8190 8191 /*@C 8192 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8193 8194 Input Parameter: 8195 . dm - The DMPlex object 8196 8197 Output Parameter: 8198 . cellHeight - The height of a cell 8199 8200 Level: developer 8201 8202 .seealso `DMPlexSetVTKCellHeight()` 8203 @*/ 8204 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8205 { 8206 DM_Plex *mesh = (DM_Plex *)dm->data; 8207 8208 PetscFunctionBegin; 8209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8210 PetscValidIntPointer(cellHeight, 2); 8211 *cellHeight = mesh->vtkCellHeight; 8212 PetscFunctionReturn(0); 8213 } 8214 8215 /*@C 8216 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8217 8218 Input Parameters: 8219 + dm - The DMPlex object 8220 - cellHeight - The height of a cell 8221 8222 Level: developer 8223 8224 .seealso `DMPlexGetVTKCellHeight()` 8225 @*/ 8226 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8227 { 8228 DM_Plex *mesh = (DM_Plex *)dm->data; 8229 8230 PetscFunctionBegin; 8231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8232 mesh->vtkCellHeight = cellHeight; 8233 PetscFunctionReturn(0); 8234 } 8235 8236 /*@ 8237 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8238 8239 Input Parameter: 8240 . dm - The DMPlex object 8241 8242 Output Parameters: 8243 + gcStart - The first ghost cell, or NULL 8244 - gcEnd - The upper bound on ghost cells, or NULL 8245 8246 Level: advanced 8247 8248 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8249 @*/ 8250 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8251 { 8252 DMLabel ctLabel; 8253 8254 PetscFunctionBegin; 8255 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8256 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8257 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8258 // Reset label for fast lookup 8259 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8260 PetscFunctionReturn(0); 8261 } 8262 8263 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8264 { 8265 PetscSection section, globalSection; 8266 PetscInt *numbers, p; 8267 8268 PetscFunctionBegin; 8269 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8270 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8271 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8272 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8273 PetscCall(PetscSectionSetUp(section)); 8274 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8275 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8276 for (p = pStart; p < pEnd; ++p) { 8277 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8278 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8279 else numbers[p - pStart] += shift; 8280 } 8281 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8282 if (globalSize) { 8283 PetscLayout layout; 8284 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8285 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8286 PetscCall(PetscLayoutDestroy(&layout)); 8287 } 8288 PetscCall(PetscSectionDestroy(§ion)); 8289 PetscCall(PetscSectionDestroy(&globalSection)); 8290 PetscFunctionReturn(0); 8291 } 8292 8293 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8294 { 8295 PetscInt cellHeight, cStart, cEnd; 8296 8297 PetscFunctionBegin; 8298 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8299 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8300 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8301 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8302 PetscFunctionReturn(0); 8303 } 8304 8305 /*@ 8306 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8307 8308 Input Parameter: 8309 . dm - The DMPlex object 8310 8311 Output Parameter: 8312 . globalCellNumbers - Global cell numbers for all cells on this process 8313 8314 Level: developer 8315 8316 .seealso `DMPlexGetVertexNumbering()` 8317 @*/ 8318 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8319 { 8320 DM_Plex *mesh = (DM_Plex *)dm->data; 8321 8322 PetscFunctionBegin; 8323 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8324 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8325 *globalCellNumbers = mesh->globalCellNumbers; 8326 PetscFunctionReturn(0); 8327 } 8328 8329 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8330 { 8331 PetscInt vStart, vEnd; 8332 8333 PetscFunctionBegin; 8334 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8335 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8336 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8337 PetscFunctionReturn(0); 8338 } 8339 8340 /*@ 8341 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8342 8343 Input Parameter: 8344 . dm - The DMPlex object 8345 8346 Output Parameter: 8347 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8348 8349 Level: developer 8350 8351 .seealso `DMPlexGetCellNumbering()` 8352 @*/ 8353 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8354 { 8355 DM_Plex *mesh = (DM_Plex *)dm->data; 8356 8357 PetscFunctionBegin; 8358 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8359 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8360 *globalVertexNumbers = mesh->globalVertexNumbers; 8361 PetscFunctionReturn(0); 8362 } 8363 8364 /*@ 8365 DMPlexCreatePointNumbering - Create a global numbering for all points. 8366 8367 Collective on dm 8368 8369 Input Parameter: 8370 . dm - The DMPlex object 8371 8372 Output Parameter: 8373 . globalPointNumbers - Global numbers for all points on this process 8374 8375 Notes: 8376 8377 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8378 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8379 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8380 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8381 8382 The partitioned mesh is 8383 ``` 8384 (2)--0--(3)--1--(4) (1)--0--(2) 8385 ``` 8386 and its global numbering is 8387 ``` 8388 (3)--0--(4)--1--(5)--2--(6) 8389 ``` 8390 Then the global numbering is provided as 8391 ``` 8392 [0] Number of indices in set 5 8393 [0] 0 0 8394 [0] 1 1 8395 [0] 2 3 8396 [0] 3 4 8397 [0] 4 -6 8398 [1] Number of indices in set 3 8399 [1] 0 2 8400 [1] 1 5 8401 [1] 2 6 8402 ``` 8403 8404 Level: developer 8405 8406 .seealso `DMPlexGetCellNumbering()` 8407 @*/ 8408 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8409 { 8410 IS nums[4]; 8411 PetscInt depths[4], gdepths[4], starts[4]; 8412 PetscInt depth, d, shift = 0; 8413 PetscBool empty = PETSC_FALSE; 8414 8415 PetscFunctionBegin; 8416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8417 PetscCall(DMPlexGetDepth(dm, &depth)); 8418 // For unstratified meshes use dim instead of depth 8419 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8420 // If any stratum is empty, we must mark all empty 8421 for (d = 0; d <= depth; ++d) { 8422 PetscInt end; 8423 8424 depths[d] = depth - d; 8425 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8426 if (!(starts[d] - end)) empty = PETSC_TRUE; 8427 } 8428 if (empty) 8429 for (d = 0; d <= depth; ++d) { 8430 depths[d] = -1; 8431 starts[d] = -1; 8432 } 8433 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8434 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8435 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]); 8436 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8437 for (d = 0; d <= depth; ++d) { 8438 PetscInt pStart, pEnd, gsize; 8439 8440 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8441 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8442 shift += gsize; 8443 } 8444 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8445 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8446 PetscFunctionReturn(0); 8447 } 8448 8449 /*@ 8450 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8451 8452 Input Parameter: 8453 . dm - The DMPlex object 8454 8455 Output Parameter: 8456 . ranks - The rank field 8457 8458 Options Database Keys: 8459 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8460 8461 Level: intermediate 8462 8463 .seealso: `DMView()` 8464 @*/ 8465 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8466 { 8467 DM rdm; 8468 PetscFE fe; 8469 PetscScalar *r; 8470 PetscMPIInt rank; 8471 DMPolytopeType ct; 8472 PetscInt dim, cStart, cEnd, c; 8473 PetscBool simplex; 8474 8475 PetscFunctionBeginUser; 8476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8477 PetscValidPointer(ranks, 2); 8478 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8479 PetscCall(DMClone(dm, &rdm)); 8480 PetscCall(DMGetDimension(rdm, &dim)); 8481 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8482 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8483 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8484 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8485 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8486 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8487 PetscCall(PetscFEDestroy(&fe)); 8488 PetscCall(DMCreateDS(rdm)); 8489 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8490 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8491 PetscCall(VecGetArray(*ranks, &r)); 8492 for (c = cStart; c < cEnd; ++c) { 8493 PetscScalar *lr; 8494 8495 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8496 if (lr) *lr = rank; 8497 } 8498 PetscCall(VecRestoreArray(*ranks, &r)); 8499 PetscCall(DMDestroy(&rdm)); 8500 PetscFunctionReturn(0); 8501 } 8502 8503 /*@ 8504 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8505 8506 Input Parameters: 8507 + dm - The DMPlex 8508 - label - The DMLabel 8509 8510 Output Parameter: 8511 . val - The label value field 8512 8513 Options Database Keys: 8514 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8515 8516 Level: intermediate 8517 8518 .seealso: `DMView()` 8519 @*/ 8520 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8521 { 8522 DM rdm; 8523 PetscFE fe; 8524 PetscScalar *v; 8525 PetscInt dim, cStart, cEnd, c; 8526 8527 PetscFunctionBeginUser; 8528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8529 PetscValidPointer(label, 2); 8530 PetscValidPointer(val, 3); 8531 PetscCall(DMClone(dm, &rdm)); 8532 PetscCall(DMGetDimension(rdm, &dim)); 8533 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8534 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8535 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8536 PetscCall(PetscFEDestroy(&fe)); 8537 PetscCall(DMCreateDS(rdm)); 8538 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8539 PetscCall(DMCreateGlobalVector(rdm, val)); 8540 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8541 PetscCall(VecGetArray(*val, &v)); 8542 for (c = cStart; c < cEnd; ++c) { 8543 PetscScalar *lv; 8544 PetscInt cval; 8545 8546 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8547 PetscCall(DMLabelGetValue(label, c, &cval)); 8548 *lv = cval; 8549 } 8550 PetscCall(VecRestoreArray(*val, &v)); 8551 PetscCall(DMDestroy(&rdm)); 8552 PetscFunctionReturn(0); 8553 } 8554 8555 /*@ 8556 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8557 8558 Input Parameter: 8559 . dm - The DMPlex object 8560 8561 Notes: 8562 This is a useful diagnostic when creating meshes programmatically. 8563 8564 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8565 8566 Level: developer 8567 8568 .seealso: `DMCreate()`, `DMSetFromOptions()` 8569 @*/ 8570 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8571 { 8572 PetscSection coneSection, supportSection; 8573 const PetscInt *cone, *support; 8574 PetscInt coneSize, c, supportSize, s; 8575 PetscInt pStart, pEnd, p, pp, csize, ssize; 8576 PetscBool storagecheck = PETSC_TRUE; 8577 8578 PetscFunctionBegin; 8579 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8580 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8581 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8582 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8583 /* Check that point p is found in the support of its cone points, and vice versa */ 8584 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8585 for (p = pStart; p < pEnd; ++p) { 8586 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8587 PetscCall(DMPlexGetCone(dm, p, &cone)); 8588 for (c = 0; c < coneSize; ++c) { 8589 PetscBool dup = PETSC_FALSE; 8590 PetscInt d; 8591 for (d = c - 1; d >= 0; --d) { 8592 if (cone[c] == cone[d]) { 8593 dup = PETSC_TRUE; 8594 break; 8595 } 8596 } 8597 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8598 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8599 for (s = 0; s < supportSize; ++s) { 8600 if (support[s] == p) break; 8601 } 8602 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8603 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8604 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8605 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8606 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8607 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8608 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8609 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]); 8610 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8611 } 8612 } 8613 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8614 if (p != pp) { 8615 storagecheck = PETSC_FALSE; 8616 continue; 8617 } 8618 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8619 PetscCall(DMPlexGetSupport(dm, p, &support)); 8620 for (s = 0; s < supportSize; ++s) { 8621 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8622 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8623 for (c = 0; c < coneSize; ++c) { 8624 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8625 if (cone[c] != pp) { 8626 c = 0; 8627 break; 8628 } 8629 if (cone[c] == p) break; 8630 } 8631 if (c >= coneSize) { 8632 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8633 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8634 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8635 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8636 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8637 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8638 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8639 } 8640 } 8641 } 8642 if (storagecheck) { 8643 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8644 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8645 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8646 } 8647 PetscFunctionReturn(0); 8648 } 8649 8650 /* 8651 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. 8652 */ 8653 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8654 { 8655 DMPolytopeType cct; 8656 PetscInt ptpoints[4]; 8657 const PetscInt *cone, *ccone, *ptcone; 8658 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8659 8660 PetscFunctionBegin; 8661 *unsplit = 0; 8662 switch (ct) { 8663 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8664 ptpoints[npt++] = c; 8665 break; 8666 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8667 PetscCall(DMPlexGetCone(dm, c, &cone)); 8668 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8669 for (cp = 0; cp < coneSize; ++cp) { 8670 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8671 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8672 } 8673 break; 8674 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8675 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8676 PetscCall(DMPlexGetCone(dm, c, &cone)); 8677 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8678 for (cp = 0; cp < coneSize; ++cp) { 8679 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8680 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8681 for (ccp = 0; ccp < cconeSize; ++ccp) { 8682 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8683 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8684 PetscInt p; 8685 for (p = 0; p < npt; ++p) 8686 if (ptpoints[p] == ccone[ccp]) break; 8687 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8688 } 8689 } 8690 } 8691 break; 8692 default: 8693 break; 8694 } 8695 for (pt = 0; pt < npt; ++pt) { 8696 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8697 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8698 } 8699 PetscFunctionReturn(0); 8700 } 8701 8702 /*@ 8703 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8704 8705 Input Parameters: 8706 + dm - The DMPlex object 8707 - cellHeight - Normally 0 8708 8709 Notes: 8710 This is a useful diagnostic when creating meshes programmatically. 8711 Currently applicable only to homogeneous simplex or tensor meshes. 8712 8713 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8714 8715 Level: developer 8716 8717 .seealso: `DMCreate()`, `DMSetFromOptions()` 8718 @*/ 8719 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8720 { 8721 DMPlexInterpolatedFlag interp; 8722 DMPolytopeType ct; 8723 PetscInt vStart, vEnd, cStart, cEnd, c; 8724 8725 PetscFunctionBegin; 8726 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8727 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8728 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8729 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8730 for (c = cStart; c < cEnd; ++c) { 8731 PetscInt *closure = NULL; 8732 PetscInt coneSize, closureSize, cl, Nv = 0; 8733 8734 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8735 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8736 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8737 if (interp == DMPLEX_INTERPOLATED_FULL) { 8738 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8739 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)); 8740 } 8741 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8742 for (cl = 0; cl < closureSize * 2; cl += 2) { 8743 const PetscInt p = closure[cl]; 8744 if ((p >= vStart) && (p < vEnd)) ++Nv; 8745 } 8746 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8747 /* Special Case: Tensor faces with identified vertices */ 8748 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8749 PetscInt unsplit; 8750 8751 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8752 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8753 } 8754 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)); 8755 } 8756 PetscFunctionReturn(0); 8757 } 8758 8759 /*@ 8760 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8761 8762 Collective 8763 8764 Input Parameters: 8765 + dm - The DMPlex object 8766 - cellHeight - Normally 0 8767 8768 Notes: 8769 This is a useful diagnostic when creating meshes programmatically. 8770 This routine is only relevant for meshes that are fully interpolated across all ranks. 8771 It will error out if a partially interpolated mesh is given on some rank. 8772 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8773 8774 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8775 8776 Level: developer 8777 8778 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8779 @*/ 8780 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8781 { 8782 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8783 DMPlexInterpolatedFlag interpEnum; 8784 8785 PetscFunctionBegin; 8786 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8787 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8788 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8789 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8790 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8791 PetscFunctionReturn(0); 8792 } 8793 8794 PetscCall(DMGetDimension(dm, &dim)); 8795 PetscCall(DMPlexGetDepth(dm, &depth)); 8796 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8797 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8798 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8799 for (c = cStart; c < cEnd; ++c) { 8800 const PetscInt *cone, *ornt, *faceSizes, *faces; 8801 const DMPolytopeType *faceTypes; 8802 DMPolytopeType ct; 8803 PetscInt numFaces, coneSize, f; 8804 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8805 8806 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8807 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8808 if (unsplit) continue; 8809 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8810 PetscCall(DMPlexGetCone(dm, c, &cone)); 8811 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8812 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8813 for (cl = 0; cl < closureSize * 2; cl += 2) { 8814 const PetscInt p = closure[cl]; 8815 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8816 } 8817 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8818 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); 8819 for (f = 0; f < numFaces; ++f) { 8820 DMPolytopeType fct; 8821 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8822 8823 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8824 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8825 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8826 const PetscInt p = fclosure[cl]; 8827 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8828 } 8829 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]); 8830 for (v = 0; v < fnumCorners; ++v) { 8831 if (fclosure[v] != faces[fOff + v]) { 8832 PetscInt v1; 8833 8834 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8835 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8836 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8837 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8838 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8839 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]); 8840 } 8841 } 8842 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8843 fOff += faceSizes[f]; 8844 } 8845 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8846 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8847 } 8848 } 8849 PetscFunctionReturn(0); 8850 } 8851 8852 /*@ 8853 DMPlexCheckGeometry - Check the geometry of mesh cells 8854 8855 Input Parameter: 8856 . dm - The DMPlex object 8857 8858 Notes: 8859 This is a useful diagnostic when creating meshes programmatically. 8860 8861 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8862 8863 Level: developer 8864 8865 .seealso: `DMCreate()`, `DMSetFromOptions()` 8866 @*/ 8867 PetscErrorCode DMPlexCheckGeometry(DM dm) 8868 { 8869 Vec coordinates; 8870 PetscReal detJ, J[9], refVol = 1.0; 8871 PetscReal vol; 8872 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8873 8874 PetscFunctionBegin; 8875 PetscCall(DMGetDimension(dm, &dim)); 8876 PetscCall(DMGetCoordinateDim(dm, &dE)); 8877 if (dim != dE) PetscFunctionReturn(0); 8878 PetscCall(DMPlexGetDepth(dm, &depth)); 8879 for (d = 0; d < dim; ++d) refVol *= 2.0; 8880 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8881 /* Make sure local coordinates are created, because that step is collective */ 8882 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8883 if (!coordinates) PetscFunctionReturn(0); 8884 for (c = cStart; c < cEnd; ++c) { 8885 DMPolytopeType ct; 8886 PetscInt unsplit; 8887 PetscBool ignoreZeroVol = PETSC_FALSE; 8888 8889 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8890 switch (ct) { 8891 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8892 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8893 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8894 ignoreZeroVol = PETSC_TRUE; 8895 break; 8896 default: 8897 break; 8898 } 8899 switch (ct) { 8900 case DM_POLYTOPE_TRI_PRISM: 8901 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8902 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8903 case DM_POLYTOPE_PYRAMID: 8904 continue; 8905 default: 8906 break; 8907 } 8908 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8909 if (unsplit) continue; 8910 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8911 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); 8912 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8913 /* This should work with periodicity since DG coordinates should be used */ 8914 if (depth > 1) { 8915 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8916 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); 8917 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8918 } 8919 } 8920 PetscFunctionReturn(0); 8921 } 8922 8923 /*@ 8924 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8925 8926 Collective 8927 8928 Input Parameters: 8929 + dm - The DMPlex object 8930 . pointSF - The Point SF, or NULL for Point SF attached to DM 8931 - allowExtraRoots - Flag to allow extra points not present in the DM 8932 8933 Notes: 8934 This is mainly intended for debugging/testing purposes. 8935 8936 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8937 8938 Extra roots can come from priodic cuts, where additional points appear on the boundary 8939 8940 Level: developer 8941 8942 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8943 @*/ 8944 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 8945 { 8946 PetscInt l, nleaves, nroots, overlap; 8947 const PetscInt *locals; 8948 const PetscSFNode *remotes; 8949 PetscBool distributed; 8950 MPI_Comm comm; 8951 PetscMPIInt rank; 8952 8953 PetscFunctionBegin; 8954 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8955 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8956 else pointSF = dm->sf; 8957 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8958 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8959 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8960 { 8961 PetscMPIInt mpiFlag; 8962 8963 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8964 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8965 } 8966 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8967 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8968 if (!distributed) { 8969 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); 8970 PetscFunctionReturn(0); 8971 } 8972 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); 8973 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8974 8975 /* Check SF graph is compatible with DMPlex chart */ 8976 { 8977 PetscInt pStart, pEnd, maxLeaf; 8978 8979 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8980 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8981 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8982 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8983 } 8984 8985 /* Check Point SF has no local points referenced */ 8986 for (l = 0; l < nleaves; l++) { 8987 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); 8988 } 8989 8990 /* Check there are no cells in interface */ 8991 if (!overlap) { 8992 PetscInt cellHeight, cStart, cEnd; 8993 8994 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8995 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8996 for (l = 0; l < nleaves; ++l) { 8997 const PetscInt point = locals ? locals[l] : l; 8998 8999 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9000 } 9001 } 9002 9003 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9004 { 9005 const PetscInt *rootdegree; 9006 9007 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9008 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9009 for (l = 0; l < nleaves; ++l) { 9010 const PetscInt point = locals ? locals[l] : l; 9011 const PetscInt *cone; 9012 PetscInt coneSize, c, idx; 9013 9014 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9015 PetscCall(DMPlexGetCone(dm, point, &cone)); 9016 for (c = 0; c < coneSize; ++c) { 9017 if (!rootdegree[cone[c]]) { 9018 if (locals) { 9019 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9020 } else { 9021 idx = (cone[c] < nleaves) ? cone[c] : -1; 9022 } 9023 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9024 } 9025 } 9026 } 9027 } 9028 PetscFunctionReturn(0); 9029 } 9030 9031 /*@ 9032 DMPlexCheck - Perform various checks of Plex sanity 9033 9034 Input Parameter: 9035 . dm - The DMPlex object 9036 9037 Notes: 9038 This is a useful diagnostic when creating meshes programmatically. 9039 9040 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 9041 9042 Currently does not include DMPlexCheckCellShape(). 9043 9044 Level: developer 9045 9046 .seealso: DMCreate(), DMSetFromOptions() 9047 @*/ 9048 PetscErrorCode DMPlexCheck(DM dm) 9049 { 9050 PetscInt cellHeight; 9051 9052 PetscFunctionBegin; 9053 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9054 PetscCall(DMPlexCheckSymmetry(dm)); 9055 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9056 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9057 PetscCall(DMPlexCheckGeometry(dm)); 9058 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9059 PetscCall(DMPlexCheckInterfaceCones(dm)); 9060 PetscFunctionReturn(0); 9061 } 9062 9063 typedef struct cell_stats { 9064 PetscReal min, max, sum, squaresum; 9065 PetscInt count; 9066 } cell_stats_t; 9067 9068 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9069 { 9070 PetscInt i, N = *len; 9071 9072 for (i = 0; i < N; i++) { 9073 cell_stats_t *A = (cell_stats_t *)a; 9074 cell_stats_t *B = (cell_stats_t *)b; 9075 9076 B->min = PetscMin(A->min, B->min); 9077 B->max = PetscMax(A->max, B->max); 9078 B->sum += A->sum; 9079 B->squaresum += A->squaresum; 9080 B->count += A->count; 9081 } 9082 } 9083 9084 /*@ 9085 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9086 9087 Collective on dm 9088 9089 Input Parameters: 9090 + dm - The DMPlex object 9091 . output - If true, statistics will be displayed on stdout 9092 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 9093 9094 Notes: 9095 This is mainly intended for debugging/testing purposes. 9096 9097 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 9098 9099 Level: developer 9100 9101 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9102 @*/ 9103 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9104 { 9105 DM dmCoarse; 9106 cell_stats_t stats, globalStats; 9107 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9108 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9109 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9110 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9111 PetscMPIInt rank, size; 9112 9113 PetscFunctionBegin; 9114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9115 stats.min = PETSC_MAX_REAL; 9116 stats.max = PETSC_MIN_REAL; 9117 stats.sum = stats.squaresum = 0.; 9118 stats.count = 0; 9119 9120 PetscCallMPI(MPI_Comm_size(comm, &size)); 9121 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9122 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9123 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9124 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9125 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9126 for (c = cStart; c < cEnd; c++) { 9127 PetscInt i; 9128 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9129 9130 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9131 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9132 for (i = 0; i < PetscSqr(cdim); ++i) { 9133 frobJ += J[i] * J[i]; 9134 frobInvJ += invJ[i] * invJ[i]; 9135 } 9136 cond2 = frobJ * frobInvJ; 9137 cond = PetscSqrtReal(cond2); 9138 9139 stats.min = PetscMin(stats.min, cond); 9140 stats.max = PetscMax(stats.max, cond); 9141 stats.sum += cond; 9142 stats.squaresum += cond2; 9143 stats.count++; 9144 if (output && cond > limit) { 9145 PetscSection coordSection; 9146 Vec coordsLocal; 9147 PetscScalar *coords = NULL; 9148 PetscInt Nv, d, clSize, cl, *closure = NULL; 9149 9150 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9151 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9152 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9153 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9154 for (i = 0; i < Nv / cdim; ++i) { 9155 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9156 for (d = 0; d < cdim; ++d) { 9157 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9158 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9159 } 9160 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9161 } 9162 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9163 for (cl = 0; cl < clSize * 2; cl += 2) { 9164 const PetscInt edge = closure[cl]; 9165 9166 if ((edge >= eStart) && (edge < eEnd)) { 9167 PetscReal len; 9168 9169 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9170 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9171 } 9172 } 9173 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9174 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9175 } 9176 } 9177 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9178 9179 if (size > 1) { 9180 PetscMPIInt blockLengths[2] = {4, 1}; 9181 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9182 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9183 MPI_Op statReduce; 9184 9185 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9186 PetscCallMPI(MPI_Type_commit(&statType)); 9187 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9188 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9189 PetscCallMPI(MPI_Op_free(&statReduce)); 9190 PetscCallMPI(MPI_Type_free(&statType)); 9191 } else { 9192 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9193 } 9194 if (rank == 0) { 9195 count = globalStats.count; 9196 min = globalStats.min; 9197 max = globalStats.max; 9198 mean = globalStats.sum / globalStats.count; 9199 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9200 } 9201 9202 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)); 9203 PetscCall(PetscFree2(J, invJ)); 9204 9205 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9206 if (dmCoarse) { 9207 PetscBool isplex; 9208 9209 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9210 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9211 } 9212 PetscFunctionReturn(0); 9213 } 9214 9215 /*@ 9216 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9217 orthogonal quality below given tolerance. 9218 9219 Collective on dm 9220 9221 Input Parameters: 9222 + dm - The DMPlex object 9223 . fv - Optional PetscFV object for pre-computed cell/face centroid information 9224 - atol - [0, 1] Absolute tolerance for tagging cells. 9225 9226 Output Parameters: 9227 + OrthQual - Vec containing orthogonal quality per cell 9228 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 9229 9230 Options Database Keys: 9231 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 9232 supported. 9233 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9234 9235 Notes: 9236 Orthogonal quality is given by the following formula: 9237 9238 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 9239 9240 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 9241 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9242 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9243 calculating the cosine of the angle between these vectors. 9244 9245 Orthogonal quality ranges from 1 (best) to 0 (worst). 9246 9247 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 9248 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9249 9250 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9251 9252 Level: intermediate 9253 9254 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 9255 @*/ 9256 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9257 { 9258 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9259 PetscInt *idx; 9260 PetscScalar *oqVals; 9261 const PetscScalar *cellGeomArr, *faceGeomArr; 9262 PetscReal *ci, *fi, *Ai; 9263 MPI_Comm comm; 9264 Vec cellgeom, facegeom; 9265 DM dmFace, dmCell; 9266 IS glob; 9267 ISLocalToGlobalMapping ltog; 9268 PetscViewer vwr; 9269 9270 PetscFunctionBegin; 9271 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9272 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9273 PetscValidPointer(OrthQual, 4); 9274 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9275 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9276 PetscCall(DMGetDimension(dm, &nc)); 9277 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9278 { 9279 DMPlexInterpolatedFlag interpFlag; 9280 9281 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9282 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9283 PetscMPIInt rank; 9284 9285 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9286 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9287 } 9288 } 9289 if (OrthQualLabel) { 9290 PetscValidPointer(OrthQualLabel, 5); 9291 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9292 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9293 } else { 9294 *OrthQualLabel = NULL; 9295 } 9296 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9297 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9298 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9299 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9300 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9301 PetscCall(VecCreate(comm, OrthQual)); 9302 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9303 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9304 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9305 PetscCall(VecSetUp(*OrthQual)); 9306 PetscCall(ISDestroy(&glob)); 9307 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9308 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9309 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9310 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9311 PetscCall(VecGetDM(cellgeom, &dmCell)); 9312 PetscCall(VecGetDM(facegeom, &dmFace)); 9313 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9314 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9315 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9316 PetscInt cellarr[2], *adj = NULL; 9317 PetscScalar *cArr, *fArr; 9318 PetscReal minvalc = 1.0, minvalf = 1.0; 9319 PetscFVCellGeom *cg; 9320 9321 idx[cellIter] = cell - cStart; 9322 cellarr[0] = cell; 9323 /* Make indexing into cellGeom easier */ 9324 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9325 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9326 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9327 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9328 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9329 PetscInt i; 9330 const PetscInt neigh = adj[cellneigh]; 9331 PetscReal normci = 0, normfi = 0, normai = 0; 9332 PetscFVCellGeom *cgneigh; 9333 PetscFVFaceGeom *fg; 9334 9335 /* Don't count ourselves in the neighbor list */ 9336 if (neigh == cell) continue; 9337 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9338 cellarr[1] = neigh; 9339 { 9340 PetscInt numcovpts; 9341 const PetscInt *covpts; 9342 9343 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9344 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9345 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9346 } 9347 9348 /* Compute c_i, f_i and their norms */ 9349 for (i = 0; i < nc; i++) { 9350 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9351 fi[i] = fg->centroid[i] - cg->centroid[i]; 9352 Ai[i] = fg->normal[i]; 9353 normci += PetscPowReal(ci[i], 2); 9354 normfi += PetscPowReal(fi[i], 2); 9355 normai += PetscPowReal(Ai[i], 2); 9356 } 9357 normci = PetscSqrtReal(normci); 9358 normfi = PetscSqrtReal(normfi); 9359 normai = PetscSqrtReal(normai); 9360 9361 /* Normalize and compute for each face-cell-normal pair */ 9362 for (i = 0; i < nc; i++) { 9363 ci[i] = ci[i] / normci; 9364 fi[i] = fi[i] / normfi; 9365 Ai[i] = Ai[i] / normai; 9366 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9367 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9368 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9369 } 9370 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9371 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9372 } 9373 PetscCall(PetscFree(adj)); 9374 PetscCall(PetscFree2(cArr, fArr)); 9375 /* Defer to cell if they're equal */ 9376 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9377 if (OrthQualLabel) { 9378 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9379 } 9380 } 9381 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9382 PetscCall(VecAssemblyBegin(*OrthQual)); 9383 PetscCall(VecAssemblyEnd(*OrthQual)); 9384 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9385 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9386 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9387 if (OrthQualLabel) { 9388 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9389 } 9390 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9391 PetscCall(PetscViewerDestroy(&vwr)); 9392 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9393 PetscFunctionReturn(0); 9394 } 9395 9396 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9397 * interpolator construction */ 9398 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9399 { 9400 PetscSection section, newSection, gsection; 9401 PetscSF sf; 9402 PetscBool hasConstraints, ghasConstraints; 9403 9404 PetscFunctionBegin; 9405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9406 PetscValidPointer(odm, 2); 9407 PetscCall(DMGetLocalSection(dm, §ion)); 9408 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9409 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9410 if (!ghasConstraints) { 9411 PetscCall(PetscObjectReference((PetscObject)dm)); 9412 *odm = dm; 9413 PetscFunctionReturn(0); 9414 } 9415 PetscCall(DMClone(dm, odm)); 9416 PetscCall(DMCopyFields(dm, *odm)); 9417 PetscCall(DMGetLocalSection(*odm, &newSection)); 9418 PetscCall(DMGetPointSF(*odm, &sf)); 9419 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9420 PetscCall(DMSetGlobalSection(*odm, gsection)); 9421 PetscCall(PetscSectionDestroy(&gsection)); 9422 PetscFunctionReturn(0); 9423 } 9424 9425 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9426 { 9427 DM dmco, dmfo; 9428 Mat interpo; 9429 Vec rscale; 9430 Vec cglobalo, clocal; 9431 Vec fglobal, fglobalo, flocal; 9432 PetscBool regular; 9433 9434 PetscFunctionBegin; 9435 PetscCall(DMGetFullDM(dmc, &dmco)); 9436 PetscCall(DMGetFullDM(dmf, &dmfo)); 9437 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9438 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9439 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9440 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9441 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9442 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9443 PetscCall(VecSet(cglobalo, 0.)); 9444 PetscCall(VecSet(clocal, 0.)); 9445 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9446 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9447 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9448 PetscCall(VecSet(fglobal, 0.)); 9449 PetscCall(VecSet(fglobalo, 0.)); 9450 PetscCall(VecSet(flocal, 0.)); 9451 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9452 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9453 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9454 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9455 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9456 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9457 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9458 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9459 *shift = fglobal; 9460 PetscCall(VecDestroy(&flocal)); 9461 PetscCall(VecDestroy(&fglobalo)); 9462 PetscCall(VecDestroy(&clocal)); 9463 PetscCall(VecDestroy(&cglobalo)); 9464 PetscCall(VecDestroy(&rscale)); 9465 PetscCall(MatDestroy(&interpo)); 9466 PetscCall(DMDestroy(&dmfo)); 9467 PetscCall(DMDestroy(&dmco)); 9468 PetscFunctionReturn(0); 9469 } 9470 9471 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9472 { 9473 PetscObject shifto; 9474 Vec shift; 9475 9476 PetscFunctionBegin; 9477 if (!interp) { 9478 Vec rscale; 9479 9480 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9481 PetscCall(VecDestroy(&rscale)); 9482 } else { 9483 PetscCall(PetscObjectReference((PetscObject)interp)); 9484 } 9485 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9486 if (!shifto) { 9487 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9488 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9489 shifto = (PetscObject)shift; 9490 PetscCall(VecDestroy(&shift)); 9491 } 9492 shift = (Vec)shifto; 9493 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9494 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9495 PetscCall(MatDestroy(&interp)); 9496 PetscFunctionReturn(0); 9497 } 9498 9499 /* Pointwise interpolation 9500 Just code FEM for now 9501 u^f = I u^c 9502 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9503 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9504 I_{ij} = psi^f_i phi^c_j 9505 */ 9506 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9507 { 9508 PetscSection gsc, gsf; 9509 PetscInt m, n; 9510 void *ctx; 9511 DM cdm; 9512 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9513 9514 PetscFunctionBegin; 9515 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9516 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9517 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9518 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9519 9520 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9521 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9522 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9523 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9524 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9525 9526 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9527 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9528 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9529 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9530 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9531 if (scaling) { 9532 /* Use naive scaling */ 9533 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9534 } 9535 PetscFunctionReturn(0); 9536 } 9537 9538 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9539 { 9540 VecScatter ctx; 9541 9542 PetscFunctionBegin; 9543 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9544 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9545 PetscCall(VecScatterDestroy(&ctx)); 9546 PetscFunctionReturn(0); 9547 } 9548 9549 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[]) 9550 { 9551 const PetscInt Nc = uOff[1] - uOff[0]; 9552 PetscInt c; 9553 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9554 } 9555 9556 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9557 { 9558 DM dmc; 9559 PetscDS ds; 9560 Vec ones, locmass; 9561 IS cellIS; 9562 PetscFormKey key; 9563 PetscInt depth; 9564 9565 PetscFunctionBegin; 9566 PetscCall(DMClone(dm, &dmc)); 9567 PetscCall(DMCopyDisc(dm, dmc)); 9568 PetscCall(DMGetDS(dmc, &ds)); 9569 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9570 PetscCall(DMCreateGlobalVector(dmc, mass)); 9571 PetscCall(DMGetLocalVector(dmc, &ones)); 9572 PetscCall(DMGetLocalVector(dmc, &locmass)); 9573 PetscCall(DMPlexGetDepth(dmc, &depth)); 9574 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9575 PetscCall(VecSet(locmass, 0.0)); 9576 PetscCall(VecSet(ones, 1.0)); 9577 key.label = NULL; 9578 key.value = 0; 9579 key.field = 0; 9580 key.part = 0; 9581 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9582 PetscCall(ISDestroy(&cellIS)); 9583 PetscCall(VecSet(*mass, 0.0)); 9584 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9585 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9586 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9587 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9588 PetscCall(DMDestroy(&dmc)); 9589 PetscFunctionReturn(0); 9590 } 9591 9592 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9593 { 9594 PetscSection gsc, gsf; 9595 PetscInt m, n; 9596 void *ctx; 9597 DM cdm; 9598 PetscBool regular; 9599 9600 PetscFunctionBegin; 9601 if (dmFine == dmCoarse) { 9602 DM dmc; 9603 PetscDS ds; 9604 PetscWeakForm wf; 9605 Vec u; 9606 IS cellIS; 9607 PetscFormKey key; 9608 PetscInt depth; 9609 9610 PetscCall(DMClone(dmFine, &dmc)); 9611 PetscCall(DMCopyDisc(dmFine, dmc)); 9612 PetscCall(DMGetDS(dmc, &ds)); 9613 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9614 PetscCall(PetscWeakFormClear(wf)); 9615 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9616 PetscCall(DMCreateMatrix(dmc, mass)); 9617 PetscCall(DMGetLocalVector(dmc, &u)); 9618 PetscCall(DMPlexGetDepth(dmc, &depth)); 9619 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9620 PetscCall(MatZeroEntries(*mass)); 9621 key.label = NULL; 9622 key.value = 0; 9623 key.field = 0; 9624 key.part = 0; 9625 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9626 PetscCall(ISDestroy(&cellIS)); 9627 PetscCall(DMRestoreLocalVector(dmc, &u)); 9628 PetscCall(DMDestroy(&dmc)); 9629 } else { 9630 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9631 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9632 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9633 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9634 9635 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9636 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9637 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9638 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9639 9640 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9641 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9642 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9643 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9644 } 9645 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9646 PetscFunctionReturn(0); 9647 } 9648 9649 /*@ 9650 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9651 9652 Input Parameter: 9653 . dm - The DMPlex object 9654 9655 Output Parameter: 9656 . regular - The flag 9657 9658 Level: intermediate 9659 9660 .seealso: `DMPlexSetRegularRefinement()` 9661 @*/ 9662 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9663 { 9664 PetscFunctionBegin; 9665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9666 PetscValidBoolPointer(regular, 2); 9667 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9668 PetscFunctionReturn(0); 9669 } 9670 9671 /*@ 9672 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9673 9674 Input Parameters: 9675 + dm - The DMPlex object 9676 - regular - The flag 9677 9678 Level: intermediate 9679 9680 .seealso: `DMPlexGetRegularRefinement()` 9681 @*/ 9682 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9683 { 9684 PetscFunctionBegin; 9685 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9686 ((DM_Plex *)dm->data)->regularRefinement = regular; 9687 PetscFunctionReturn(0); 9688 } 9689 9690 /* anchors */ 9691 /*@ 9692 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9693 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9694 9695 not collective 9696 9697 Input Parameter: 9698 . dm - The DMPlex object 9699 9700 Output Parameters: 9701 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9702 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9703 9704 Level: intermediate 9705 9706 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9707 @*/ 9708 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9709 { 9710 DM_Plex *plex = (DM_Plex *)dm->data; 9711 9712 PetscFunctionBegin; 9713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9714 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9715 if (anchorSection) *anchorSection = plex->anchorSection; 9716 if (anchorIS) *anchorIS = plex->anchorIS; 9717 PetscFunctionReturn(0); 9718 } 9719 9720 /*@ 9721 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9722 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9723 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9724 9725 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9726 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9727 9728 collective on dm 9729 9730 Input Parameters: 9731 + dm - The DMPlex object 9732 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. Must have a local communicator (PETSC_COMM_SELF or derivative). 9733 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9734 9735 The reference counts of anchorSection and anchorIS are incremented. 9736 9737 Level: intermediate 9738 9739 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9740 @*/ 9741 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9742 { 9743 DM_Plex *plex = (DM_Plex *)dm->data; 9744 PetscMPIInt result; 9745 9746 PetscFunctionBegin; 9747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9748 if (anchorSection) { 9749 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9750 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9751 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9752 } 9753 if (anchorIS) { 9754 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9755 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9756 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9757 } 9758 9759 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9760 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9761 plex->anchorSection = anchorSection; 9762 9763 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9764 PetscCall(ISDestroy(&plex->anchorIS)); 9765 plex->anchorIS = anchorIS; 9766 9767 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9768 PetscInt size, a, pStart, pEnd; 9769 const PetscInt *anchors; 9770 9771 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9772 PetscCall(ISGetLocalSize(anchorIS, &size)); 9773 PetscCall(ISGetIndices(anchorIS, &anchors)); 9774 for (a = 0; a < size; a++) { 9775 PetscInt p; 9776 9777 p = anchors[a]; 9778 if (p >= pStart && p < pEnd) { 9779 PetscInt dof; 9780 9781 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9782 if (dof) { 9783 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9784 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9785 } 9786 } 9787 } 9788 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9789 } 9790 /* reset the generic constraints */ 9791 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9792 PetscFunctionReturn(0); 9793 } 9794 9795 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9796 { 9797 PetscSection anchorSection; 9798 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9799 9800 PetscFunctionBegin; 9801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9802 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9803 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9804 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9805 if (numFields) { 9806 PetscInt f; 9807 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9808 9809 for (f = 0; f < numFields; f++) { 9810 PetscInt numComp; 9811 9812 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9813 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9814 } 9815 } 9816 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9817 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9818 pStart = PetscMax(pStart, sStart); 9819 pEnd = PetscMin(pEnd, sEnd); 9820 pEnd = PetscMax(pStart, pEnd); 9821 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9822 for (p = pStart; p < pEnd; p++) { 9823 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9824 if (dof) { 9825 PetscCall(PetscSectionGetDof(section, p, &dof)); 9826 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9827 for (f = 0; f < numFields; f++) { 9828 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9829 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9830 } 9831 } 9832 } 9833 PetscCall(PetscSectionSetUp(*cSec)); 9834 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9835 PetscFunctionReturn(0); 9836 } 9837 9838 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9839 { 9840 PetscSection aSec; 9841 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9842 const PetscInt *anchors; 9843 PetscInt numFields, f; 9844 IS aIS; 9845 MatType mtype; 9846 PetscBool iscuda, iskokkos; 9847 9848 PetscFunctionBegin; 9849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9850 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9851 PetscCall(PetscSectionGetStorageSize(section, &n)); 9852 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9853 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9854 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9855 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9856 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9857 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9858 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9859 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9860 else mtype = MATSEQAIJ; 9861 PetscCall(MatSetType(*cMat, mtype)); 9862 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9863 PetscCall(ISGetIndices(aIS, &anchors)); 9864 /* cSec will be a subset of aSec and section */ 9865 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9866 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9867 PetscCall(PetscMalloc1(m + 1, &i)); 9868 i[0] = 0; 9869 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9870 for (p = pStart; p < pEnd; p++) { 9871 PetscInt rDof, rOff, r; 9872 9873 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9874 if (!rDof) continue; 9875 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9876 if (numFields) { 9877 for (f = 0; f < numFields; f++) { 9878 annz = 0; 9879 for (r = 0; r < rDof; r++) { 9880 a = anchors[rOff + r]; 9881 if (a < sStart || a >= sEnd) continue; 9882 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9883 annz += aDof; 9884 } 9885 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9886 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9887 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9888 } 9889 } else { 9890 annz = 0; 9891 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9892 for (q = 0; q < dof; q++) { 9893 a = anchors[rOff + q]; 9894 if (a < sStart || a >= sEnd) continue; 9895 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9896 annz += aDof; 9897 } 9898 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9899 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9900 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9901 } 9902 } 9903 nnz = i[m]; 9904 PetscCall(PetscMalloc1(nnz, &j)); 9905 offset = 0; 9906 for (p = pStart; p < pEnd; p++) { 9907 if (numFields) { 9908 for (f = 0; f < numFields; f++) { 9909 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9910 for (q = 0; q < dof; q++) { 9911 PetscInt rDof, rOff, r; 9912 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9913 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9914 for (r = 0; r < rDof; r++) { 9915 PetscInt s; 9916 9917 a = anchors[rOff + r]; 9918 if (a < sStart || a >= sEnd) continue; 9919 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9920 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9921 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9922 } 9923 } 9924 } 9925 } else { 9926 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9927 for (q = 0; q < dof; q++) { 9928 PetscInt rDof, rOff, r; 9929 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9930 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9931 for (r = 0; r < rDof; r++) { 9932 PetscInt s; 9933 9934 a = anchors[rOff + r]; 9935 if (a < sStart || a >= sEnd) continue; 9936 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9937 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9938 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9939 } 9940 } 9941 } 9942 } 9943 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9944 PetscCall(PetscFree(i)); 9945 PetscCall(PetscFree(j)); 9946 PetscCall(ISRestoreIndices(aIS, &anchors)); 9947 PetscFunctionReturn(0); 9948 } 9949 9950 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9951 { 9952 DM_Plex *plex = (DM_Plex *)dm->data; 9953 PetscSection anchorSection, section, cSec; 9954 Mat cMat; 9955 9956 PetscFunctionBegin; 9957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9958 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9959 if (anchorSection) { 9960 PetscInt Nf; 9961 9962 PetscCall(DMGetLocalSection(dm, §ion)); 9963 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9964 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9965 PetscCall(DMGetNumFields(dm, &Nf)); 9966 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9967 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9968 PetscCall(PetscSectionDestroy(&cSec)); 9969 PetscCall(MatDestroy(&cMat)); 9970 } 9971 PetscFunctionReturn(0); 9972 } 9973 9974 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9975 { 9976 IS subis; 9977 PetscSection section, subsection; 9978 9979 PetscFunctionBegin; 9980 PetscCall(DMGetLocalSection(dm, §ion)); 9981 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9982 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9983 /* Create subdomain */ 9984 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9985 /* Create submodel */ 9986 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9987 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9988 PetscCall(DMSetLocalSection(*subdm, subsection)); 9989 PetscCall(PetscSectionDestroy(&subsection)); 9990 PetscCall(DMCopyDisc(dm, *subdm)); 9991 /* Create map from submodel to global model */ 9992 if (is) { 9993 PetscSection sectionGlobal, subsectionGlobal; 9994 IS spIS; 9995 const PetscInt *spmap; 9996 PetscInt *subIndices; 9997 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9998 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9999 10000 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10001 PetscCall(ISGetIndices(spIS, &spmap)); 10002 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10003 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10004 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10005 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10006 for (p = pStart; p < pEnd; ++p) { 10007 PetscInt gdof, pSubSize = 0; 10008 10009 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10010 if (gdof > 0) { 10011 for (f = 0; f < Nf; ++f) { 10012 PetscInt fdof, fcdof; 10013 10014 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10015 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10016 pSubSize += fdof - fcdof; 10017 } 10018 subSize += pSubSize; 10019 if (pSubSize) { 10020 if (bs < 0) { 10021 bs = pSubSize; 10022 } else if (bs != pSubSize) { 10023 /* Layout does not admit a pointwise block size */ 10024 bs = 1; 10025 } 10026 } 10027 } 10028 } 10029 /* Must have same blocksize on all procs (some might have no points) */ 10030 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10031 bsLocal[1] = bs; 10032 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10033 if (bsMinMax[0] != bsMinMax[1]) { 10034 bs = 1; 10035 } else { 10036 bs = bsMinMax[0]; 10037 } 10038 PetscCall(PetscMalloc1(subSize, &subIndices)); 10039 for (p = pStart; p < pEnd; ++p) { 10040 PetscInt gdof, goff; 10041 10042 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10043 if (gdof > 0) { 10044 const PetscInt point = spmap[p]; 10045 10046 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10047 for (f = 0; f < Nf; ++f) { 10048 PetscInt fdof, fcdof, fc, f2, poff = 0; 10049 10050 /* Can get rid of this loop by storing field information in the global section */ 10051 for (f2 = 0; f2 < f; ++f2) { 10052 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10053 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10054 poff += fdof - fcdof; 10055 } 10056 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10057 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10058 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10059 } 10060 } 10061 } 10062 PetscCall(ISRestoreIndices(spIS, &spmap)); 10063 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10064 if (bs > 1) { 10065 /* We need to check that the block size does not come from non-contiguous fields */ 10066 PetscInt i, j, set = 1; 10067 for (i = 0; i < subSize; i += bs) { 10068 for (j = 0; j < bs; ++j) { 10069 if (subIndices[i + j] != subIndices[i] + j) { 10070 set = 0; 10071 break; 10072 } 10073 } 10074 } 10075 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10076 } 10077 /* Attach nullspace */ 10078 for (f = 0; f < Nf; ++f) { 10079 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10080 if ((*subdm)->nullspaceConstructors[f]) break; 10081 } 10082 if (f < Nf) { 10083 MatNullSpace nullSpace; 10084 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10085 10086 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10087 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10088 } 10089 } 10090 PetscFunctionReturn(0); 10091 } 10092 10093 /*@ 10094 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10095 10096 Input Parameter: 10097 - dm - The DM 10098 10099 Level: developer 10100 10101 Options Database Keys: 10102 . -dm_plex_monitor_throughput - Activate the monitor 10103 10104 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 10105 @*/ 10106 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10107 { 10108 #if defined(PETSC_USE_LOG) 10109 PetscStageLog stageLog; 10110 PetscLogEvent event; 10111 PetscLogStage stage; 10112 PetscEventPerfInfo eventInfo; 10113 PetscReal cellRate, flopRate; 10114 PetscInt cStart, cEnd, Nf, N; 10115 const char *name; 10116 #endif 10117 10118 PetscFunctionBegin; 10119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10120 #if defined(PETSC_USE_LOG) 10121 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10122 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10123 PetscCall(DMGetNumFields(dm, &Nf)); 10124 PetscCall(PetscLogGetStageLog(&stageLog)); 10125 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10126 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10127 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10128 N = (cEnd - cStart) * Nf * eventInfo.count; 10129 flopRate = eventInfo.flops / eventInfo.time; 10130 cellRate = N / eventInfo.time; 10131 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))); 10132 #else 10133 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10134 #endif 10135 PetscFunctionReturn(0); 10136 } 10137