1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart, DMPLEX_Generate; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The `DMPLEX` object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Level: intermediate 28 29 Note: 30 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 31 If the mesh has no cells, this returns `PETSC_FALSE`. 32 33 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 34 @*/ 35 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 36 { 37 DMPolytopeType ct; 38 PetscInt cStart, cEnd; 39 40 PetscFunctionBegin; 41 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 42 if (cEnd <= cStart) { 43 *simplex = PETSC_FALSE; 44 PetscFunctionReturn(0); 45 } 46 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 47 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 48 PetscFunctionReturn(0); 49 } 50 51 /*@ 52 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 53 54 Input Parameters: 55 + dm - The `DMPLEX` object 56 - height - The cell height in the Plex, 0 is the default 57 58 Output Parameters: 59 + cStart - The first "normal" cell 60 - cEnd - The upper bound on "normal"" cells 61 62 Level: developer 63 64 Note: 65 This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 66 67 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 68 @*/ 69 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 70 { 71 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 72 PetscInt cS, cE, c; 73 74 PetscFunctionBegin; 75 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 76 for (c = cS; c < cE; ++c) { 77 DMPolytopeType cct; 78 79 PetscCall(DMPlexGetCellType(dm, c, &cct)); 80 if ((PetscInt)cct < 0) break; 81 switch (cct) { 82 case DM_POLYTOPE_POINT: 83 case DM_POLYTOPE_SEGMENT: 84 case DM_POLYTOPE_TRIANGLE: 85 case DM_POLYTOPE_QUADRILATERAL: 86 case DM_POLYTOPE_TETRAHEDRON: 87 case DM_POLYTOPE_HEXAHEDRON: 88 ct = cct; 89 break; 90 default: 91 break; 92 } 93 if (ct != DM_POLYTOPE_UNKNOWN) break; 94 } 95 if (ct != DM_POLYTOPE_UNKNOWN) { 96 DMLabel ctLabel; 97 98 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 99 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 100 // Reset label for fast lookup 101 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 102 } 103 if (cStart) *cStart = cS; 104 if (cEnd) *cEnd = cE; 105 PetscFunctionReturn(0); 106 } 107 108 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 109 { 110 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 111 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 112 113 PetscFunctionBegin; 114 *ft = PETSC_VTK_INVALID; 115 PetscCall(DMGetCoordinateDim(dm, &cdim)); 116 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 117 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 118 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 119 if (field >= 0) { 120 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 121 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 122 } else { 123 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 124 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 125 } 126 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 127 if (globalvcdof[0]) { 128 *sStart = vStart; 129 *sEnd = vEnd; 130 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 131 else *ft = PETSC_VTK_POINT_FIELD; 132 } else if (globalvcdof[1]) { 133 *sStart = cStart; 134 *sEnd = cEnd; 135 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 136 else *ft = PETSC_VTK_CELL_FIELD; 137 } else { 138 if (field >= 0) { 139 const char *fieldname; 140 141 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 143 } else { 144 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 145 } 146 } 147 PetscFunctionReturn(0); 148 } 149 150 /*@ 151 DMPlexVecView1D - Plot many 1D solutions on the same line graph 152 153 Collective on dm 154 155 Input Parameters: 156 + dm - The `DMPLEX` object 157 . n - The number of vectors 158 . u - The array of local vectors 159 - viewer - The `PetscViewer` 160 161 Level: advanced 162 163 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `VecViewFromOptions()`, `VecView()` 164 @*/ 165 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 166 { 167 PetscDS ds; 168 PetscDraw draw = NULL; 169 PetscDrawLG lg; 170 Vec coordinates; 171 const PetscScalar *coords, **sol; 172 PetscReal *vals; 173 PetscInt *Nc; 174 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 175 char **names; 176 177 PetscFunctionBegin; 178 PetscCall(DMGetDS(dm, &ds)); 179 PetscCall(PetscDSGetNumFields(ds, &Nf)); 180 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 181 PetscCall(PetscDSGetComponents(ds, &Nc)); 182 183 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 184 if (!draw) PetscFunctionReturn(0); 185 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 186 187 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 188 for (i = 0, l = 0; i < n; ++i) { 189 const char *vname; 190 191 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 192 for (f = 0; f < Nf; ++f) { 193 PetscObject disc; 194 const char *fname; 195 char tmpname[PETSC_MAX_PATH_LEN]; 196 197 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 198 /* TODO Create names for components */ 199 for (c = 0; c < Nc[f]; ++c, ++l) { 200 PetscCall(PetscObjectGetName(disc, &fname)); 201 PetscCall(PetscStrcpy(tmpname, vname)); 202 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 203 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 204 PetscCall(PetscStrallocpy(tmpname, &names[l])); 205 } 206 } 207 } 208 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 209 /* Just add P_1 support for now */ 210 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 211 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 212 PetscCall(VecGetArrayRead(coordinates, &coords)); 213 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 214 for (v = vStart; v < vEnd; ++v) { 215 PetscScalar *x, *svals; 216 217 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 218 for (i = 0; i < n; ++i) { 219 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 220 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 221 } 222 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 223 } 224 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 225 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 226 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 227 PetscCall(PetscFree3(sol, names, vals)); 228 229 PetscCall(PetscDrawLGDraw(lg)); 230 PetscCall(PetscDrawLGDestroy(&lg)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 235 { 236 DM dm; 237 238 PetscFunctionBegin; 239 PetscCall(VecGetDM(u, &dm)); 240 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 241 PetscFunctionReturn(0); 242 } 243 244 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 245 { 246 DM dm; 247 PetscSection s; 248 PetscDraw draw, popup; 249 DM cdm; 250 PetscSection coordSection; 251 Vec coordinates; 252 const PetscScalar *coords, *array; 253 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 254 PetscReal vbound[2], time; 255 PetscBool flg; 256 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 257 const char *name; 258 char title[PETSC_MAX_PATH_LEN]; 259 260 PetscFunctionBegin; 261 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 262 PetscCall(VecGetDM(v, &dm)); 263 PetscCall(DMGetCoordinateDim(dm, &dim)); 264 PetscCall(DMGetLocalSection(dm, &s)); 265 PetscCall(PetscSectionGetNumFields(s, &Nf)); 266 PetscCall(DMGetCoarsenLevel(dm, &level)); 267 PetscCall(DMGetCoordinateDM(dm, &cdm)); 268 PetscCall(DMGetLocalSection(cdm, &coordSection)); 269 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 270 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 271 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 272 273 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 274 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 275 276 PetscCall(VecGetLocalSize(coordinates, &N)); 277 PetscCall(VecGetArrayRead(coordinates, &coords)); 278 for (c = 0; c < N; c += dim) { 279 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 280 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 281 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 282 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 283 } 284 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 285 PetscCall(PetscDrawClear(draw)); 286 287 /* Could implement something like DMDASelectFields() */ 288 for (f = 0; f < Nf; ++f) { 289 DM fdm = dm; 290 Vec fv = v; 291 IS fis; 292 char prefix[PETSC_MAX_PATH_LEN]; 293 const char *fname; 294 295 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 296 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 297 298 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 299 else prefix[0] = '\0'; 300 if (Nf > 1) { 301 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 302 PetscCall(VecGetSubVector(v, fis, &fv)); 303 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 304 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 305 } 306 for (comp = 0; comp < Nc; ++comp, ++w) { 307 PetscInt nmax = 2; 308 309 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 310 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 311 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 312 PetscCall(PetscDrawSetTitle(draw, title)); 313 314 /* TODO Get max and min only for this component */ 315 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 316 if (!flg) { 317 PetscCall(VecMin(fv, NULL, &vbound[0])); 318 PetscCall(VecMax(fv, NULL, &vbound[1])); 319 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 320 } 321 PetscCall(PetscDrawGetPopup(draw, &popup)); 322 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 323 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 324 325 PetscCall(VecGetArrayRead(fv, &array)); 326 for (c = cStart; c < cEnd; ++c) { 327 PetscScalar *coords = NULL, *a = NULL; 328 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 329 330 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 331 if (a) { 332 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 333 color[1] = color[2] = color[3] = color[0]; 334 } else { 335 PetscScalar *vals = NULL; 336 PetscInt numVals, va; 337 338 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 339 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); 340 switch (numVals / Nc) { 341 case 3: /* P1 Triangle */ 342 case 4: /* P1 Quadrangle */ 343 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 344 break; 345 case 6: /* P2 Triangle */ 346 case 8: /* P2 Quadrangle */ 347 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 348 break; 349 default: 350 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 351 } 352 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 353 } 354 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 switch (numCoords) { 356 case 6: 357 case 12: /* Localized triangle */ 358 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])); 359 break; 360 case 8: 361 case 16: /* Localized quadrilateral */ 362 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])); 363 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])); 364 break; 365 default: 366 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 367 } 368 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 369 } 370 PetscCall(VecRestoreArrayRead(fv, &array)); 371 PetscCall(PetscDrawFlush(draw)); 372 PetscCall(PetscDrawPause(draw)); 373 PetscCall(PetscDrawSave(draw)); 374 } 375 if (Nf > 1) { 376 PetscCall(VecRestoreSubVector(v, fis, &fv)); 377 PetscCall(ISDestroy(&fis)); 378 PetscCall(DMDestroy(&fdm)); 379 } 380 } 381 PetscFunctionReturn(0); 382 } 383 384 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 385 { 386 DM dm; 387 PetscDraw draw; 388 PetscInt dim; 389 PetscBool isnull; 390 391 PetscFunctionBegin; 392 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 393 PetscCall(PetscDrawIsNull(draw, &isnull)); 394 if (isnull) PetscFunctionReturn(0); 395 396 PetscCall(VecGetDM(v, &dm)); 397 PetscCall(DMGetCoordinateDim(dm, &dim)); 398 switch (dim) { 399 case 1: 400 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 401 break; 402 case 2: 403 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 404 break; 405 default: 406 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 407 } 408 PetscFunctionReturn(0); 409 } 410 411 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 412 { 413 DM dm; 414 Vec locv; 415 const char *name; 416 PetscSection section; 417 PetscInt pStart, pEnd; 418 PetscInt numFields; 419 PetscViewerVTKFieldType ft; 420 421 PetscFunctionBegin; 422 PetscCall(VecGetDM(v, &dm)); 423 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 424 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 425 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 426 PetscCall(VecCopy(v, locv)); 427 PetscCall(DMGetLocalSection(dm, §ion)); 428 PetscCall(PetscSectionGetNumFields(section, &numFields)); 429 if (!numFields) { 430 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 431 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 432 } else { 433 PetscInt f; 434 435 for (f = 0; f < numFields; f++) { 436 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 437 if (ft == PETSC_VTK_INVALID) continue; 438 PetscCall(PetscObjectReference((PetscObject)locv)); 439 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 440 } 441 PetscCall(VecDestroy(&locv)); 442 } 443 PetscFunctionReturn(0); 444 } 445 446 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 447 { 448 DM dm; 449 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 450 451 PetscFunctionBegin; 452 PetscCall(VecGetDM(v, &dm)); 453 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 454 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 455 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 456 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 457 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 458 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 459 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 460 PetscInt i, numFields; 461 PetscObject fe; 462 PetscBool fem = PETSC_FALSE; 463 Vec locv = v; 464 const char *name; 465 PetscInt step; 466 PetscReal time; 467 468 PetscCall(DMGetNumFields(dm, &numFields)); 469 for (i = 0; i < numFields; i++) { 470 PetscCall(DMGetField(dm, i, NULL, &fe)); 471 if (fe->classid == PETSCFE_CLASSID) { 472 fem = PETSC_TRUE; 473 break; 474 } 475 } 476 if (fem) { 477 PetscObject isZero; 478 479 PetscCall(DMGetLocalVector(dm, &locv)); 480 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 481 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 482 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 483 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 484 PetscCall(VecCopy(v, locv)); 485 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 486 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 487 } 488 if (isvtk) { 489 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 490 } else if (ishdf5) { 491 #if defined(PETSC_HAVE_HDF5) 492 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 493 #else 494 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 495 #endif 496 } else if (isdraw) { 497 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 498 } else if (isglvis) { 499 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 500 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 501 PetscCall(VecView_GLVis(locv, viewer)); 502 } else if (iscgns) { 503 #if defined(PETSC_HAVE_CGNS) 504 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 505 #else 506 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 507 #endif 508 } 509 if (fem) { 510 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 511 PetscCall(DMRestoreLocalVector(dm, &locv)); 512 } 513 } else { 514 PetscBool isseq; 515 516 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 517 if (isseq) PetscCall(VecView_Seq(v, viewer)); 518 else PetscCall(VecView_MPI(v, viewer)); 519 } 520 PetscFunctionReturn(0); 521 } 522 523 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 524 { 525 DM dm; 526 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 527 528 PetscFunctionBegin; 529 PetscCall(VecGetDM(v, &dm)); 530 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 532 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 535 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 536 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 537 if (isvtk || isdraw || isglvis || iscgns) { 538 Vec locv; 539 PetscObject isZero; 540 const char *name; 541 542 PetscCall(DMGetLocalVector(dm, &locv)); 543 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 544 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 545 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 546 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 547 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 548 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 549 PetscCall(VecView_Plex_Local(locv, viewer)); 550 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 551 PetscCall(DMRestoreLocalVector(dm, &locv)); 552 } else if (ishdf5) { 553 #if defined(PETSC_HAVE_HDF5) 554 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 555 #else 556 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 557 #endif 558 } else if (isexodusii) { 559 #if defined(PETSC_HAVE_EXODUSII) 560 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 561 #else 562 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 563 #endif 564 } else { 565 PetscBool isseq; 566 567 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 568 if (isseq) PetscCall(VecView_Seq(v, viewer)); 569 else PetscCall(VecView_MPI(v, viewer)); 570 } 571 PetscFunctionReturn(0); 572 } 573 574 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 575 { 576 DM dm; 577 MPI_Comm comm; 578 PetscViewerFormat format; 579 Vec v; 580 PetscBool isvtk, ishdf5; 581 582 PetscFunctionBegin; 583 PetscCall(VecGetDM(originalv, &dm)); 584 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 585 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 586 PetscCall(PetscViewerGetFormat(viewer, &format)); 587 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 588 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 589 if (format == PETSC_VIEWER_NATIVE) { 590 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 591 /* this need a better fix */ 592 if (dm->useNatural) { 593 if (dm->sfNatural) { 594 const char *vecname; 595 PetscInt n, nroots; 596 597 PetscCall(VecGetLocalSize(originalv, &n)); 598 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 599 if (n == nroots) { 600 PetscCall(DMGetGlobalVector(dm, &v)); 601 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 602 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 603 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 604 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 605 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 606 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 607 } else v = originalv; 608 } else v = originalv; 609 610 if (ishdf5) { 611 #if defined(PETSC_HAVE_HDF5) 612 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 613 #else 614 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 615 #endif 616 } else if (isvtk) { 617 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 618 } else { 619 PetscBool isseq; 620 621 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 622 if (isseq) PetscCall(VecView_Seq(v, viewer)); 623 else PetscCall(VecView_MPI(v, viewer)); 624 } 625 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 626 PetscFunctionReturn(0); 627 } 628 629 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 630 { 631 DM dm; 632 PetscBool ishdf5; 633 634 PetscFunctionBegin; 635 PetscCall(VecGetDM(v, &dm)); 636 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 637 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 638 if (ishdf5) { 639 DM dmBC; 640 Vec gv; 641 const char *name; 642 643 PetscCall(DMGetOutputDM(dm, &dmBC)); 644 PetscCall(DMGetGlobalVector(dmBC, &gv)); 645 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 646 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 647 PetscCall(VecLoad_Default(gv, viewer)); 648 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 649 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 650 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 651 } else PetscCall(VecLoad_Default(v, viewer)); 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 656 { 657 DM dm; 658 PetscBool ishdf5, isexodusii; 659 660 PetscFunctionBegin; 661 PetscCall(VecGetDM(v, &dm)); 662 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 663 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 664 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 665 if (ishdf5) { 666 #if defined(PETSC_HAVE_HDF5) 667 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 668 #else 669 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 670 #endif 671 } else if (isexodusii) { 672 #if defined(PETSC_HAVE_EXODUSII) 673 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 674 #else 675 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 676 #endif 677 } else PetscCall(VecLoad_Default(v, viewer)); 678 PetscFunctionReturn(0); 679 } 680 681 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 682 { 683 DM dm; 684 PetscViewerFormat format; 685 PetscBool ishdf5; 686 687 PetscFunctionBegin; 688 PetscCall(VecGetDM(originalv, &dm)); 689 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 690 PetscCall(PetscViewerGetFormat(viewer, &format)); 691 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 692 if (format == PETSC_VIEWER_NATIVE) { 693 if (dm->useNatural) { 694 if (dm->sfNatural) { 695 if (ishdf5) { 696 #if defined(PETSC_HAVE_HDF5) 697 Vec v; 698 const char *vecname; 699 700 PetscCall(DMGetGlobalVector(dm, &v)); 701 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 702 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 703 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 704 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 705 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 706 PetscCall(DMRestoreGlobalVector(dm, &v)); 707 #else 708 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 709 #endif 710 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 711 } 712 } else PetscCall(VecLoad_Default(originalv, viewer)); 713 } 714 PetscFunctionReturn(0); 715 } 716 717 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 718 { 719 PetscSection coordSection; 720 Vec coordinates; 721 DMLabel depthLabel, celltypeLabel; 722 const char *name[4]; 723 const PetscScalar *a; 724 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 725 726 PetscFunctionBegin; 727 PetscCall(DMGetDimension(dm, &dim)); 728 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 729 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 730 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 731 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 732 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 733 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 734 PetscCall(VecGetArrayRead(coordinates, &a)); 735 name[0] = "vertex"; 736 name[1] = "edge"; 737 name[dim - 1] = "face"; 738 name[dim] = "cell"; 739 for (c = cStart; c < cEnd; ++c) { 740 PetscInt *closure = NULL; 741 PetscInt closureSize, cl, ct; 742 743 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 744 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 745 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 746 PetscCall(PetscViewerASCIIPushTab(viewer)); 747 for (cl = 0; cl < closureSize * 2; cl += 2) { 748 PetscInt point = closure[cl], depth, dof, off, d, p; 749 750 if ((point < pStart) || (point >= pEnd)) continue; 751 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 752 if (!dof) continue; 753 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 754 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 755 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 756 for (p = 0; p < dof / dim; ++p) { 757 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 758 for (d = 0; d < dim; ++d) { 759 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 760 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 761 } 762 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 763 } 764 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 765 } 766 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 767 PetscCall(PetscViewerASCIIPopTab(viewer)); 768 } 769 PetscCall(VecRestoreArrayRead(coordinates, &a)); 770 PetscFunctionReturn(0); 771 } 772 773 typedef enum { 774 CS_CARTESIAN, 775 CS_POLAR, 776 CS_CYLINDRICAL, 777 CS_SPHERICAL 778 } CoordSystem; 779 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 780 781 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 782 { 783 PetscInt i; 784 785 PetscFunctionBegin; 786 if (dim > 3) { 787 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 788 } else { 789 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 790 791 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 792 switch (cs) { 793 case CS_CARTESIAN: 794 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 795 break; 796 case CS_POLAR: 797 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 798 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 799 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 800 break; 801 case CS_CYLINDRICAL: 802 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 803 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 804 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 805 trcoords[2] = coords[2]; 806 break; 807 case CS_SPHERICAL: 808 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 809 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 810 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 811 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 812 break; 813 } 814 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 815 } 816 PetscFunctionReturn(0); 817 } 818 819 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 820 { 821 DM_Plex *mesh = (DM_Plex *)dm->data; 822 DM cdm, cdmCell; 823 PetscSection coordSection, coordSectionCell; 824 Vec coordinates, coordinatesCell; 825 PetscViewerFormat format; 826 827 PetscFunctionBegin; 828 PetscCall(PetscViewerGetFormat(viewer, &format)); 829 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 830 const char *name; 831 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 832 PetscInt pStart, pEnd, p, numLabels, l; 833 PetscMPIInt rank, size; 834 835 PetscCall(DMGetCoordinateDM(dm, &cdm)); 836 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 837 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 838 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 839 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 840 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 841 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 842 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 843 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 844 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 845 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 846 PetscCall(DMGetDimension(dm, &dim)); 847 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 848 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 849 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 850 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 851 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 852 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 853 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 854 for (p = pStart; p < pEnd; ++p) { 855 PetscInt dof, off, s; 856 857 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 858 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 859 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 860 } 861 PetscCall(PetscViewerFlush(viewer)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off, c; 866 867 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 869 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])); 870 } 871 PetscCall(PetscViewerFlush(viewer)); 872 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 873 if (coordSection && coordinates) { 874 CoordSystem cs = CS_CARTESIAN; 875 const PetscScalar *array, *arrayCell = NULL; 876 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 877 PetscMPIInt rank; 878 const char *name; 879 880 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 881 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 882 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 883 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 884 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 885 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 886 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 887 pStart = PetscMin(pvStart, pcStart); 888 pEnd = PetscMax(pvEnd, pcEnd); 889 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 890 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 891 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 892 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 893 894 PetscCall(VecGetArrayRead(coordinates, &array)); 895 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 896 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 897 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 898 for (p = pStart; p < pEnd; ++p) { 899 PetscInt dof, off; 900 901 if (p >= pvStart && p < pvEnd) { 902 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 903 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 904 if (dof) { 905 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 906 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 907 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 908 } 909 } 910 if (cdmCell && p >= pcStart && p < pcEnd) { 911 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 912 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 913 if (dof) { 914 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 915 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 916 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 917 } 918 } 919 } 920 PetscCall(PetscViewerFlush(viewer)); 921 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 922 PetscCall(VecRestoreArrayRead(coordinates, &array)); 923 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 924 } 925 PetscCall(DMGetNumLabels(dm, &numLabels)); 926 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 927 for (l = 0; l < numLabels; ++l) { 928 DMLabel label; 929 PetscBool isdepth; 930 const char *name; 931 932 PetscCall(DMGetLabelName(dm, l, &name)); 933 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 934 if (isdepth) continue; 935 PetscCall(DMGetLabel(dm, name, &label)); 936 PetscCall(DMLabelView(label, viewer)); 937 } 938 if (size > 1) { 939 PetscSF sf; 940 941 PetscCall(DMGetPointSF(dm, &sf)); 942 PetscCall(PetscSFView(sf, viewer)); 943 } 944 if (mesh->periodic.face_sf) PetscCall(PetscSFView(mesh->periodic.face_sf, viewer)); 945 PetscCall(PetscViewerFlush(viewer)); 946 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 947 const char *name, *color; 948 const char *defcolors[3] = {"gray", "orange", "green"}; 949 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 950 char lname[PETSC_MAX_PATH_LEN]; 951 PetscReal scale = 2.0; 952 PetscReal tikzscale = 1.0; 953 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 954 double tcoords[3]; 955 PetscScalar *coords; 956 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 957 PetscMPIInt rank, size; 958 char **names, **colors, **lcolors; 959 PetscBool flg, lflg; 960 PetscBT wp = NULL; 961 PetscInt pEnd, pStart; 962 963 PetscCall(DMGetCoordinateDM(dm, &cdm)); 964 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 965 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 966 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 967 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 968 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 969 PetscCall(DMGetDimension(dm, &dim)); 970 PetscCall(DMPlexGetDepth(dm, &depth)); 971 PetscCall(DMGetNumLabels(dm, &numLabels)); 972 numLabels = PetscMax(numLabels, 10); 973 numColors = 10; 974 numLColors = 10; 975 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 976 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 977 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 978 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 979 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 980 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 981 n = 4; 982 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 983 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 984 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 985 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 986 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 987 if (!useLabels) numLabels = 0; 988 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 989 if (!useColors) { 990 numColors = 3; 991 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 992 } 993 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 994 if (!useColors) { 995 numLColors = 4; 996 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 997 } 998 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 999 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 1000 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 1001 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 1002 if (depth < dim) plotEdges = PETSC_FALSE; 1003 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 1004 1005 /* filter points with labelvalue != labeldefaultvalue */ 1006 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1007 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1008 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1009 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1010 if (lflg) { 1011 DMLabel lbl; 1012 1013 PetscCall(DMGetLabel(dm, lname, &lbl)); 1014 if (lbl) { 1015 PetscInt val, defval; 1016 1017 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1018 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1019 for (c = pStart; c < pEnd; c++) { 1020 PetscInt *closure = NULL; 1021 PetscInt closureSize; 1022 1023 PetscCall(DMLabelGetValue(lbl, c, &val)); 1024 if (val == defval) continue; 1025 1026 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1027 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1028 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1029 } 1030 } 1031 } 1032 1033 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1034 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1035 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1036 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1037 \\documentclass[tikz]{standalone}\n\n\ 1038 \\usepackage{pgflibraryshapes}\n\ 1039 \\usetikzlibrary{backgrounds}\n\ 1040 \\usetikzlibrary{arrows}\n\ 1041 \\begin{document}\n")); 1042 if (size > 1) { 1043 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1044 for (p = 0; p < size; ++p) { 1045 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1046 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1047 } 1048 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1049 } 1050 if (drawHasse) { 1051 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1052 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1056 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1058 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1059 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1060 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1061 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1062 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1063 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1064 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1065 } 1066 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1067 1068 /* Plot vertices */ 1069 PetscCall(VecGetArray(coordinates, &coords)); 1070 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1071 for (v = vStart; v < vEnd; ++v) { 1072 PetscInt off, dof, d; 1073 PetscBool isLabeled = PETSC_FALSE; 1074 1075 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1076 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1077 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1079 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1080 for (d = 0; d < dof; ++d) { 1081 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1082 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1083 } 1084 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1085 if (dim == 3) { 1086 PetscReal tmp = tcoords[1]; 1087 tcoords[1] = tcoords[2]; 1088 tcoords[2] = -tmp; 1089 } 1090 for (d = 0; d < dof; ++d) { 1091 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1093 } 1094 if (drawHasse) color = colors[0 % numColors]; 1095 else color = colors[rank % numColors]; 1096 for (l = 0; l < numLabels; ++l) { 1097 PetscInt val; 1098 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1099 if (val >= 0) { 1100 color = lcolors[l % numLColors]; 1101 isLabeled = PETSC_TRUE; 1102 break; 1103 } 1104 } 1105 if (drawNumbers[0]) { 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1107 } else if (drawColors[0]) { 1108 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1109 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1110 } 1111 PetscCall(VecRestoreArray(coordinates, &coords)); 1112 PetscCall(PetscViewerFlush(viewer)); 1113 /* Plot edges */ 1114 if (plotEdges) { 1115 PetscCall(VecGetArray(coordinates, &coords)); 1116 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1117 for (e = eStart; e < eEnd; ++e) { 1118 const PetscInt *cone; 1119 PetscInt coneSize, offA, offB, dof, d; 1120 1121 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1122 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1123 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1124 PetscCall(DMPlexGetCone(dm, e, &cone)); 1125 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1126 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1127 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1128 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1129 for (d = 0; d < dof; ++d) { 1130 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1131 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1132 } 1133 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1134 if (dim == 3) { 1135 PetscReal tmp = tcoords[1]; 1136 tcoords[1] = tcoords[2]; 1137 tcoords[2] = -tmp; 1138 } 1139 for (d = 0; d < dof; ++d) { 1140 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1141 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1142 } 1143 if (drawHasse) color = colors[1 % numColors]; 1144 else color = colors[rank % numColors]; 1145 for (l = 0; l < numLabels; ++l) { 1146 PetscInt val; 1147 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1148 if (val >= 0) { 1149 color = lcolors[l % numLColors]; 1150 break; 1151 } 1152 } 1153 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1154 } 1155 PetscCall(VecRestoreArray(coordinates, &coords)); 1156 PetscCall(PetscViewerFlush(viewer)); 1157 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1158 } 1159 /* Plot cells */ 1160 if (dim == 3 || !drawNumbers[1]) { 1161 for (e = eStart; e < eEnd; ++e) { 1162 const PetscInt *cone; 1163 1164 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1165 color = colors[rank % numColors]; 1166 for (l = 0; l < numLabels; ++l) { 1167 PetscInt val; 1168 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1169 if (val >= 0) { 1170 color = lcolors[l % numLColors]; 1171 break; 1172 } 1173 } 1174 PetscCall(DMPlexGetCone(dm, e, &cone)); 1175 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1176 } 1177 } else { 1178 DMPolytopeType ct; 1179 1180 /* Drawing a 2D polygon */ 1181 for (c = cStart; c < cEnd; ++c) { 1182 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1183 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1184 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1185 const PetscInt *cone; 1186 PetscInt coneSize, e; 1187 1188 PetscCall(DMPlexGetCone(dm, c, &cone)); 1189 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1190 for (e = 0; e < coneSize; ++e) { 1191 const PetscInt *econe; 1192 1193 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1194 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)); 1195 } 1196 } else { 1197 PetscInt *closure = NULL; 1198 PetscInt closureSize, Nv = 0, v; 1199 1200 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1201 for (p = 0; p < closureSize * 2; p += 2) { 1202 const PetscInt point = closure[p]; 1203 1204 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1205 } 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1207 for (v = 0; v <= Nv; ++v) { 1208 const PetscInt vertex = closure[v % Nv]; 1209 1210 if (v > 0) { 1211 if (plotEdges) { 1212 const PetscInt *edge; 1213 PetscInt endpoints[2], ne; 1214 1215 endpoints[0] = closure[v - 1]; 1216 endpoints[1] = vertex; 1217 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1218 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1219 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1220 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1221 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1222 } 1223 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1224 } 1225 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1226 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1227 } 1228 } 1229 } 1230 for (c = cStart; c < cEnd; ++c) { 1231 double ccoords[3] = {0.0, 0.0, 0.0}; 1232 PetscBool isLabeled = PETSC_FALSE; 1233 PetscScalar *cellCoords = NULL; 1234 const PetscScalar *array; 1235 PetscInt numCoords, cdim, d; 1236 PetscBool isDG; 1237 1238 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1239 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1240 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1241 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1242 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1243 for (p = 0; p < numCoords / cdim; ++p) { 1244 for (d = 0; d < cdim; ++d) { 1245 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1246 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1247 } 1248 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1249 if (cdim == 3) { 1250 PetscReal tmp = tcoords[1]; 1251 tcoords[1] = tcoords[2]; 1252 tcoords[2] = -tmp; 1253 } 1254 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1255 } 1256 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1257 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1258 for (d = 0; d < cdim; ++d) { 1259 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1260 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1261 } 1262 if (drawHasse) color = colors[depth % numColors]; 1263 else color = colors[rank % numColors]; 1264 for (l = 0; l < numLabels; ++l) { 1265 PetscInt val; 1266 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1267 if (val >= 0) { 1268 color = lcolors[l % numLColors]; 1269 isLabeled = PETSC_TRUE; 1270 break; 1271 } 1272 } 1273 if (drawNumbers[dim]) { 1274 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1275 } else if (drawColors[dim]) { 1276 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1277 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1278 } 1279 if (drawHasse) { 1280 color = colors[depth % numColors]; 1281 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1282 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1283 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1284 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1285 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1286 1287 color = colors[1 % numColors]; 1288 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1289 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1291 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1292 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1293 1294 color = colors[0 % numColors]; 1295 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1296 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1297 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1298 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1299 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1300 1301 for (p = pStart; p < pEnd; ++p) { 1302 const PetscInt *cone; 1303 PetscInt coneSize, cp; 1304 1305 PetscCall(DMPlexGetCone(dm, p, &cone)); 1306 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1307 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1308 } 1309 } 1310 PetscCall(PetscViewerFlush(viewer)); 1311 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1312 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1313 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1314 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1315 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1316 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1317 PetscCall(PetscFree3(names, colors, lcolors)); 1318 PetscCall(PetscBTDestroy(&wp)); 1319 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1320 Vec cown, acown; 1321 VecScatter sct; 1322 ISLocalToGlobalMapping g2l; 1323 IS gid, acis; 1324 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1325 MPI_Group ggroup, ngroup; 1326 PetscScalar *array, nid; 1327 const PetscInt *idxs; 1328 PetscInt *idxs2, *start, *adjacency, *work; 1329 PetscInt64 lm[3], gm[3]; 1330 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1331 PetscMPIInt d1, d2, rank; 1332 1333 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1334 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1335 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1336 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1337 #endif 1338 if (ncomm != MPI_COMM_NULL) { 1339 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1340 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1341 d1 = 0; 1342 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1343 nid = d2; 1344 PetscCallMPI(MPI_Group_free(&ggroup)); 1345 PetscCallMPI(MPI_Group_free(&ngroup)); 1346 PetscCallMPI(MPI_Comm_free(&ncomm)); 1347 } else nid = 0.0; 1348 1349 /* Get connectivity */ 1350 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1351 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1352 1353 /* filter overlapped local cells */ 1354 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1355 PetscCall(ISGetIndices(gid, &idxs)); 1356 PetscCall(ISGetLocalSize(gid, &cum)); 1357 PetscCall(PetscMalloc1(cum, &idxs2)); 1358 for (c = cStart, cum = 0; c < cEnd; c++) { 1359 if (idxs[c - cStart] < 0) continue; 1360 idxs2[cum++] = idxs[c - cStart]; 1361 } 1362 PetscCall(ISRestoreIndices(gid, &idxs)); 1363 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1364 PetscCall(ISDestroy(&gid)); 1365 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1366 1367 /* support for node-aware cell locality */ 1368 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1369 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1370 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1371 PetscCall(VecGetArray(cown, &array)); 1372 for (c = 0; c < numVertices; c++) array[c] = nid; 1373 PetscCall(VecRestoreArray(cown, &array)); 1374 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1375 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1376 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1377 PetscCall(ISDestroy(&acis)); 1378 PetscCall(VecScatterDestroy(&sct)); 1379 PetscCall(VecDestroy(&cown)); 1380 1381 /* compute edgeCut */ 1382 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1383 PetscCall(PetscMalloc1(cum, &work)); 1384 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1385 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1386 PetscCall(ISDestroy(&gid)); 1387 PetscCall(VecGetArray(acown, &array)); 1388 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1389 PetscInt totl; 1390 1391 totl = start[c + 1] - start[c]; 1392 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1393 for (i = 0; i < totl; i++) { 1394 if (work[i] < 0) { 1395 ect += 1; 1396 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1397 } 1398 } 1399 } 1400 PetscCall(PetscFree(work)); 1401 PetscCall(VecRestoreArray(acown, &array)); 1402 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1403 lm[1] = -numVertices; 1404 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1405 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1406 lm[0] = ect; /* edgeCut */ 1407 lm[1] = ectn; /* node-aware edgeCut */ 1408 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1409 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1410 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1411 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1412 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1413 #else 1414 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1415 #endif 1416 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1417 PetscCall(PetscFree(start)); 1418 PetscCall(PetscFree(adjacency)); 1419 PetscCall(VecDestroy(&acown)); 1420 } else { 1421 const char *name; 1422 PetscInt *sizes, *hybsizes, *ghostsizes; 1423 PetscInt locDepth, depth, cellHeight, dim, d; 1424 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1425 PetscInt numLabels, l, maxSize = 17; 1426 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1427 MPI_Comm comm; 1428 PetscMPIInt size, rank; 1429 1430 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1431 PetscCallMPI(MPI_Comm_size(comm, &size)); 1432 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1433 PetscCall(DMGetDimension(dm, &dim)); 1434 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1435 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1436 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1437 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1438 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1439 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1440 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1441 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1442 gcNum = gcEnd - gcStart; 1443 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1444 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1445 for (d = 0; d <= depth; d++) { 1446 PetscInt Nc[2] = {0, 0}, ict; 1447 1448 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1449 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1450 ict = ct0; 1451 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1452 ct0 = (DMPolytopeType)ict; 1453 for (p = pStart; p < pEnd; ++p) { 1454 DMPolytopeType ct; 1455 1456 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1457 if (ct == ct0) ++Nc[0]; 1458 else ++Nc[1]; 1459 } 1460 if (size < maxSize) { 1461 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1462 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1463 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1464 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1465 for (p = 0; p < size; ++p) { 1466 if (rank == 0) { 1467 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1468 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1469 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1470 } 1471 } 1472 } else { 1473 PetscInt locMinMax[2]; 1474 1475 locMinMax[0] = Nc[0] + Nc[1]; 1476 locMinMax[1] = Nc[0] + Nc[1]; 1477 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1478 locMinMax[0] = Nc[1]; 1479 locMinMax[1] = Nc[1]; 1480 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1481 if (d == depth) { 1482 locMinMax[0] = gcNum; 1483 locMinMax[1] = gcNum; 1484 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1485 } 1486 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1487 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1488 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1489 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1490 } 1491 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1492 } 1493 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1494 { 1495 const PetscReal *maxCell; 1496 const PetscReal *L; 1497 PetscBool localized; 1498 1499 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1500 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1501 if (L || localized) { 1502 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1503 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1504 if (L) { 1505 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1506 for (d = 0; d < dim; ++d) { 1507 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1508 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1509 } 1510 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1511 } 1512 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1513 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1514 } 1515 } 1516 PetscCall(DMGetNumLabels(dm, &numLabels)); 1517 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1518 for (l = 0; l < numLabels; ++l) { 1519 DMLabel label; 1520 const char *name; 1521 IS valueIS; 1522 const PetscInt *values; 1523 PetscInt numValues, v; 1524 1525 PetscCall(DMGetLabelName(dm, l, &name)); 1526 PetscCall(DMGetLabel(dm, name, &label)); 1527 PetscCall(DMLabelGetNumValues(label, &numValues)); 1528 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1529 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1530 PetscCall(ISGetIndices(valueIS, &values)); 1531 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1532 for (v = 0; v < numValues; ++v) { 1533 PetscInt size; 1534 1535 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1536 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1537 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1538 } 1539 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1540 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1541 PetscCall(ISRestoreIndices(valueIS, &values)); 1542 PetscCall(ISDestroy(&valueIS)); 1543 } 1544 { 1545 char **labelNames; 1546 PetscInt Nl = numLabels; 1547 PetscBool flg; 1548 1549 PetscCall(PetscMalloc1(Nl, &labelNames)); 1550 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1551 for (l = 0; l < Nl; ++l) { 1552 DMLabel label; 1553 1554 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1555 if (flg) { 1556 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1557 PetscCall(DMLabelView(label, viewer)); 1558 } 1559 PetscCall(PetscFree(labelNames[l])); 1560 } 1561 PetscCall(PetscFree(labelNames)); 1562 } 1563 /* If no fields are specified, people do not want to see adjacency */ 1564 if (dm->Nf) { 1565 PetscInt f; 1566 1567 for (f = 0; f < dm->Nf; ++f) { 1568 const char *name; 1569 1570 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1571 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1572 PetscCall(PetscViewerASCIIPushTab(viewer)); 1573 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1574 if (dm->fields[f].adjacency[0]) { 1575 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1576 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1577 } else { 1578 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1579 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1580 } 1581 PetscCall(PetscViewerASCIIPopTab(viewer)); 1582 } 1583 } 1584 PetscCall(DMGetCoarseDM(dm, &cdm)); 1585 if (cdm) { 1586 PetscCall(PetscViewerASCIIPushTab(viewer)); 1587 PetscCall(PetscViewerASCIIPrintf(viewer, "Defined by transform from:\n")); 1588 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1589 PetscCall(PetscViewerASCIIPopTab(viewer)); 1590 } 1591 } 1592 PetscFunctionReturn(0); 1593 } 1594 1595 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1596 { 1597 DMPolytopeType ct; 1598 PetscMPIInt rank; 1599 PetscInt cdim; 1600 1601 PetscFunctionBegin; 1602 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1603 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1604 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1605 switch (ct) { 1606 case DM_POLYTOPE_SEGMENT: 1607 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1608 switch (cdim) { 1609 case 1: { 1610 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1611 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1612 1613 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1614 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1615 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1616 } break; 1617 case 2: { 1618 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1619 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1620 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1621 1622 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1623 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)); 1624 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)); 1625 } break; 1626 default: 1627 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1628 } 1629 break; 1630 case DM_POLYTOPE_TRIANGLE: 1631 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)); 1632 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1633 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1634 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1635 break; 1636 case DM_POLYTOPE_QUADRILATERAL: 1637 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)); 1638 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)); 1639 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1640 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1641 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1642 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1643 break; 1644 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1645 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)); 1646 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)); 1647 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1648 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1649 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1650 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1651 break; 1652 case DM_POLYTOPE_FV_GHOST: 1653 break; 1654 default: 1655 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1656 } 1657 PetscFunctionReturn(0); 1658 } 1659 1660 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1661 { 1662 DMPolytopeType ct; 1663 PetscReal centroid[2] = {0., 0.}; 1664 PetscMPIInt rank; 1665 PetscInt fillColor, v, e, d; 1666 1667 PetscFunctionBegin; 1668 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1669 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1670 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1671 switch (ct) { 1672 case DM_POLYTOPE_TRIANGLE: { 1673 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1674 1675 for (v = 0; v < 3; ++v) { 1676 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1677 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1678 } 1679 for (e = 0; e < 3; ++e) { 1680 refCoords[0] = refVertices[e * 2 + 0]; 1681 refCoords[1] = refVertices[e * 2 + 1]; 1682 for (d = 1; d <= edgeDiv; ++d) { 1683 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1684 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1685 } 1686 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1687 for (d = 0; d < edgeDiv; ++d) { 1688 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)); 1689 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1690 } 1691 } 1692 } break; 1693 default: 1694 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1695 } 1696 PetscFunctionReturn(0); 1697 } 1698 1699 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1700 { 1701 PetscDraw draw; 1702 DM cdm; 1703 PetscSection coordSection; 1704 Vec coordinates; 1705 const PetscScalar *coords; 1706 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1707 PetscReal *refCoords, *edgeCoords; 1708 PetscBool isnull, drawAffine = PETSC_TRUE; 1709 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1710 1711 PetscFunctionBegin; 1712 PetscCall(DMGetCoordinateDim(dm, &dim)); 1713 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1714 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1715 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1716 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1717 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1718 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1719 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1720 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1721 1722 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1723 PetscCall(PetscDrawIsNull(draw, &isnull)); 1724 if (isnull) PetscFunctionReturn(0); 1725 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1726 1727 PetscCall(VecGetLocalSize(coordinates, &N)); 1728 PetscCall(VecGetArrayRead(coordinates, &coords)); 1729 for (c = 0; c < N; c += dim) { 1730 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1731 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1732 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1733 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1734 } 1735 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1736 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1737 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1738 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1739 PetscCall(PetscDrawClear(draw)); 1740 1741 for (c = cStart; c < cEnd; ++c) { 1742 PetscScalar *coords = NULL; 1743 PetscInt numCoords; 1744 1745 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1746 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1747 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1748 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1749 } 1750 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1751 PetscCall(PetscDrawFlush(draw)); 1752 PetscCall(PetscDrawPause(draw)); 1753 PetscCall(PetscDrawSave(draw)); 1754 PetscFunctionReturn(0); 1755 } 1756 1757 #if defined(PETSC_HAVE_EXODUSII) 1758 #include <exodusII.h> 1759 #include <petscviewerexodusii.h> 1760 #endif 1761 1762 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1763 { 1764 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1765 char name[PETSC_MAX_PATH_LEN]; 1766 1767 PetscFunctionBegin; 1768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1769 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1770 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1771 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1772 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1773 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1774 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1776 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1777 if (iascii) { 1778 PetscViewerFormat format; 1779 PetscCall(PetscViewerGetFormat(viewer, &format)); 1780 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1781 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1782 } else if (ishdf5) { 1783 #if defined(PETSC_HAVE_HDF5) 1784 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1785 #else 1786 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1787 #endif 1788 } else if (isvtk) { 1789 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1790 } else if (isdraw) { 1791 PetscCall(DMPlexView_Draw(dm, viewer)); 1792 } else if (isglvis) { 1793 PetscCall(DMPlexView_GLVis(dm, viewer)); 1794 #if defined(PETSC_HAVE_EXODUSII) 1795 } else if (isexodus) { 1796 /* 1797 exodusII requires that all sets be part of exactly one cell set. 1798 If the dm does not have a "Cell Sets" label defined, we create one 1799 with ID 1, containig all cells. 1800 Note that if the Cell Sets label is defined but does not cover all cells, 1801 we may still have a problem. This should probably be checked here or in the viewer; 1802 */ 1803 PetscInt numCS; 1804 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1805 if (!numCS) { 1806 PetscInt cStart, cEnd, c; 1807 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1808 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1809 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1810 } 1811 PetscCall(DMView_PlexExodusII(dm, viewer)); 1812 #endif 1813 #if defined(PETSC_HAVE_CGNS) 1814 } else if (iscgns) { 1815 PetscCall(DMView_PlexCGNS(dm, viewer)); 1816 #endif 1817 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1818 /* Optionally view the partition */ 1819 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1820 if (flg) { 1821 Vec ranks; 1822 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1823 PetscCall(VecView(ranks, viewer)); 1824 PetscCall(VecDestroy(&ranks)); 1825 } 1826 /* Optionally view a label */ 1827 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1828 if (flg) { 1829 DMLabel label; 1830 Vec val; 1831 1832 PetscCall(DMGetLabel(dm, name, &label)); 1833 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1834 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1835 PetscCall(VecView(val, viewer)); 1836 PetscCall(VecDestroy(&val)); 1837 } 1838 PetscFunctionReturn(0); 1839 } 1840 1841 /*@ 1842 DMPlexTopologyView - Saves a `DMPLEX` topology into a file 1843 1844 Collective on dm 1845 1846 Input Parameters: 1847 + dm - The `DM` whose topology is to be saved 1848 - viewer - The `PetscViewer` to save it in 1849 1850 Level: advanced 1851 1852 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()`, `PetscViewer` 1853 @*/ 1854 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1855 { 1856 PetscBool ishdf5; 1857 1858 PetscFunctionBegin; 1859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1860 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1861 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1862 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1863 if (ishdf5) { 1864 #if defined(PETSC_HAVE_HDF5) 1865 PetscViewerFormat format; 1866 PetscCall(PetscViewerGetFormat(viewer, &format)); 1867 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1868 IS globalPointNumbering; 1869 1870 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1871 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1872 PetscCall(ISDestroy(&globalPointNumbering)); 1873 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1874 #else 1875 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1876 #endif 1877 } 1878 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1879 PetscFunctionReturn(0); 1880 } 1881 1882 /*@ 1883 DMPlexCoordinatesView - Saves `DMPLEX` coordinates into a file 1884 1885 Collective on dm 1886 1887 Input Parameters: 1888 + dm - The `DM` whose coordinates are to be saved 1889 - viewer - The `PetscViewer` for saving 1890 1891 Level: advanced 1892 1893 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()`, `PetscViewer` 1894 @*/ 1895 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1896 { 1897 PetscBool ishdf5; 1898 1899 PetscFunctionBegin; 1900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1901 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1902 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1903 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1904 if (ishdf5) { 1905 #if defined(PETSC_HAVE_HDF5) 1906 PetscViewerFormat format; 1907 PetscCall(PetscViewerGetFormat(viewer, &format)); 1908 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1909 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1910 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1911 #else 1912 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1913 #endif 1914 } 1915 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1916 PetscFunctionReturn(0); 1917 } 1918 1919 /*@ 1920 DMPlexLabelsView - Saves `DMPLEX` labels into a file 1921 1922 Collective on dm 1923 1924 Input Parameters: 1925 + dm - The `DM` whose labels are to be saved 1926 - viewer - The `PetscViewer` for saving 1927 1928 Level: advanced 1929 1930 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()`, `PetscViewer` 1931 @*/ 1932 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1933 { 1934 PetscBool ishdf5; 1935 1936 PetscFunctionBegin; 1937 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1938 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1939 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1940 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1941 if (ishdf5) { 1942 #if defined(PETSC_HAVE_HDF5) 1943 IS globalPointNumbering; 1944 PetscViewerFormat format; 1945 1946 PetscCall(PetscViewerGetFormat(viewer, &format)); 1947 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1948 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1949 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1950 PetscCall(ISDestroy(&globalPointNumbering)); 1951 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1952 #else 1953 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1954 #endif 1955 } 1956 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1957 PetscFunctionReturn(0); 1958 } 1959 1960 /*@ 1961 DMPlexSectionView - Saves a section associated with a `DMPLEX` 1962 1963 Collective on dm 1964 1965 Input Parameters: 1966 + dm - The `DM` that contains the topology on which the section to be saved is defined 1967 . viewer - The `PetscViewer` for saving 1968 - sectiondm - The `DM` that contains the section to be saved 1969 1970 Level: advanced 1971 1972 Notes: 1973 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. 1974 1975 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. 1976 1977 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()`, `PetscViewer` 1978 @*/ 1979 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1980 { 1981 PetscBool ishdf5; 1982 1983 PetscFunctionBegin; 1984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1985 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1986 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1987 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1988 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1989 if (ishdf5) { 1990 #if defined(PETSC_HAVE_HDF5) 1991 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1992 #else 1993 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1994 #endif 1995 } 1996 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1997 PetscFunctionReturn(0); 1998 } 1999 2000 /*@ 2001 DMPlexGlobalVectorView - Saves a global vector 2002 2003 Collective on dm 2004 2005 Input Parameters: 2006 + dm - The `DM` that represents the topology 2007 . viewer - The `PetscViewer` to save data with 2008 . sectiondm - The `DM` that contains the global section on which vec is defined 2009 - vec - The global vector to be saved 2010 2011 Level: advanced 2012 2013 Notes: 2014 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. 2015 2016 Typical calling sequence: 2017 .vb 2018 DMCreate(PETSC_COMM_WORLD, &dm); 2019 DMSetType(dm, DMPLEX); 2020 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2021 DMClone(dm, §iondm); 2022 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2023 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2024 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2025 PetscSectionSetChart(section, pStart, pEnd); 2026 PetscSectionSetUp(section); 2027 DMSetLocalSection(sectiondm, section); 2028 PetscSectionDestroy(§ion); 2029 DMGetGlobalVector(sectiondm, &vec); 2030 PetscObjectSetName((PetscObject)vec, "vec_name"); 2031 DMPlexTopologyView(dm, viewer); 2032 DMPlexSectionView(dm, viewer, sectiondm); 2033 DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2034 DMRestoreGlobalVector(sectiondm, &vec); 2035 DMDestroy(§iondm); 2036 DMDestroy(&dm); 2037 .ve 2038 2039 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2040 @*/ 2041 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2042 { 2043 PetscBool ishdf5; 2044 2045 PetscFunctionBegin; 2046 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2047 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2048 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2049 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2050 /* Check consistency */ 2051 { 2052 PetscSection section; 2053 PetscBool includesConstraints; 2054 PetscInt m, m1; 2055 2056 PetscCall(VecGetLocalSize(vec, &m1)); 2057 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2058 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2059 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2060 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2061 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2062 } 2063 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2064 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2065 if (ishdf5) { 2066 #if defined(PETSC_HAVE_HDF5) 2067 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2068 #else 2069 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2070 #endif 2071 } 2072 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2073 PetscFunctionReturn(0); 2074 } 2075 2076 /*@ 2077 DMPlexLocalVectorView - Saves a local vector 2078 2079 Collective on dm 2080 2081 Input Parameters: 2082 + dm - The `DM` that represents the topology 2083 . viewer - The `PetscViewer` to save data with 2084 . sectiondm - The `DM` that contains the local section on which vec is defined; may be the same as dm 2085 - vec - The local vector to be saved 2086 2087 Level: advanced 2088 2089 Note: 2090 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. 2091 2092 Typical calling sequence: 2093 .vb 2094 DMCreate(PETSC_COMM_WORLD, &dm); 2095 DMSetType(dm, DMPLEX); 2096 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2097 DMClone(dm, §iondm); 2098 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2099 PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2100 DMPlexGetChart(sectiondm, &pStart, &pEnd); 2101 PetscSectionSetChart(section, pStart, pEnd); 2102 PetscSectionSetUp(section); 2103 DMSetLocalSection(sectiondm, section); 2104 DMGetLocalVector(sectiondm, &vec); 2105 PetscObjectSetName((PetscObject)vec, "vec_name"); 2106 DMPlexTopologyView(dm, viewer); 2107 DMPlexSectionView(dm, viewer, sectiondm); 2108 DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2109 DMRestoreLocalVector(sectiondm, &vec); 2110 DMDestroy(§iondm); 2111 DMDestroy(&dm); 2112 .ve 2113 2114 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2115 @*/ 2116 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2117 { 2118 PetscBool ishdf5; 2119 2120 PetscFunctionBegin; 2121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2122 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2123 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2124 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2125 /* Check consistency */ 2126 { 2127 PetscSection section; 2128 PetscBool includesConstraints; 2129 PetscInt m, m1; 2130 2131 PetscCall(VecGetLocalSize(vec, &m1)); 2132 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2133 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2134 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2135 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2136 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2137 } 2138 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2139 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2140 if (ishdf5) { 2141 #if defined(PETSC_HAVE_HDF5) 2142 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2143 #else 2144 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2145 #endif 2146 } 2147 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2148 PetscFunctionReturn(0); 2149 } 2150 2151 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2152 { 2153 PetscBool ishdf5; 2154 2155 PetscFunctionBegin; 2156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2157 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2158 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2159 if (ishdf5) { 2160 #if defined(PETSC_HAVE_HDF5) 2161 PetscViewerFormat format; 2162 PetscCall(PetscViewerGetFormat(viewer, &format)); 2163 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2164 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2165 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2166 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2167 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2168 PetscFunctionReturn(0); 2169 #else 2170 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2171 #endif 2172 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2173 } 2174 2175 /*@ 2176 DMPlexTopologyLoad - Loads a topology into a `DMPLEX` 2177 2178 Collective on dm 2179 2180 Input Parameters: 2181 + dm - The `DM` into which the topology is loaded 2182 - viewer - The `PetscViewer` for the saved topology 2183 2184 Output Parameters: 2185 . 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 2186 2187 Level: advanced 2188 2189 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2190 `PetscViewer`, `PetscSF` 2191 @*/ 2192 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2193 { 2194 PetscBool ishdf5; 2195 2196 PetscFunctionBegin; 2197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2198 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2199 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2200 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2201 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2202 if (ishdf5) { 2203 #if defined(PETSC_HAVE_HDF5) 2204 PetscViewerFormat format; 2205 PetscCall(PetscViewerGetFormat(viewer, &format)); 2206 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2207 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2208 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2209 #else 2210 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2211 #endif 2212 } 2213 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2214 PetscFunctionReturn(0); 2215 } 2216 2217 /*@ 2218 DMPlexCoordinatesLoad - Loads coordinates into a `DMPLEX` 2219 2220 Collective on dm 2221 2222 Input Parameters: 2223 + dm - The `DM` into which the coordinates are loaded 2224 . viewer - The `PetscViewer` for the saved coordinates 2225 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2226 2227 Level: advanced 2228 2229 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2230 `PetscSF`, `PetscViewer` 2231 @*/ 2232 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2233 { 2234 PetscBool ishdf5; 2235 2236 PetscFunctionBegin; 2237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2238 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2239 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2240 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2241 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2242 if (ishdf5) { 2243 #if defined(PETSC_HAVE_HDF5) 2244 PetscViewerFormat format; 2245 PetscCall(PetscViewerGetFormat(viewer, &format)); 2246 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2247 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2248 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2249 #else 2250 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2251 #endif 2252 } 2253 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2254 PetscFunctionReturn(0); 2255 } 2256 2257 /*@ 2258 DMPlexLabelsLoad - Loads labels into a `DMPLEX` 2259 2260 Collective on dm 2261 2262 Input Parameters: 2263 + dm - The `DM` into which the labels are loaded 2264 . viewer - The `PetscViewer` for the saved labels 2265 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad()` when loading dm from viewer 2266 2267 Level: advanced 2268 2269 Note: 2270 The `PetscSF` argument must not be NULL if the `DM` is distributed, otherwise an error occurs. 2271 2272 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()`, 2273 `PetscSF`, `PetscViewer` 2274 @*/ 2275 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2276 { 2277 PetscBool ishdf5; 2278 2279 PetscFunctionBegin; 2280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2281 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2282 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2284 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2285 if (ishdf5) { 2286 #if defined(PETSC_HAVE_HDF5) 2287 PetscViewerFormat format; 2288 2289 PetscCall(PetscViewerGetFormat(viewer, &format)); 2290 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2291 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2292 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2293 #else 2294 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2295 #endif 2296 } 2297 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2298 PetscFunctionReturn(0); 2299 } 2300 2301 /*@ 2302 DMPlexSectionLoad - Loads section into a `DMPLEX` 2303 2304 Collective on dm 2305 2306 Input Parameters: 2307 + dm - The `DM` that represents the topology 2308 . viewer - The `PetscViewer` that represents the on-disk section (sectionA) 2309 . sectiondm - The `DM` into which the on-disk section (sectionA) is migrated 2310 - globalToLocalPointSF - The `PetscSF` returned by `DMPlexTopologyLoad(`) when loading dm from viewer 2311 2312 Output Parameters 2313 + 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) 2314 - 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) 2315 2316 Level: advanced 2317 2318 Notes: 2319 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. 2320 2321 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. 2322 2323 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. 2324 2325 Example using 2 processes: 2326 .vb 2327 NX (number of points on dm): 4 2328 sectionA : the on-disk section 2329 vecA : a vector associated with sectionA 2330 sectionB : sectiondm's local section constructed in this function 2331 vecB (local) : a vector associated with sectiondm's local section 2332 vecB (global) : a vector associated with sectiondm's global section 2333 2334 rank 0 rank 1 2335 vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2336 sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2337 sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2338 sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2339 [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2340 sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2341 sectionB->atlasDof : 1 0 1 | 1 3 2342 sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2343 vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2344 vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2345 .ve 2346 where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2347 2348 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()`, `PetscSF`, `PetscViewer` 2349 @*/ 2350 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2351 { 2352 PetscBool ishdf5; 2353 2354 PetscFunctionBegin; 2355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2356 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2357 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2358 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2359 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2360 if (localDofSF) PetscValidPointer(localDofSF, 6); 2361 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2362 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2363 if (ishdf5) { 2364 #if defined(PETSC_HAVE_HDF5) 2365 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2366 #else 2367 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2368 #endif 2369 } 2370 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2371 PetscFunctionReturn(0); 2372 } 2373 2374 /*@ 2375 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2376 2377 Collective on dm 2378 2379 Input Parameters: 2380 + dm - The `DM` that represents the topology 2381 . viewer - The `PetscViewer` that represents the on-disk vector data 2382 . sectiondm - The `DM` that contains the global section on which vec is defined 2383 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2384 - vec - The global vector to set values of 2385 2386 Level: advanced 2387 2388 Notes: 2389 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. 2390 2391 Typical calling sequence: 2392 .vb 2393 DMCreate(PETSC_COMM_WORLD, &dm); 2394 DMSetType(dm, DMPLEX); 2395 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2396 DMPlexTopologyLoad(dm, viewer, &sfX); 2397 DMClone(dm, §iondm); 2398 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2399 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2400 DMGetGlobalVector(sectiondm, &vec); 2401 PetscObjectSetName((PetscObject)vec, "vec_name"); 2402 DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2403 DMRestoreGlobalVector(sectiondm, &vec); 2404 PetscSFDestroy(&gsf); 2405 PetscSFDestroy(&sfX); 2406 DMDestroy(§iondm); 2407 DMDestroy(&dm); 2408 .ve 2409 2410 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2411 `PetscSF`, `PetscViewer` 2412 @*/ 2413 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2414 { 2415 PetscBool ishdf5; 2416 2417 PetscFunctionBegin; 2418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2419 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2420 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2421 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2422 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2423 /* Check consistency */ 2424 { 2425 PetscSection section; 2426 PetscBool includesConstraints; 2427 PetscInt m, m1; 2428 2429 PetscCall(VecGetLocalSize(vec, &m1)); 2430 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2431 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2432 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2433 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2434 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2435 } 2436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2437 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2438 if (ishdf5) { 2439 #if defined(PETSC_HAVE_HDF5) 2440 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2441 #else 2442 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2443 #endif 2444 } 2445 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2446 PetscFunctionReturn(0); 2447 } 2448 2449 /*@ 2450 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2451 2452 Collective on dm 2453 2454 Input Parameters: 2455 + dm - The `DM` that represents the topology 2456 . viewer - The `PetscViewer` that represents the on-disk vector data 2457 . sectiondm - The `DM` that contains the local section on which vec is defined 2458 . sf - The `PetscSF` that migrates the on-disk vector data into vec 2459 - vec - The local vector to set values of 2460 2461 Level: advanced 2462 2463 Notes: 2464 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. 2465 2466 Typical calling sequence: 2467 .vb 2468 DMCreate(PETSC_COMM_WORLD, &dm); 2469 DMSetType(dm, DMPLEX); 2470 PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2471 DMPlexTopologyLoad(dm, viewer, &sfX); 2472 DMClone(dm, §iondm); 2473 PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2474 DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2475 DMGetLocalVector(sectiondm, &vec); 2476 PetscObjectSetName((PetscObject)vec, "vec_name"); 2477 DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2478 DMRestoreLocalVector(sectiondm, &vec); 2479 PetscSFDestroy(&lsf); 2480 PetscSFDestroy(&sfX); 2481 DMDestroy(§iondm); 2482 DMDestroy(&dm); 2483 .ve 2484 2485 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, 2486 `PetscSF`, `PetscViewer` 2487 @*/ 2488 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2489 { 2490 PetscBool ishdf5; 2491 2492 PetscFunctionBegin; 2493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2494 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2495 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2496 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2497 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2498 /* Check consistency */ 2499 { 2500 PetscSection section; 2501 PetscBool includesConstraints; 2502 PetscInt m, m1; 2503 2504 PetscCall(VecGetLocalSize(vec, &m1)); 2505 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2506 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2507 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2508 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2509 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2510 } 2511 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2512 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2513 if (ishdf5) { 2514 #if defined(PETSC_HAVE_HDF5) 2515 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2516 #else 2517 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2518 #endif 2519 } 2520 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2521 PetscFunctionReturn(0); 2522 } 2523 2524 PetscErrorCode DMDestroy_Plex(DM dm) 2525 { 2526 DM_Plex *mesh = (DM_Plex *)dm->data; 2527 2528 PetscFunctionBegin; 2529 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2530 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2531 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2532 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2533 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2534 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2535 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2536 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2537 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2538 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2539 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2540 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2541 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2542 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", NULL)); 2543 if (--mesh->refct > 0) PetscFunctionReturn(0); 2544 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2545 PetscCall(PetscFree(mesh->cones)); 2546 PetscCall(PetscFree(mesh->coneOrientations)); 2547 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2548 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2549 PetscCall(PetscFree(mesh->supports)); 2550 PetscCall(DMPlexTransformDestroy(&mesh->tr)); 2551 PetscCall(PetscFree(mesh->facesTmp)); 2552 PetscCall(PetscFree(mesh->tetgenOpts)); 2553 PetscCall(PetscFree(mesh->triangleOpts)); 2554 PetscCall(PetscFree(mesh->transformType)); 2555 PetscCall(PetscFree(mesh->distributionName)); 2556 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2557 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2558 PetscCall(ISDestroy(&mesh->subpointIS)); 2559 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2560 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2561 PetscCall(PetscSFDestroy(&mesh->periodic.face_sf)); 2562 PetscCall(PetscSFDestroy(&mesh->periodic.composed_sf)); 2563 PetscCall(ISDestroy(&mesh->periodic.periodic_points)); 2564 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2565 PetscCall(ISDestroy(&mesh->anchorIS)); 2566 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2567 PetscCall(PetscFree(mesh->parents)); 2568 PetscCall(PetscFree(mesh->childIDs)); 2569 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2570 PetscCall(PetscFree(mesh->children)); 2571 PetscCall(DMDestroy(&mesh->referenceTree)); 2572 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2573 PetscCall(PetscFree(mesh->neighbors)); 2574 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2575 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2576 PetscCall(PetscFree(mesh)); 2577 PetscFunctionReturn(0); 2578 } 2579 2580 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2581 { 2582 PetscSection sectionGlobal; 2583 PetscInt bs = -1, mbs; 2584 PetscInt localSize, localStart = 0; 2585 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2586 MatType mtype; 2587 ISLocalToGlobalMapping ltog; 2588 2589 PetscFunctionBegin; 2590 PetscCall(MatInitializePackage()); 2591 mtype = dm->mattype; 2592 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2593 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2594 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2595 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2596 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2597 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2598 PetscCall(MatSetType(*J, mtype)); 2599 PetscCall(MatSetFromOptions(*J)); 2600 PetscCall(MatGetBlockSize(*J, &mbs)); 2601 if (mbs > 1) bs = mbs; 2602 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2603 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2604 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2605 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2606 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2607 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2608 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2609 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2610 if (!isShell) { 2611 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2612 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2613 PetscInt pStart, pEnd, p, dof, cdof; 2614 2615 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2616 2617 PetscCall(PetscCalloc1(localSize, &pblocks)); 2618 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2619 for (p = pStart; p < pEnd; ++p) { 2620 PetscInt bdof, offset; 2621 2622 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2623 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2624 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2625 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2626 dof = dof < 0 ? -(dof + 1) : dof; 2627 bdof = cdof && (dof - cdof) ? 1 : dof; 2628 if (dof) { 2629 if (bs < 0) { 2630 bs = bdof; 2631 } else if (bs != bdof) { 2632 bs = 1; 2633 } 2634 } 2635 } 2636 /* Must have same blocksize on all procs (some might have no points) */ 2637 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2638 bsLocal[1] = bs; 2639 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2640 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2641 else bs = bsMinMax[0]; 2642 bs = PetscMax(1, bs); 2643 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2644 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2645 PetscCall(MatSetBlockSize(*J, bs)); 2646 PetscCall(MatSetUp(*J)); 2647 } else { 2648 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2649 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2650 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2651 } 2652 { // Consolidate blocks 2653 PetscInt nblocks = 0; 2654 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2655 if (pblocks[i] == 0) continue; 2656 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2657 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]); 2658 } 2659 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2660 } 2661 PetscCall(PetscFree(pblocks)); 2662 } 2663 PetscCall(MatSetDM(*J, dm)); 2664 PetscFunctionReturn(0); 2665 } 2666 2667 /*@ 2668 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2669 2670 Not Collective 2671 2672 Input Parameter: 2673 . mesh - The `DMPLEX` 2674 2675 Output Parameters: 2676 . subsection - The subdomain section 2677 2678 Level: developer 2679 2680 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSection` 2681 @*/ 2682 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2683 { 2684 DM_Plex *mesh = (DM_Plex *)dm->data; 2685 2686 PetscFunctionBegin; 2687 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2688 if (!mesh->subdomainSection) { 2689 PetscSection section; 2690 PetscSF sf; 2691 2692 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2693 PetscCall(DMGetLocalSection(dm, §ion)); 2694 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2695 PetscCall(PetscSFDestroy(&sf)); 2696 } 2697 *subsection = mesh->subdomainSection; 2698 PetscFunctionReturn(0); 2699 } 2700 2701 /*@ 2702 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2703 2704 Not Collective 2705 2706 Input Parameter: 2707 . mesh - The `DMPLEX` 2708 2709 Output Parameters: 2710 + pStart - The first mesh point 2711 - pEnd - The upper bound for mesh points 2712 2713 Level: beginner 2714 2715 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()` 2716 @*/ 2717 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2718 { 2719 DM_Plex *mesh = (DM_Plex *)dm->data; 2720 2721 PetscFunctionBegin; 2722 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2723 if (mesh->tr) PetscCall(DMPlexTransformGetChart(mesh->tr, pStart, pEnd)); 2724 else PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2725 PetscFunctionReturn(0); 2726 } 2727 2728 /*@ 2729 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2730 2731 Not Collective 2732 2733 Input Parameters: 2734 + mesh - The `DMPLEX` 2735 . pStart - The first mesh point 2736 - pEnd - The upper bound for mesh points 2737 2738 Level: beginner 2739 2740 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetChart()` 2741 @*/ 2742 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2743 { 2744 DM_Plex *mesh = (DM_Plex *)dm->data; 2745 2746 PetscFunctionBegin; 2747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2748 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2749 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2750 PetscFunctionReturn(0); 2751 } 2752 2753 /*@ 2754 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2755 2756 Not Collective 2757 2758 Input Parameters: 2759 + mesh - The `DMPLEX` 2760 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2761 2762 Output Parameter: 2763 . size - The cone size for point p 2764 2765 Level: beginner 2766 2767 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2768 @*/ 2769 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2770 { 2771 DM_Plex *mesh = (DM_Plex *)dm->data; 2772 2773 PetscFunctionBegin; 2774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2775 PetscValidIntPointer(size, 3); 2776 if (mesh->tr) PetscCall(DMPlexTransformGetConeSize(mesh->tr, p, size)); 2777 else PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2778 PetscFunctionReturn(0); 2779 } 2780 2781 /*@ 2782 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2783 2784 Not Collective 2785 2786 Input Parameters: 2787 + mesh - The `DMPLEX` 2788 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 2789 - size - The cone size for point p 2790 2791 Level: beginner 2792 2793 Note: 2794 This should be called after `DMPlexSetChart()`. 2795 2796 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2797 @*/ 2798 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2799 { 2800 DM_Plex *mesh = (DM_Plex *)dm->data; 2801 2802 PetscFunctionBegin; 2803 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2804 PetscCheck(!mesh->tr, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot call DMPlexSetConeSize() on a mesh with a transform defined."); 2805 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2806 PetscFunctionReturn(0); 2807 } 2808 2809 /*@C 2810 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2811 2812 Not Collective 2813 2814 Input Parameters: 2815 + dm - The `DMPLEX` 2816 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 2817 2818 Output Parameter: 2819 . cone - An array of points which are on the in-edges for point p 2820 2821 Level: beginner 2822 2823 Fortran Note: 2824 You must also call `DMPlexRestoreCone()` after you finish using the returned array. 2825 `DMPlexRestoreCone()` is not needed/available in C. 2826 2827 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()`, `DMPlexRestoreCone()` 2828 @*/ 2829 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2830 { 2831 DM_Plex *mesh = (DM_Plex *)dm->data; 2832 PetscInt off; 2833 2834 PetscFunctionBegin; 2835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2836 PetscValidPointer(cone, 3); 2837 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2838 *cone = &mesh->cones[off]; 2839 PetscFunctionReturn(0); 2840 } 2841 2842 /*@C 2843 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2844 2845 Not Collective 2846 2847 Input Parameters: 2848 + dm - The `DMPLEX` 2849 - p - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2850 2851 Output Parameters: 2852 + pConesSection - `PetscSection` describing the layout of pCones 2853 - pCones - An array of points which are on the in-edges for the point set p 2854 2855 Level: intermediate 2856 2857 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()`, `PetscSection`, `IS` 2858 @*/ 2859 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2860 { 2861 PetscSection cs, newcs; 2862 PetscInt *cones; 2863 PetscInt *newarr = NULL; 2864 PetscInt n; 2865 2866 PetscFunctionBegin; 2867 PetscCall(DMPlexGetCones(dm, &cones)); 2868 PetscCall(DMPlexGetConeSection(dm, &cs)); 2869 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2870 if (pConesSection) *pConesSection = newcs; 2871 if (pCones) { 2872 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2873 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2874 } 2875 PetscFunctionReturn(0); 2876 } 2877 2878 /*@ 2879 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2880 2881 Not Collective 2882 2883 Input Parameters: 2884 + dm - The `DMPLEX` 2885 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2886 2887 Output Parameter: 2888 . expandedPoints - An array of vertices recursively expanded from input points 2889 2890 Level: advanced 2891 2892 Notes: 2893 Like `DMPlexGetConeRecursive()` but returns only the 0-depth IS (i.e. vertices only) and no sections. 2894 2895 There is no corresponding Restore function, just call `ISDestroy()` on the returned `IS` to deallocate. 2896 2897 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, 2898 `DMPlexGetDepth()`, `IS` 2899 @*/ 2900 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2901 { 2902 IS *expandedPointsAll; 2903 PetscInt depth; 2904 2905 PetscFunctionBegin; 2906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2907 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2908 PetscValidPointer(expandedPoints, 3); 2909 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2910 *expandedPoints = expandedPointsAll[0]; 2911 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2912 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2913 PetscFunctionReturn(0); 2914 } 2915 2916 /*@ 2917 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). 2918 2919 Not Collective 2920 2921 Input Parameters: 2922 + dm - The `DMPLEX` 2923 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 2924 2925 Output Parameters: 2926 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 2927 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2928 - sections - (optional) An array of sections which describe mappings from points to their cone points 2929 2930 Level: advanced 2931 2932 Notes: 2933 Like `DMPlexGetConeTuple()` but recursive. 2934 2935 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. 2936 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2937 2938 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: 2939 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2940 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2941 2942 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 2943 `DMPlexGetDepth()`, `PetscSection`, `IS` 2944 @*/ 2945 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2946 { 2947 const PetscInt *arr0 = NULL, *cone = NULL; 2948 PetscInt *arr = NULL, *newarr = NULL; 2949 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2950 IS *expandedPoints_; 2951 PetscSection *sections_; 2952 2953 PetscFunctionBegin; 2954 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2955 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2956 if (depth) PetscValidIntPointer(depth, 3); 2957 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2958 if (sections) PetscValidPointer(sections, 5); 2959 PetscCall(ISGetLocalSize(points, &n)); 2960 PetscCall(ISGetIndices(points, &arr0)); 2961 PetscCall(DMPlexGetDepth(dm, &depth_)); 2962 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2963 PetscCall(PetscCalloc1(depth_, §ions_)); 2964 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2965 for (d = depth_ - 1; d >= 0; d--) { 2966 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2967 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2968 for (i = 0; i < n; i++) { 2969 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2970 if (arr[i] >= start && arr[i] < end) { 2971 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2972 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2973 } else { 2974 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2975 } 2976 } 2977 PetscCall(PetscSectionSetUp(sections_[d])); 2978 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2979 PetscCall(PetscMalloc1(newn, &newarr)); 2980 for (i = 0; i < n; i++) { 2981 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2982 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2983 if (cn > 1) { 2984 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2985 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2986 } else { 2987 newarr[co] = arr[i]; 2988 } 2989 } 2990 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2991 arr = newarr; 2992 n = newn; 2993 } 2994 PetscCall(ISRestoreIndices(points, &arr0)); 2995 *depth = depth_; 2996 if (expandedPoints) *expandedPoints = expandedPoints_; 2997 else { 2998 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2999 PetscCall(PetscFree(expandedPoints_)); 3000 } 3001 if (sections) *sections = sections_; 3002 else { 3003 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 3004 PetscCall(PetscFree(sections_)); 3005 } 3006 PetscFunctionReturn(0); 3007 } 3008 3009 /*@ 3010 DMPlexRestoreConeRecursive - Deallocates arrays created by `DMPlexGetConeRecursive()` 3011 3012 Not Collective 3013 3014 Input Parameters: 3015 + dm - The `DMPLEX` 3016 - points - The `IS` of points, which must lie in the chart set with `DMPlexSetChart()` 3017 3018 Output Parameters: 3019 + depth - (optional) Size of the output arrays, equal to `DMPLEX` depth, returned by `DMPlexGetDepth()` 3020 . expandedPoints - (optional) An array of recursively expanded cones 3021 - sections - (optional) An array of sections which describe mappings from points to their cone points 3022 3023 Level: advanced 3024 3025 Note: 3026 See `DMPlexGetConeRecursive()` 3027 3028 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, 3029 `DMPlexGetDepth()`, `IS`, `PetscSection` 3030 @*/ 3031 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3032 { 3033 PetscInt d, depth_; 3034 3035 PetscFunctionBegin; 3036 PetscCall(DMPlexGetDepth(dm, &depth_)); 3037 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3038 if (depth) *depth = 0; 3039 if (expandedPoints) { 3040 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3041 PetscCall(PetscFree(*expandedPoints)); 3042 } 3043 if (sections) { 3044 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3045 PetscCall(PetscFree(*sections)); 3046 } 3047 PetscFunctionReturn(0); 3048 } 3049 3050 /*@ 3051 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 3052 3053 Not Collective 3054 3055 Input Parameters: 3056 + mesh - The `DMPLEX` 3057 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3058 - cone - An array of points which are on the in-edges for point p 3059 3060 Level: beginner 3061 3062 Note: 3063 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3064 3065 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3066 @*/ 3067 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3068 { 3069 DM_Plex *mesh = (DM_Plex *)dm->data; 3070 PetscInt pStart, pEnd; 3071 PetscInt dof, off, c; 3072 3073 PetscFunctionBegin; 3074 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3075 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3076 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3077 if (dof) PetscValidIntPointer(cone, 3); 3078 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3079 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); 3080 for (c = 0; c < dof; ++c) { 3081 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); 3082 mesh->cones[off + c] = cone[c]; 3083 } 3084 PetscFunctionReturn(0); 3085 } 3086 3087 /*@C 3088 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3089 3090 Not Collective 3091 3092 Input Parameters: 3093 + mesh - The `DMPLEX` 3094 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3095 3096 Output Parameter: 3097 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3098 integer giving the prescription for cone traversal. 3099 3100 Level: beginner 3101 3102 Note: 3103 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3104 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3105 of o, however it is not necessarily the inverse. To get the inverse, use `DMPolytopeTypeComposeOrientationInv()` 3106 with the identity. 3107 3108 Fortran Note: 3109 You must also call `DMPlexRestoreConeOrientation()` after you finish using the returned array. 3110 `DMPlexRestoreConeOrientation()` is not needed/available in C. 3111 3112 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3113 @*/ 3114 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3115 { 3116 DM_Plex *mesh = (DM_Plex *)dm->data; 3117 PetscInt off; 3118 3119 PetscFunctionBegin; 3120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3121 if (PetscDefined(USE_DEBUG)) { 3122 PetscInt dof; 3123 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3124 if (dof) PetscValidPointer(coneOrientation, 3); 3125 } 3126 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3127 3128 *coneOrientation = &mesh->coneOrientations[off]; 3129 PetscFunctionReturn(0); 3130 } 3131 3132 /*@ 3133 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3134 3135 Not Collective 3136 3137 Input Parameters: 3138 + mesh - The `DMPLEX` 3139 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3140 - coneOrientation - An array of orientations 3141 3142 Level: beginner 3143 3144 Notes: 3145 This should be called after all calls to `DMPlexSetConeSize()` and `DMSetUp()`. 3146 3147 The meaning of coneOrientation is detailed in `DMPlexGetConeOrientation()`. 3148 3149 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3150 @*/ 3151 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3152 { 3153 DM_Plex *mesh = (DM_Plex *)dm->data; 3154 PetscInt pStart, pEnd; 3155 PetscInt dof, off, c; 3156 3157 PetscFunctionBegin; 3158 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3159 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3160 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3161 if (dof) PetscValidIntPointer(coneOrientation, 3); 3162 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3163 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); 3164 for (c = 0; c < dof; ++c) { 3165 PetscInt cdof, o = coneOrientation[c]; 3166 3167 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3168 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); 3169 mesh->coneOrientations[off + c] = o; 3170 } 3171 PetscFunctionReturn(0); 3172 } 3173 3174 /*@ 3175 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3176 3177 Not Collective 3178 3179 Input Parameters: 3180 + mesh - The `DMPLEX` 3181 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3182 . conePos - The local index in the cone where the point should be put 3183 - conePoint - The mesh point to insert 3184 3185 Level: beginner 3186 3187 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3188 @*/ 3189 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3190 { 3191 DM_Plex *mesh = (DM_Plex *)dm->data; 3192 PetscInt pStart, pEnd; 3193 PetscInt dof, off; 3194 3195 PetscFunctionBegin; 3196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3197 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3198 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); 3199 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); 3200 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3201 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3202 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); 3203 mesh->cones[off + conePos] = conePoint; 3204 PetscFunctionReturn(0); 3205 } 3206 3207 /*@ 3208 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3209 3210 Not Collective 3211 3212 Input Parameters: 3213 + mesh - The `DMPLEX` 3214 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3215 . conePos - The local index in the cone where the point should be put 3216 - coneOrientation - The point orientation to insert 3217 3218 Level: beginner 3219 3220 Note: 3221 The meaning of coneOrientation values is detailed in `DMPlexGetConeOrientation()`. 3222 3223 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3224 @*/ 3225 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3226 { 3227 DM_Plex *mesh = (DM_Plex *)dm->data; 3228 PetscInt pStart, pEnd; 3229 PetscInt dof, off; 3230 3231 PetscFunctionBegin; 3232 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3233 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3234 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); 3235 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3236 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3237 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); 3238 mesh->coneOrientations[off + conePos] = coneOrientation; 3239 PetscFunctionReturn(0); 3240 } 3241 3242 /*@C 3243 DMPlexGetOrientedCone - Return the points and orientations on the in-edges for this point in the DAG 3244 3245 Not collective 3246 3247 Input Parameters: 3248 + dm - The DMPlex 3249 - p - The point, which must lie in the chart set with DMPlexSetChart() 3250 3251 Output Parameters: 3252 + cone - An array of points which are on the in-edges for point p 3253 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3254 integer giving the prescription for cone traversal. 3255 3256 Level: beginner 3257 3258 Notes: 3259 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3260 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3261 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3262 with the identity. 3263 3264 Fortran Notes: 3265 Since it returns an array, this routine is only available in Fortran 90, and you must 3266 include petsc.h90 in your code. 3267 You must also call DMPlexRestoreCone() after you finish using the returned array. 3268 DMPlexRestoreCone() is not needed/available in C. 3269 3270 .seealso: `DMPlexRestoreOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3271 @*/ 3272 PetscErrorCode DMPlexGetOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3273 { 3274 DM_Plex *mesh = (DM_Plex *)dm->data; 3275 3276 PetscFunctionBegin; 3277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3278 if (mesh->tr) { 3279 PetscCall(DMPlexTransformGetCone(mesh->tr, p, cone, ornt)); 3280 } else { 3281 PetscInt off; 3282 if (PetscDefined(USE_DEBUG)) { 3283 PetscInt dof; 3284 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3285 if (dof) { 3286 if (cone) PetscValidPointer(cone, 3); 3287 if (ornt) PetscValidPointer(ornt, 4); 3288 } 3289 } 3290 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3291 if (cone) *cone = &mesh->cones[off]; 3292 if (ornt) *ornt = &mesh->coneOrientations[off]; 3293 } 3294 PetscFunctionReturn(0); 3295 } 3296 3297 /*@C 3298 DMPlexRestoreOrientedCone - Restore the points and orientations on the in-edges for this point in the DAG 3299 3300 Not collective 3301 3302 Input Parameters: 3303 + dm - The DMPlex 3304 . p - The point, which must lie in the chart set with DMPlexSetChart() 3305 . cone - An array of points which are on the in-edges for point p 3306 - ornt - An array of orientations which are on the in-edges for point p. An orientation is an 3307 integer giving the prescription for cone traversal. 3308 3309 Level: beginner 3310 3311 Notes: 3312 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3313 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3314 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3315 with the identity. 3316 3317 Fortran Notes: 3318 Since it returns an array, this routine is only available in Fortran 90, and you must 3319 include petsc.h90 in your code. 3320 You must also call DMPlexRestoreCone() after you finish using the returned array. 3321 DMPlexRestoreCone() is not needed/available in C. 3322 3323 .seealso: `DMPlexGetOrientedCone()`, `DMPlexGetConeSize()`, `DMPlexGetCone()`, `DMPlexGetChart()` 3324 @*/ 3325 PetscErrorCode DMPlexRestoreOrientedCone(DM dm, PetscInt p, const PetscInt *cone[], const PetscInt *ornt[]) 3326 { 3327 DM_Plex *mesh = (DM_Plex *)dm->data; 3328 3329 PetscFunctionBegin; 3330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3331 if (mesh->tr) PetscCall(DMPlexTransformRestoreCone(mesh->tr, p, cone, ornt)); 3332 PetscFunctionReturn(0); 3333 } 3334 3335 /*@ 3336 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3337 3338 Not Collective 3339 3340 Input Parameters: 3341 + mesh - The `DMPLEX` 3342 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3343 3344 Output Parameter: 3345 . size - The support size for point p 3346 3347 Level: beginner 3348 3349 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3350 @*/ 3351 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3352 { 3353 DM_Plex *mesh = (DM_Plex *)dm->data; 3354 3355 PetscFunctionBegin; 3356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3357 PetscValidIntPointer(size, 3); 3358 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3359 PetscFunctionReturn(0); 3360 } 3361 3362 /*@ 3363 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3364 3365 Not Collective 3366 3367 Input Parameters: 3368 + mesh - The `DMPLEX` 3369 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3370 - size - The support size for point p 3371 3372 Level: beginner 3373 3374 Note: 3375 This should be called after DMPlexSetChart(). 3376 3377 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3378 @*/ 3379 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3380 { 3381 DM_Plex *mesh = (DM_Plex *)dm->data; 3382 3383 PetscFunctionBegin; 3384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3385 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3386 PetscFunctionReturn(0); 3387 } 3388 3389 /*@C 3390 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3391 3392 Not Collective 3393 3394 Input Parameters: 3395 + mesh - The `DMPLEX` 3396 - p - The point, which must lie in the chart set with `DMPlexSetChart()` 3397 3398 Output Parameter: 3399 . support - An array of points which are on the out-edges for point p 3400 3401 Level: beginner 3402 3403 Fortran Note: 3404 You must also call `DMPlexRestoreSupport()` after you finish using the returned array. 3405 `DMPlexRestoreSupport()` is not needed/available in C. 3406 3407 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3408 @*/ 3409 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3410 { 3411 DM_Plex *mesh = (DM_Plex *)dm->data; 3412 PetscInt off; 3413 3414 PetscFunctionBegin; 3415 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3416 PetscValidPointer(support, 3); 3417 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3418 *support = &mesh->supports[off]; 3419 PetscFunctionReturn(0); 3420 } 3421 3422 /*@ 3423 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3424 3425 Not Collective 3426 3427 Input Parameters: 3428 + mesh - The `DMPLEX` 3429 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3430 - support - An array of points which are on the out-edges for point p 3431 3432 Level: beginner 3433 3434 Note: 3435 This should be called after all calls to `DMPlexSetSupportSize()` and `DMSetUp()`. 3436 3437 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3438 @*/ 3439 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3440 { 3441 DM_Plex *mesh = (DM_Plex *)dm->data; 3442 PetscInt pStart, pEnd; 3443 PetscInt dof, off, c; 3444 3445 PetscFunctionBegin; 3446 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3447 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3448 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3449 if (dof) PetscValidIntPointer(support, 3); 3450 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3451 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); 3452 for (c = 0; c < dof; ++c) { 3453 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); 3454 mesh->supports[off + c] = support[c]; 3455 } 3456 PetscFunctionReturn(0); 3457 } 3458 3459 /*@ 3460 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3461 3462 Not Collective 3463 3464 Input Parameters: 3465 + mesh - The `DMPLEX` 3466 . p - The point, which must lie in the chart set with `DMPlexSetChart()` 3467 . supportPos - The local index in the cone where the point should be put 3468 - supportPoint - The mesh point to insert 3469 3470 Level: beginner 3471 3472 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3473 @*/ 3474 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3475 { 3476 DM_Plex *mesh = (DM_Plex *)dm->data; 3477 PetscInt pStart, pEnd; 3478 PetscInt dof, off; 3479 3480 PetscFunctionBegin; 3481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3482 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3483 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3484 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3485 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); 3486 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); 3487 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); 3488 mesh->supports[off + supportPos] = supportPoint; 3489 PetscFunctionReturn(0); 3490 } 3491 3492 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3493 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3494 { 3495 switch (ct) { 3496 case DM_POLYTOPE_SEGMENT: 3497 if (o == -1) return -2; 3498 break; 3499 case DM_POLYTOPE_TRIANGLE: 3500 if (o == -3) return -1; 3501 if (o == -2) return -3; 3502 if (o == -1) return -2; 3503 break; 3504 case DM_POLYTOPE_QUADRILATERAL: 3505 if (o == -4) return -2; 3506 if (o == -3) return -1; 3507 if (o == -2) return -4; 3508 if (o == -1) return -3; 3509 break; 3510 default: 3511 return o; 3512 } 3513 return o; 3514 } 3515 3516 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3517 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3518 { 3519 switch (ct) { 3520 case DM_POLYTOPE_SEGMENT: 3521 if ((o == -2) || (o == 1)) return -1; 3522 if (o == -1) return 0; 3523 break; 3524 case DM_POLYTOPE_TRIANGLE: 3525 if (o == -3) return -2; 3526 if (o == -2) return -1; 3527 if (o == -1) return -3; 3528 break; 3529 case DM_POLYTOPE_QUADRILATERAL: 3530 if (o == -4) return -2; 3531 if (o == -3) return -1; 3532 if (o == -2) return -4; 3533 if (o == -1) return -3; 3534 break; 3535 default: 3536 return o; 3537 } 3538 return o; 3539 } 3540 3541 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3542 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3543 { 3544 PetscInt pStart, pEnd, p; 3545 3546 PetscFunctionBegin; 3547 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3548 for (p = pStart; p < pEnd; ++p) { 3549 const PetscInt *cone, *ornt; 3550 PetscInt coneSize, c; 3551 3552 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3553 PetscCall(DMPlexGetCone(dm, p, &cone)); 3554 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3555 for (c = 0; c < coneSize; ++c) { 3556 DMPolytopeType ct; 3557 const PetscInt o = ornt[c]; 3558 3559 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3560 switch (ct) { 3561 case DM_POLYTOPE_SEGMENT: 3562 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3563 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3564 break; 3565 case DM_POLYTOPE_TRIANGLE: 3566 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3567 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3568 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3569 break; 3570 case DM_POLYTOPE_QUADRILATERAL: 3571 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3572 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3573 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3574 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3575 break; 3576 default: 3577 break; 3578 } 3579 } 3580 } 3581 PetscFunctionReturn(0); 3582 } 3583 3584 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3585 { 3586 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3587 PetscInt *closure; 3588 const PetscInt *tmp = NULL, *tmpO = NULL; 3589 PetscInt off = 0, tmpSize, t; 3590 3591 PetscFunctionBeginHot; 3592 if (ornt) { 3593 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3594 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3595 } 3596 if (*points) { 3597 closure = *points; 3598 } else { 3599 PetscInt maxConeSize, maxSupportSize; 3600 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3601 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3602 } 3603 if (useCone) { 3604 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3605 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3606 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3607 } else { 3608 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3609 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3610 } 3611 if (ct == DM_POLYTOPE_UNKNOWN) { 3612 closure[off++] = p; 3613 closure[off++] = 0; 3614 for (t = 0; t < tmpSize; ++t) { 3615 closure[off++] = tmp[t]; 3616 closure[off++] = tmpO ? tmpO[t] : 0; 3617 } 3618 } else { 3619 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3620 3621 /* We assume that cells with a valid type have faces with a valid type */ 3622 closure[off++] = p; 3623 closure[off++] = ornt; 3624 for (t = 0; t < tmpSize; ++t) { 3625 DMPolytopeType ft; 3626 3627 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3628 closure[off++] = tmp[arr[t]]; 3629 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3630 } 3631 } 3632 if (numPoints) *numPoints = tmpSize + 1; 3633 if (points) *points = closure; 3634 PetscFunctionReturn(0); 3635 } 3636 3637 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3638 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3639 { 3640 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3641 const PetscInt *cone, *ornt; 3642 PetscInt *pts, *closure = NULL; 3643 DMPolytopeType ft; 3644 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3645 PetscInt dim, coneSize, c, d, clSize, cl; 3646 3647 PetscFunctionBeginHot; 3648 PetscCall(DMGetDimension(dm, &dim)); 3649 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3650 PetscCall(DMPlexGetCone(dm, point, &cone)); 3651 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3652 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3653 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3654 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3655 maxSize = PetscMax(coneSeries, supportSeries); 3656 if (*points) { 3657 pts = *points; 3658 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3659 c = 0; 3660 pts[c++] = point; 3661 pts[c++] = o; 3662 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3663 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3664 for (cl = 0; cl < clSize * 2; cl += 2) { 3665 pts[c++] = closure[cl]; 3666 pts[c++] = closure[cl + 1]; 3667 } 3668 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3669 for (cl = 0; cl < clSize * 2; cl += 2) { 3670 pts[c++] = closure[cl]; 3671 pts[c++] = closure[cl + 1]; 3672 } 3673 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3674 for (d = 2; d < coneSize; ++d) { 3675 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3676 pts[c++] = cone[arr[d * 2 + 0]]; 3677 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3678 } 3679 if (dim >= 3) { 3680 for (d = 2; d < coneSize; ++d) { 3681 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3682 const PetscInt *fcone, *fornt; 3683 PetscInt fconeSize, fc, i; 3684 3685 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3686 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3687 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3688 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3689 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3690 for (fc = 0; fc < fconeSize; ++fc) { 3691 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3692 const PetscInt co = farr[fc * 2 + 1]; 3693 3694 for (i = 0; i < c; i += 2) 3695 if (pts[i] == cp) break; 3696 if (i == c) { 3697 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3698 pts[c++] = cp; 3699 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3700 } 3701 } 3702 } 3703 } 3704 *numPoints = c / 2; 3705 *points = pts; 3706 PetscFunctionReturn(0); 3707 } 3708 3709 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3710 { 3711 DMPolytopeType ct; 3712 PetscInt *closure, *fifo; 3713 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3714 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3715 PetscInt depth, maxSize; 3716 3717 PetscFunctionBeginHot; 3718 PetscCall(DMPlexGetDepth(dm, &depth)); 3719 if (depth == 1) { 3720 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3721 PetscFunctionReturn(0); 3722 } 3723 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3724 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3725 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3726 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3727 PetscFunctionReturn(0); 3728 } 3729 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3730 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3731 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3732 maxSize = PetscMax(coneSeries, supportSeries); 3733 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3734 if (*points) { 3735 closure = *points; 3736 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3737 closure[closureSize++] = p; 3738 closure[closureSize++] = ornt; 3739 fifo[fifoSize++] = p; 3740 fifo[fifoSize++] = ornt; 3741 fifo[fifoSize++] = ct; 3742 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3743 while (fifoSize - fifoStart) { 3744 const PetscInt q = fifo[fifoStart++]; 3745 const PetscInt o = fifo[fifoStart++]; 3746 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3747 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3748 const PetscInt *tmp, *tmpO; 3749 PetscInt tmpSize, t; 3750 3751 if (PetscDefined(USE_DEBUG)) { 3752 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3753 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); 3754 } 3755 if (useCone) { 3756 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3757 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3758 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3759 } else { 3760 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3761 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3762 tmpO = NULL; 3763 } 3764 for (t = 0; t < tmpSize; ++t) { 3765 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3766 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3767 const PetscInt cp = tmp[ip]; 3768 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3769 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3770 PetscInt c; 3771 3772 /* Check for duplicate */ 3773 for (c = 0; c < closureSize; c += 2) { 3774 if (closure[c] == cp) break; 3775 } 3776 if (c == closureSize) { 3777 closure[closureSize++] = cp; 3778 closure[closureSize++] = co; 3779 fifo[fifoSize++] = cp; 3780 fifo[fifoSize++] = co; 3781 fifo[fifoSize++] = ct; 3782 } 3783 } 3784 } 3785 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3786 if (numPoints) *numPoints = closureSize / 2; 3787 if (points) *points = closure; 3788 PetscFunctionReturn(0); 3789 } 3790 3791 /*@C 3792 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3793 3794 Not Collective 3795 3796 Input Parameters: 3797 + dm - The `DMPLEX` 3798 . p - The mesh point 3799 - useCone - `PETSC_TRUE` for the closure, otherwise return the star 3800 3801 Input/Output Parameter: 3802 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3803 if NULL on input, internal storage will be returned, otherwise the provided array is used 3804 3805 Output Parameter: 3806 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3807 3808 Level: beginner 3809 3810 Note: 3811 If using internal storage (points is NULL on input), each call overwrites the last output. 3812 3813 Fortran Note: 3814 The numPoints argument is not present in the Fortran binding since it is internal to the array. 3815 3816 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3817 @*/ 3818 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3819 { 3820 PetscFunctionBeginHot; 3821 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3822 if (numPoints) PetscValidIntPointer(numPoints, 4); 3823 if (points) PetscValidPointer(points, 5); 3824 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3825 PetscFunctionReturn(0); 3826 } 3827 3828 /*@C 3829 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3830 3831 Not Collective 3832 3833 Input Parameters: 3834 + dm - The `DMPLEX` 3835 . p - The mesh point 3836 . useCone - `PETSC_TRUE` for the closure, otherwise return the star 3837 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3838 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3839 3840 Level: beginner 3841 3842 Note: 3843 If not using internal storage (points is not NULL on input), this call is unnecessary 3844 3845 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3846 @*/ 3847 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3848 { 3849 PetscFunctionBeginHot; 3850 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3851 if (numPoints) *numPoints = 0; 3852 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3853 PetscFunctionReturn(0); 3854 } 3855 3856 /*@ 3857 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3858 3859 Not Collective 3860 3861 Input Parameter: 3862 . mesh - The `DMPLEX` 3863 3864 Output Parameters: 3865 + maxConeSize - The maximum number of in-edges 3866 - maxSupportSize - The maximum number of out-edges 3867 3868 Level: beginner 3869 3870 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3871 @*/ 3872 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3873 { 3874 DM_Plex *mesh = (DM_Plex *)dm->data; 3875 3876 PetscFunctionBegin; 3877 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3878 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3879 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3880 PetscFunctionReturn(0); 3881 } 3882 3883 PetscErrorCode DMSetUp_Plex(DM dm) 3884 { 3885 DM_Plex *mesh = (DM_Plex *)dm->data; 3886 PetscInt size, maxSupportSize; 3887 3888 PetscFunctionBegin; 3889 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3890 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3891 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3892 PetscCall(PetscMalloc1(size, &mesh->cones)); 3893 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3894 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3895 if (maxSupportSize) { 3896 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3897 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3898 PetscCall(PetscMalloc1(size, &mesh->supports)); 3899 } 3900 PetscFunctionReturn(0); 3901 } 3902 3903 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3904 { 3905 PetscFunctionBegin; 3906 if (subdm) PetscCall(DMClone(dm, subdm)); 3907 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3908 if (subdm) (*subdm)->useNatural = dm->useNatural; 3909 if (dm->useNatural && dm->sfMigration) { 3910 PetscSF sfNatural; 3911 3912 (*subdm)->sfMigration = dm->sfMigration; 3913 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3914 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3915 (*subdm)->sfNatural = sfNatural; 3916 } 3917 PetscFunctionReturn(0); 3918 } 3919 3920 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3921 { 3922 PetscInt i = 0; 3923 3924 PetscFunctionBegin; 3925 PetscCall(DMClone(dms[0], superdm)); 3926 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3927 (*superdm)->useNatural = PETSC_FALSE; 3928 for (i = 0; i < len; i++) { 3929 if (dms[i]->useNatural && dms[i]->sfMigration) { 3930 PetscSF sfNatural; 3931 3932 (*superdm)->sfMigration = dms[i]->sfMigration; 3933 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3934 (*superdm)->useNatural = PETSC_TRUE; 3935 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3936 (*superdm)->sfNatural = sfNatural; 3937 break; 3938 } 3939 } 3940 PetscFunctionReturn(0); 3941 } 3942 3943 /*@ 3944 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3945 3946 Not Collective 3947 3948 Input Parameter: 3949 . mesh - The `DMPLEX` 3950 3951 Level: beginner 3952 3953 Note: 3954 This should be called after all calls to `DMPlexSetCone()` 3955 3956 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3957 @*/ 3958 PetscErrorCode DMPlexSymmetrize(DM dm) 3959 { 3960 DM_Plex *mesh = (DM_Plex *)dm->data; 3961 PetscInt *offsets; 3962 PetscInt supportSize; 3963 PetscInt pStart, pEnd, p; 3964 3965 PetscFunctionBegin; 3966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3967 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3968 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3969 /* Calculate support sizes */ 3970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3971 for (p = pStart; p < pEnd; ++p) { 3972 PetscInt dof, off, c; 3973 3974 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3975 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3976 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3977 } 3978 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3979 /* Calculate supports */ 3980 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3981 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3982 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3983 for (p = pStart; p < pEnd; ++p) { 3984 PetscInt dof, off, c; 3985 3986 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3987 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3988 for (c = off; c < off + dof; ++c) { 3989 const PetscInt q = mesh->cones[c]; 3990 PetscInt offS; 3991 3992 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3993 3994 mesh->supports[offS + offsets[q]] = p; 3995 ++offsets[q]; 3996 } 3997 } 3998 PetscCall(PetscFree(offsets)); 3999 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 4000 PetscFunctionReturn(0); 4001 } 4002 4003 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 4004 { 4005 IS stratumIS; 4006 4007 PetscFunctionBegin; 4008 if (pStart >= pEnd) PetscFunctionReturn(0); 4009 if (PetscDefined(USE_DEBUG)) { 4010 PetscInt qStart, qEnd, numLevels, level; 4011 PetscBool overlap = PETSC_FALSE; 4012 PetscCall(DMLabelGetNumValues(label, &numLevels)); 4013 for (level = 0; level < numLevels; level++) { 4014 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4015 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 4016 overlap = PETSC_TRUE; 4017 break; 4018 } 4019 } 4020 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); 4021 } 4022 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 4023 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 4024 PetscCall(ISDestroy(&stratumIS)); 4025 PetscFunctionReturn(0); 4026 } 4027 4028 /*@ 4029 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 4030 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 4031 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 4032 the DAG. 4033 4034 Collective on dm 4035 4036 Input Parameter: 4037 . mesh - The `DMPLEX` 4038 4039 Level: beginner 4040 4041 Notes: 4042 Concretely, `DMPlexStratify()` creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 4043 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 4044 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through `DMPlexGetDepthLabel()` or `DMPlexGetDepthStratum()`, or 4045 manually via `DMGetLabel()`. The height is defined implicitly by height = maxDimension - depth, and can be accessed 4046 via `DMPlexGetHeightStratum()`. For example, cells have height 0 and faces have height 1. 4047 4048 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 4049 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 4050 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 4051 to interpolate only that one (e0), so that 4052 .vb 4053 cone(c0) = {e0, v2} 4054 cone(e0) = {v0, v1} 4055 .ve 4056 If `DMPlexStratify()` is run on this mesh, it will give depths 4057 .vb 4058 depth 0 = {v0, v1, v2} 4059 depth 1 = {e0, c0} 4060 .ve 4061 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 4062 4063 `DMPlexStratify()` should be called after all calls to `DMPlexSymmetrize()` 4064 4065 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 4066 @*/ 4067 PetscErrorCode DMPlexStratify(DM dm) 4068 { 4069 DM_Plex *mesh = (DM_Plex *)dm->data; 4070 DMLabel label; 4071 PetscInt pStart, pEnd, p; 4072 PetscInt numRoots = 0, numLeaves = 0; 4073 4074 PetscFunctionBegin; 4075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4076 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 4077 4078 /* Create depth label */ 4079 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4080 PetscCall(DMCreateLabel(dm, "depth")); 4081 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4082 4083 { 4084 /* Initialize roots and count leaves */ 4085 PetscInt sMin = PETSC_MAX_INT; 4086 PetscInt sMax = PETSC_MIN_INT; 4087 PetscInt coneSize, supportSize; 4088 4089 for (p = pStart; p < pEnd; ++p) { 4090 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4091 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4092 if (!coneSize && supportSize) { 4093 sMin = PetscMin(p, sMin); 4094 sMax = PetscMax(p, sMax); 4095 ++numRoots; 4096 } else if (!supportSize && coneSize) { 4097 ++numLeaves; 4098 } else if (!supportSize && !coneSize) { 4099 /* Isolated points */ 4100 sMin = PetscMin(p, sMin); 4101 sMax = PetscMax(p, sMax); 4102 } 4103 } 4104 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4105 } 4106 4107 if (numRoots + numLeaves == (pEnd - pStart)) { 4108 PetscInt sMin = PETSC_MAX_INT; 4109 PetscInt sMax = PETSC_MIN_INT; 4110 PetscInt coneSize, supportSize; 4111 4112 for (p = pStart; p < pEnd; ++p) { 4113 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4114 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4115 if (!supportSize && coneSize) { 4116 sMin = PetscMin(p, sMin); 4117 sMax = PetscMax(p, sMax); 4118 } 4119 } 4120 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4121 } else { 4122 PetscInt level = 0; 4123 PetscInt qStart, qEnd, q; 4124 4125 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4126 while (qEnd > qStart) { 4127 PetscInt sMin = PETSC_MAX_INT; 4128 PetscInt sMax = PETSC_MIN_INT; 4129 4130 for (q = qStart; q < qEnd; ++q) { 4131 const PetscInt *support; 4132 PetscInt supportSize, s; 4133 4134 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4135 PetscCall(DMPlexGetSupport(dm, q, &support)); 4136 for (s = 0; s < supportSize; ++s) { 4137 sMin = PetscMin(support[s], sMin); 4138 sMax = PetscMax(support[s], sMax); 4139 } 4140 } 4141 PetscCall(DMLabelGetNumValues(label, &level)); 4142 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4143 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4144 } 4145 } 4146 { /* just in case there is an empty process */ 4147 PetscInt numValues, maxValues = 0, v; 4148 4149 PetscCall(DMLabelGetNumValues(label, &numValues)); 4150 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4151 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4152 } 4153 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4154 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4155 PetscFunctionReturn(0); 4156 } 4157 4158 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4159 { 4160 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4161 PetscInt dim, depth, pheight, coneSize; 4162 4163 PetscFunctionBeginHot; 4164 PetscCall(DMGetDimension(dm, &dim)); 4165 PetscCall(DMPlexGetDepth(dm, &depth)); 4166 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4167 pheight = depth - pdepth; 4168 if (depth <= 1) { 4169 switch (pdepth) { 4170 case 0: 4171 ct = DM_POLYTOPE_POINT; 4172 break; 4173 case 1: 4174 switch (coneSize) { 4175 case 2: 4176 ct = DM_POLYTOPE_SEGMENT; 4177 break; 4178 case 3: 4179 ct = DM_POLYTOPE_TRIANGLE; 4180 break; 4181 case 4: 4182 switch (dim) { 4183 case 2: 4184 ct = DM_POLYTOPE_QUADRILATERAL; 4185 break; 4186 case 3: 4187 ct = DM_POLYTOPE_TETRAHEDRON; 4188 break; 4189 default: 4190 break; 4191 } 4192 break; 4193 case 5: 4194 ct = DM_POLYTOPE_PYRAMID; 4195 break; 4196 case 6: 4197 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4198 break; 4199 case 8: 4200 ct = DM_POLYTOPE_HEXAHEDRON; 4201 break; 4202 default: 4203 break; 4204 } 4205 } 4206 } else { 4207 if (pdepth == 0) { 4208 ct = DM_POLYTOPE_POINT; 4209 } else if (pheight == 0) { 4210 switch (dim) { 4211 case 1: 4212 switch (coneSize) { 4213 case 2: 4214 ct = DM_POLYTOPE_SEGMENT; 4215 break; 4216 default: 4217 break; 4218 } 4219 break; 4220 case 2: 4221 switch (coneSize) { 4222 case 3: 4223 ct = DM_POLYTOPE_TRIANGLE; 4224 break; 4225 case 4: 4226 ct = DM_POLYTOPE_QUADRILATERAL; 4227 break; 4228 default: 4229 break; 4230 } 4231 break; 4232 case 3: 4233 switch (coneSize) { 4234 case 4: 4235 ct = DM_POLYTOPE_TETRAHEDRON; 4236 break; 4237 case 5: { 4238 const PetscInt *cone; 4239 PetscInt faceConeSize; 4240 4241 PetscCall(DMPlexGetCone(dm, p, &cone)); 4242 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4243 switch (faceConeSize) { 4244 case 3: 4245 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4246 break; 4247 case 4: 4248 ct = DM_POLYTOPE_PYRAMID; 4249 break; 4250 } 4251 } break; 4252 case 6: 4253 ct = DM_POLYTOPE_HEXAHEDRON; 4254 break; 4255 default: 4256 break; 4257 } 4258 break; 4259 default: 4260 break; 4261 } 4262 } else if (pheight > 0) { 4263 switch (coneSize) { 4264 case 2: 4265 ct = DM_POLYTOPE_SEGMENT; 4266 break; 4267 case 3: 4268 ct = DM_POLYTOPE_TRIANGLE; 4269 break; 4270 case 4: 4271 ct = DM_POLYTOPE_QUADRILATERAL; 4272 break; 4273 default: 4274 break; 4275 } 4276 } 4277 } 4278 *pt = ct; 4279 PetscFunctionReturn(0); 4280 } 4281 4282 /*@ 4283 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4284 4285 Collective on dm 4286 4287 Input Parameter: 4288 . mesh - The `DMPLEX` 4289 4290 Level: developer 4291 4292 Note: 4293 This function is normally called automatically when a cell type is requested. It creates an 4294 internal `DMLabel` named "celltype" which can be directly accessed using `DMGetLabel()`. A user may disable 4295 automatic creation by creating the label manually, using `DMCreateLabel`(dm, "celltype"). 4296 4297 `DMPlexComputeCellTypes()` should be called after all calls to `DMPlexSymmetrize()` and `DMPlexStratify()` 4298 4299 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4300 @*/ 4301 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4302 { 4303 DM_Plex *mesh; 4304 DMLabel ctLabel; 4305 PetscInt pStart, pEnd, p; 4306 4307 PetscFunctionBegin; 4308 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4309 mesh = (DM_Plex *)dm->data; 4310 PetscCall(DMCreateLabel(dm, "celltype")); 4311 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4312 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4313 for (p = pStart; p < pEnd; ++p) { 4314 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4315 PetscInt pdepth; 4316 4317 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4318 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4319 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4320 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4321 } 4322 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4323 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4324 PetscFunctionReturn(0); 4325 } 4326 4327 /*@C 4328 DMPlexGetJoin - Get an array for the join of the set of points 4329 4330 Not Collective 4331 4332 Input Parameters: 4333 + dm - The `DMPLEX` object 4334 . numPoints - The number of input points for the join 4335 - points - The input points 4336 4337 Output Parameters: 4338 + numCoveredPoints - The number of points in the join 4339 - coveredPoints - The points in the join 4340 4341 Level: intermediate 4342 4343 Note: 4344 Currently, this is restricted to a single level join 4345 4346 Fortran Note: 4347 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4348 4349 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4350 @*/ 4351 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4352 { 4353 DM_Plex *mesh = (DM_Plex *)dm->data; 4354 PetscInt *join[2]; 4355 PetscInt joinSize, i = 0; 4356 PetscInt dof, off, p, c, m; 4357 PetscInt maxSupportSize; 4358 4359 PetscFunctionBegin; 4360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4361 PetscValidIntPointer(points, 3); 4362 PetscValidIntPointer(numCoveredPoints, 4); 4363 PetscValidPointer(coveredPoints, 5); 4364 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4365 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4366 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4367 /* Copy in support of first point */ 4368 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4369 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4370 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4371 /* Check each successive support */ 4372 for (p = 1; p < numPoints; ++p) { 4373 PetscInt newJoinSize = 0; 4374 4375 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4376 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4377 for (c = 0; c < dof; ++c) { 4378 const PetscInt point = mesh->supports[off + c]; 4379 4380 for (m = 0; m < joinSize; ++m) { 4381 if (point == join[i][m]) { 4382 join[1 - i][newJoinSize++] = point; 4383 break; 4384 } 4385 } 4386 } 4387 joinSize = newJoinSize; 4388 i = 1 - i; 4389 } 4390 *numCoveredPoints = joinSize; 4391 *coveredPoints = join[i]; 4392 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4393 PetscFunctionReturn(0); 4394 } 4395 4396 /*@C 4397 DMPlexRestoreJoin - Restore an array for the join of the set of points 4398 4399 Not Collective 4400 4401 Input Parameters: 4402 + dm - The `DMPLEX` object 4403 . numPoints - The number of input points for the join 4404 - points - The input points 4405 4406 Output Parameters: 4407 + numCoveredPoints - The number of points in the join 4408 - coveredPoints - The points in the join 4409 4410 Level: intermediate 4411 4412 Fortran Note: 4413 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4414 4415 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4416 @*/ 4417 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4418 { 4419 PetscFunctionBegin; 4420 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4421 if (points) PetscValidIntPointer(points, 3); 4422 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4423 PetscValidPointer(coveredPoints, 5); 4424 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4425 if (numCoveredPoints) *numCoveredPoints = 0; 4426 PetscFunctionReturn(0); 4427 } 4428 4429 /*@C 4430 DMPlexGetFullJoin - Get an array for the join of the set of points 4431 4432 Not Collective 4433 4434 Input Parameters: 4435 + dm - The `DMPLEX` object 4436 . numPoints - The number of input points for the join 4437 - points - The input points 4438 4439 Output Parameters: 4440 + numCoveredPoints - The number of points in the join 4441 - coveredPoints - The points in the join 4442 4443 Level: intermediate 4444 4445 Fortran Note: 4446 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4447 4448 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4449 @*/ 4450 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4451 { 4452 PetscInt *offsets, **closures; 4453 PetscInt *join[2]; 4454 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4455 PetscInt p, d, c, m, ms; 4456 4457 PetscFunctionBegin; 4458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4459 PetscValidIntPointer(points, 3); 4460 PetscValidIntPointer(numCoveredPoints, 4); 4461 PetscValidPointer(coveredPoints, 5); 4462 4463 PetscCall(DMPlexGetDepth(dm, &depth)); 4464 PetscCall(PetscCalloc1(numPoints, &closures)); 4465 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4466 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4467 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4468 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4469 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4470 4471 for (p = 0; p < numPoints; ++p) { 4472 PetscInt closureSize; 4473 4474 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4475 4476 offsets[p * (depth + 2) + 0] = 0; 4477 for (d = 0; d < depth + 1; ++d) { 4478 PetscInt pStart, pEnd, i; 4479 4480 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4481 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4482 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4483 offsets[p * (depth + 2) + d + 1] = i; 4484 break; 4485 } 4486 } 4487 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4488 } 4489 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); 4490 } 4491 for (d = 0; d < depth + 1; ++d) { 4492 PetscInt dof; 4493 4494 /* Copy in support of first point */ 4495 dof = offsets[d + 1] - offsets[d]; 4496 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4497 /* Check each successive cone */ 4498 for (p = 1; p < numPoints && joinSize; ++p) { 4499 PetscInt newJoinSize = 0; 4500 4501 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4502 for (c = 0; c < dof; ++c) { 4503 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4504 4505 for (m = 0; m < joinSize; ++m) { 4506 if (point == join[i][m]) { 4507 join[1 - i][newJoinSize++] = point; 4508 break; 4509 } 4510 } 4511 } 4512 joinSize = newJoinSize; 4513 i = 1 - i; 4514 } 4515 if (joinSize) break; 4516 } 4517 *numCoveredPoints = joinSize; 4518 *coveredPoints = join[i]; 4519 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4520 PetscCall(PetscFree(closures)); 4521 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4522 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4523 PetscFunctionReturn(0); 4524 } 4525 4526 /*@C 4527 DMPlexGetMeet - Get an array for the meet of the set of points 4528 4529 Not Collective 4530 4531 Input Parameters: 4532 + dm - The `DMPLEX` object 4533 . numPoints - The number of input points for the meet 4534 - points - The input points 4535 4536 Output Parameters: 4537 + numCoveredPoints - The number of points in the meet 4538 - coveredPoints - The points in the meet 4539 4540 Level: intermediate 4541 4542 Note: 4543 Currently, this is restricted to a single level meet 4544 4545 Fortran Notes: 4546 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4547 4548 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4549 @*/ 4550 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4551 { 4552 DM_Plex *mesh = (DM_Plex *)dm->data; 4553 PetscInt *meet[2]; 4554 PetscInt meetSize, i = 0; 4555 PetscInt dof, off, p, c, m; 4556 PetscInt maxConeSize; 4557 4558 PetscFunctionBegin; 4559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4560 PetscValidIntPointer(points, 3); 4561 PetscValidIntPointer(numCoveringPoints, 4); 4562 PetscValidPointer(coveringPoints, 5); 4563 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4564 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4565 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4566 /* Copy in cone of first point */ 4567 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4568 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4569 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4570 /* Check each successive cone */ 4571 for (p = 1; p < numPoints; ++p) { 4572 PetscInt newMeetSize = 0; 4573 4574 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4575 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4576 for (c = 0; c < dof; ++c) { 4577 const PetscInt point = mesh->cones[off + c]; 4578 4579 for (m = 0; m < meetSize; ++m) { 4580 if (point == meet[i][m]) { 4581 meet[1 - i][newMeetSize++] = point; 4582 break; 4583 } 4584 } 4585 } 4586 meetSize = newMeetSize; 4587 i = 1 - i; 4588 } 4589 *numCoveringPoints = meetSize; 4590 *coveringPoints = meet[i]; 4591 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4592 PetscFunctionReturn(0); 4593 } 4594 4595 /*@C 4596 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4597 4598 Not Collective 4599 4600 Input Parameters: 4601 + dm - The `DMPLEX` object 4602 . numPoints - The number of input points for the meet 4603 - points - The input points 4604 4605 Output Parameters: 4606 + numCoveredPoints - The number of points in the meet 4607 - coveredPoints - The points in the meet 4608 4609 Level: intermediate 4610 4611 Fortran Note: 4612 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4613 4614 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4615 @*/ 4616 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4617 { 4618 PetscFunctionBegin; 4619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4620 if (points) PetscValidIntPointer(points, 3); 4621 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4622 PetscValidPointer(coveredPoints, 5); 4623 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4624 if (numCoveredPoints) *numCoveredPoints = 0; 4625 PetscFunctionReturn(0); 4626 } 4627 4628 /*@C 4629 DMPlexGetFullMeet - Get an array for the meet of the set of points 4630 4631 Not Collective 4632 4633 Input Parameters: 4634 + dm - The `DMPLEX` object 4635 . numPoints - The number of input points for the meet 4636 - points - The input points 4637 4638 Output Parameters: 4639 + numCoveredPoints - The number of points in the meet 4640 - coveredPoints - The points in the meet 4641 4642 Level: intermediate 4643 4644 Fortran Note: 4645 The numCoveredPoints argument is not present in the Fortran binding since it is internal to the array. 4646 4647 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4648 @*/ 4649 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4650 { 4651 PetscInt *offsets, **closures; 4652 PetscInt *meet[2]; 4653 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4654 PetscInt p, h, c, m, mc; 4655 4656 PetscFunctionBegin; 4657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4658 PetscValidIntPointer(points, 3); 4659 PetscValidIntPointer(numCoveredPoints, 4); 4660 PetscValidPointer(coveredPoints, 5); 4661 4662 PetscCall(DMPlexGetDepth(dm, &height)); 4663 PetscCall(PetscMalloc1(numPoints, &closures)); 4664 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4665 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4666 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4667 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4668 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4669 4670 for (p = 0; p < numPoints; ++p) { 4671 PetscInt closureSize; 4672 4673 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4674 4675 offsets[p * (height + 2) + 0] = 0; 4676 for (h = 0; h < height + 1; ++h) { 4677 PetscInt pStart, pEnd, i; 4678 4679 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4680 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4681 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4682 offsets[p * (height + 2) + h + 1] = i; 4683 break; 4684 } 4685 } 4686 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4687 } 4688 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); 4689 } 4690 for (h = 0; h < height + 1; ++h) { 4691 PetscInt dof; 4692 4693 /* Copy in cone of first point */ 4694 dof = offsets[h + 1] - offsets[h]; 4695 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4696 /* Check each successive cone */ 4697 for (p = 1; p < numPoints && meetSize; ++p) { 4698 PetscInt newMeetSize = 0; 4699 4700 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4701 for (c = 0; c < dof; ++c) { 4702 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4703 4704 for (m = 0; m < meetSize; ++m) { 4705 if (point == meet[i][m]) { 4706 meet[1 - i][newMeetSize++] = point; 4707 break; 4708 } 4709 } 4710 } 4711 meetSize = newMeetSize; 4712 i = 1 - i; 4713 } 4714 if (meetSize) break; 4715 } 4716 *numCoveredPoints = meetSize; 4717 *coveredPoints = meet[i]; 4718 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4719 PetscCall(PetscFree(closures)); 4720 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4721 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4722 PetscFunctionReturn(0); 4723 } 4724 4725 /*@C 4726 DMPlexEqual - Determine if two `DM` have the same topology 4727 4728 Not Collective 4729 4730 Input Parameters: 4731 + dmA - A `DMPLEX` object 4732 - dmB - A `DMPLEX` object 4733 4734 Output Parameters: 4735 . equal - `PETSC_TRUE` if the topologies are identical 4736 4737 Level: intermediate 4738 4739 Note: 4740 We are not solving graph isomorphism, so we do not permute. 4741 4742 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4743 @*/ 4744 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4745 { 4746 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4747 4748 PetscFunctionBegin; 4749 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4750 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4751 PetscValidBoolPointer(equal, 3); 4752 4753 *equal = PETSC_FALSE; 4754 PetscCall(DMPlexGetDepth(dmA, &depth)); 4755 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4756 if (depth != depthB) PetscFunctionReturn(0); 4757 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4758 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4759 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4760 for (p = pStart; p < pEnd; ++p) { 4761 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4762 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4763 4764 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4765 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4766 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4767 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4768 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4769 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4770 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4771 for (c = 0; c < coneSize; ++c) { 4772 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4773 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4774 } 4775 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4776 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4777 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4778 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4779 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4780 for (s = 0; s < supportSize; ++s) { 4781 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4782 } 4783 } 4784 *equal = PETSC_TRUE; 4785 PetscFunctionReturn(0); 4786 } 4787 4788 /*@C 4789 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4790 4791 Not Collective 4792 4793 Input Parameters: 4794 + dm - The `DMPLEX` 4795 . cellDim - The cell dimension 4796 - numCorners - The number of vertices on a cell 4797 4798 Output Parameters: 4799 . numFaceVertices - The number of vertices on a face 4800 4801 Level: developer 4802 4803 Note: 4804 Of course this can only work for a restricted set of symmetric shapes 4805 4806 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 4807 @*/ 4808 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4809 { 4810 MPI_Comm comm; 4811 4812 PetscFunctionBegin; 4813 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4814 PetscValidIntPointer(numFaceVertices, 4); 4815 switch (cellDim) { 4816 case 0: 4817 *numFaceVertices = 0; 4818 break; 4819 case 1: 4820 *numFaceVertices = 1; 4821 break; 4822 case 2: 4823 switch (numCorners) { 4824 case 3: /* triangle */ 4825 *numFaceVertices = 2; /* Edge has 2 vertices */ 4826 break; 4827 case 4: /* quadrilateral */ 4828 *numFaceVertices = 2; /* Edge has 2 vertices */ 4829 break; 4830 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4831 *numFaceVertices = 3; /* Edge has 3 vertices */ 4832 break; 4833 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4834 *numFaceVertices = 3; /* Edge has 3 vertices */ 4835 break; 4836 default: 4837 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4838 } 4839 break; 4840 case 3: 4841 switch (numCorners) { 4842 case 4: /* tetradehdron */ 4843 *numFaceVertices = 3; /* Face has 3 vertices */ 4844 break; 4845 case 6: /* tet cohesive cells */ 4846 *numFaceVertices = 4; /* Face has 4 vertices */ 4847 break; 4848 case 8: /* hexahedron */ 4849 *numFaceVertices = 4; /* Face has 4 vertices */ 4850 break; 4851 case 9: /* tet cohesive Lagrange cells */ 4852 *numFaceVertices = 6; /* Face has 6 vertices */ 4853 break; 4854 case 10: /* quadratic tetrahedron */ 4855 *numFaceVertices = 6; /* Face has 6 vertices */ 4856 break; 4857 case 12: /* hex cohesive Lagrange cells */ 4858 *numFaceVertices = 6; /* Face has 6 vertices */ 4859 break; 4860 case 18: /* quadratic tet cohesive Lagrange cells */ 4861 *numFaceVertices = 6; /* Face has 6 vertices */ 4862 break; 4863 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4864 *numFaceVertices = 9; /* Face has 9 vertices */ 4865 break; 4866 default: 4867 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4868 } 4869 break; 4870 default: 4871 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4872 } 4873 PetscFunctionReturn(0); 4874 } 4875 4876 /*@ 4877 DMPlexGetDepthLabel - Get the `DMLabel` recording the depth of each point 4878 4879 Not Collective 4880 4881 Input Parameter: 4882 . dm - The `DMPLEX` object 4883 4884 Output Parameter: 4885 . depthLabel - The `DMLabel` recording point depth 4886 4887 Level: developer 4888 4889 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4890 @*/ 4891 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4892 { 4893 PetscFunctionBegin; 4894 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4895 PetscValidPointer(depthLabel, 2); 4896 *depthLabel = dm->depthLabel; 4897 PetscFunctionReturn(0); 4898 } 4899 4900 /*@ 4901 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4902 4903 Not Collective 4904 4905 Input Parameter: 4906 . dm - The `DMPLEX` object 4907 4908 Output Parameter: 4909 . depth - The number of strata (breadth first levels) in the DAG 4910 4911 Level: developer 4912 4913 Notes: 4914 This returns maximum of point depths over all points, i.e. maximum value of the label returned by `DMPlexGetDepthLabel()`. 4915 4916 The point depth is described more in detail in `DMPlexGetDepthStratum()`. 4917 4918 An empty mesh gives -1. 4919 4920 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4921 @*/ 4922 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4923 { 4924 DM_Plex *mesh = (DM_Plex *)dm->data; 4925 DMLabel label; 4926 PetscInt d = 0; 4927 4928 PetscFunctionBegin; 4929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4930 PetscValidIntPointer(depth, 2); 4931 if (mesh->tr) { 4932 PetscCall(DMPlexTransformGetDepth(mesh->tr, depth)); 4933 } else { 4934 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4935 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4936 *depth = d - 1; 4937 } 4938 PetscFunctionReturn(0); 4939 } 4940 4941 /*@ 4942 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4943 4944 Not Collective 4945 4946 Input Parameters: 4947 + dm - The `DMPLEX` object 4948 - depth - The requested depth 4949 4950 Output Parameters: 4951 + start - The first point at this depth 4952 - end - One beyond the last point at this depth 4953 4954 Level: developer 4955 4956 Notes: 4957 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4958 often "vertices". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then depth stratum 1 contains the next 4959 higher dimension, e.g., "edges". 4960 4961 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4962 @*/ 4963 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4964 { 4965 DM_Plex *mesh = (DM_Plex *)dm->data; 4966 DMLabel label; 4967 PetscInt pStart, pEnd; 4968 4969 PetscFunctionBegin; 4970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4971 if (start) { 4972 PetscValidIntPointer(start, 3); 4973 *start = 0; 4974 } 4975 if (end) { 4976 PetscValidIntPointer(end, 4); 4977 *end = 0; 4978 } 4979 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4980 if (pStart == pEnd) PetscFunctionReturn(0); 4981 if (depth < 0) { 4982 if (start) *start = pStart; 4983 if (end) *end = pEnd; 4984 PetscFunctionReturn(0); 4985 } 4986 if (mesh->tr) { 4987 PetscCall(DMPlexTransformGetDepthStratum(mesh->tr, depth, start, end)); 4988 } else { 4989 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4990 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4991 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4992 } 4993 PetscFunctionReturn(0); 4994 } 4995 4996 /*@ 4997 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4998 4999 Not Collective 5000 5001 Input Parameters: 5002 + dm - The `DMPLEX` object 5003 - height - The requested height 5004 5005 Output Parameters: 5006 + start - The first point at this height 5007 - end - One beyond the last point at this height 5008 5009 Level: developer 5010 5011 Notes: 5012 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 5013 points, often called "cells" or "elements". If the mesh is "interpolated" (see `DMPlexInterpolate()`), then height 5014 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 5015 5016 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5017 @*/ 5018 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 5019 { 5020 DMLabel label; 5021 PetscInt depth, pStart, pEnd; 5022 5023 PetscFunctionBegin; 5024 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5025 if (start) { 5026 PetscValidIntPointer(start, 3); 5027 *start = 0; 5028 } 5029 if (end) { 5030 PetscValidIntPointer(end, 4); 5031 *end = 0; 5032 } 5033 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 5034 if (pStart == pEnd) PetscFunctionReturn(0); 5035 if (height < 0) { 5036 if (start) *start = pStart; 5037 if (end) *end = pEnd; 5038 PetscFunctionReturn(0); 5039 } 5040 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5041 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 5042 PetscCall(DMLabelGetNumValues(label, &depth)); 5043 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 5044 PetscFunctionReturn(0); 5045 } 5046 5047 /*@ 5048 DMPlexGetPointDepth - Get the depth of a given point 5049 5050 Not Collective 5051 5052 Input Parameters: 5053 + dm - The `DMPLEX` object 5054 - point - The point 5055 5056 Output Parameter: 5057 . depth - The depth of the point 5058 5059 Level: intermediate 5060 5061 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 5062 @*/ 5063 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 5064 { 5065 PetscFunctionBegin; 5066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5067 PetscValidIntPointer(depth, 3); 5068 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 5069 PetscFunctionReturn(0); 5070 } 5071 5072 /*@ 5073 DMPlexGetPointHeight - Get the height of a given point 5074 5075 Not Collective 5076 5077 Input Parameters: 5078 + dm - The `DMPLEX` object 5079 - point - The point 5080 5081 Output Parameter: 5082 . height - The height of the point 5083 5084 Level: intermediate 5085 5086 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 5087 @*/ 5088 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5089 { 5090 PetscInt n, pDepth; 5091 5092 PetscFunctionBegin; 5093 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5094 PetscValidIntPointer(height, 3); 5095 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5096 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5097 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5098 PetscFunctionReturn(0); 5099 } 5100 5101 /*@ 5102 DMPlexGetCellTypeLabel - Get the `DMLabel` recording the polytope type of each cell 5103 5104 Not Collective 5105 5106 Input Parameter: 5107 . dm - The `DMPLEX` object 5108 5109 Output Parameter: 5110 . celltypeLabel - The `DMLabel` recording cell polytope type 5111 5112 Level: developer 5113 5114 Note: 5115 This function will trigger automatica computation of cell types. This can be disabled by calling 5116 `DMCreateLabel`(dm, "celltype") beforehand. 5117 5118 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5119 @*/ 5120 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5121 { 5122 PetscFunctionBegin; 5123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5124 PetscValidPointer(celltypeLabel, 2); 5125 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5126 *celltypeLabel = dm->celltypeLabel; 5127 PetscFunctionReturn(0); 5128 } 5129 5130 /*@ 5131 DMPlexGetCellType - Get the polytope type of a given cell 5132 5133 Not Collective 5134 5135 Input Parameters: 5136 + dm - The `DMPLEX` object 5137 - cell - The cell 5138 5139 Output Parameter: 5140 . celltype - The polytope type of the cell 5141 5142 Level: intermediate 5143 5144 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5145 @*/ 5146 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5147 { 5148 DM_Plex *mesh = (DM_Plex *)dm->data; 5149 DMLabel label; 5150 PetscInt ct; 5151 5152 PetscFunctionBegin; 5153 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5154 PetscValidPointer(celltype, 3); 5155 if (mesh->tr) { 5156 PetscCall(DMPlexTransformGetCellType(mesh->tr, cell, celltype)); 5157 } else { 5158 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5159 PetscCall(DMLabelGetValue(label, cell, &ct)); 5160 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5161 *celltype = (DMPolytopeType)ct; 5162 } 5163 PetscFunctionReturn(0); 5164 } 5165 5166 /*@ 5167 DMPlexSetCellType - Set the polytope type of a given cell 5168 5169 Not Collective 5170 5171 Input Parameters: 5172 + dm - The `DMPLEX` object 5173 . cell - The cell 5174 - celltype - The polytope type of the cell 5175 5176 Level: advanced 5177 5178 Note: 5179 By default, cell types will be automatically computed using `DMPlexComputeCellTypes()` before this function 5180 is executed. This function will override the computed type. However, if automatic classification will not succeed 5181 and a user wants to manually specify all types, the classification must be disabled by calling 5182 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5183 5184 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5185 @*/ 5186 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5187 { 5188 DMLabel label; 5189 5190 PetscFunctionBegin; 5191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5192 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5193 PetscCall(DMLabelSetValue(label, cell, celltype)); 5194 PetscFunctionReturn(0); 5195 } 5196 5197 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5198 { 5199 PetscSection section, s; 5200 Mat m; 5201 PetscInt maxHeight; 5202 const char *prefix; 5203 5204 PetscFunctionBegin; 5205 PetscCall(DMClone(dm, cdm)); 5206 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 5207 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 5208 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 5209 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5210 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5211 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5212 PetscCall(DMSetLocalSection(*cdm, section)); 5213 PetscCall(PetscSectionDestroy(§ion)); 5214 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5215 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5216 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5217 PetscCall(PetscSectionDestroy(&s)); 5218 PetscCall(MatDestroy(&m)); 5219 5220 PetscCall(DMSetNumFields(*cdm, 1)); 5221 PetscCall(DMCreateDS(*cdm)); 5222 (*cdm)->cloneOpts = PETSC_TRUE; 5223 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(*cdm)); 5224 PetscFunctionReturn(0); 5225 } 5226 5227 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5228 { 5229 Vec coordsLocal, cellCoordsLocal; 5230 DM coordsDM, cellCoordsDM; 5231 5232 PetscFunctionBegin; 5233 *field = NULL; 5234 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5235 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5236 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5237 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5238 if (coordsLocal && coordsDM) { 5239 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5240 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5241 } 5242 PetscFunctionReturn(0); 5243 } 5244 5245 /*@C 5246 DMPlexGetConeSection - Return a section which describes the layout of cone data 5247 5248 Not Collective 5249 5250 Input Parameters: 5251 . dm - The `DMPLEX` object 5252 5253 Output Parameter: 5254 . section - The `PetscSection` object 5255 5256 Level: developer 5257 5258 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()`, `PetscSection` 5259 @*/ 5260 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5261 { 5262 DM_Plex *mesh = (DM_Plex *)dm->data; 5263 5264 PetscFunctionBegin; 5265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5266 if (section) *section = mesh->coneSection; 5267 PetscFunctionReturn(0); 5268 } 5269 5270 /*@C 5271 DMPlexGetSupportSection - Return a section which describes the layout of support data 5272 5273 Not Collective 5274 5275 Input Parameters: 5276 . dm - The `DMPLEX` object 5277 5278 Output Parameter: 5279 . section - The `PetscSection` object 5280 5281 Level: developer 5282 5283 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `PetscSection` 5284 @*/ 5285 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5286 { 5287 DM_Plex *mesh = (DM_Plex *)dm->data; 5288 5289 PetscFunctionBegin; 5290 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5291 if (section) *section = mesh->supportSection; 5292 PetscFunctionReturn(0); 5293 } 5294 5295 /*@C 5296 DMPlexGetCones - Return cone data 5297 5298 Not Collective 5299 5300 Input Parameters: 5301 . dm - The `DMPLEX` object 5302 5303 Output Parameter: 5304 . cones - The cone for each point 5305 5306 Level: developer 5307 5308 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()` 5309 @*/ 5310 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5311 { 5312 DM_Plex *mesh = (DM_Plex *)dm->data; 5313 5314 PetscFunctionBegin; 5315 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5316 if (cones) *cones = mesh->cones; 5317 PetscFunctionReturn(0); 5318 } 5319 5320 /*@C 5321 DMPlexGetConeOrientations - Return cone orientation data 5322 5323 Not Collective 5324 5325 Input Parameters: 5326 . dm - The `DMPLEX` object 5327 5328 Output Parameter: 5329 . coneOrientations - The array of cone orientations for all points 5330 5331 Level: developer 5332 5333 Notes: 5334 The `PetscSection` returned by `DMPlexGetConeSection()` partitions coneOrientations into cone orientations of particular points as returned by `DMPlexGetConeOrientation()`. 5335 5336 The meaning of coneOrientations values is detailed in `DMPlexGetConeOrientation()`. 5337 5338 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()`, `PetscSection` 5339 @*/ 5340 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5341 { 5342 DM_Plex *mesh = (DM_Plex *)dm->data; 5343 5344 PetscFunctionBegin; 5345 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5346 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5347 PetscFunctionReturn(0); 5348 } 5349 5350 /******************************** FEM Support **********************************/ 5351 5352 /* 5353 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5354 representing a line in the section. 5355 */ 5356 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5357 { 5358 PetscFunctionBeginHot; 5359 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5360 if (line < 0) { 5361 *k = 0; 5362 *Nc = 0; 5363 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5364 *k = 1; 5365 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5366 /* An order k SEM disc has k-1 dofs on an edge */ 5367 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5368 *k = *k / *Nc + 1; 5369 } 5370 PetscFunctionReturn(0); 5371 } 5372 5373 /*@ 5374 5375 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5376 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5377 section provided (or the section of the DM). 5378 5379 Input Parameters: 5380 + dm - The DM 5381 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5382 - section - The PetscSection to reorder, or NULL for the default section 5383 5384 Example: 5385 A typical interpolated single-quad mesh might order points as 5386 .vb 5387 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5388 5389 v4 -- e6 -- v3 5390 | | 5391 e7 c0 e8 5392 | | 5393 v1 -- e5 -- v2 5394 .ve 5395 5396 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5397 dofs in the order of points, e.g., 5398 .vb 5399 c0 -> [0,1,2,3] 5400 v1 -> [4] 5401 ... 5402 e5 -> [8, 9] 5403 .ve 5404 5405 which corresponds to the dofs 5406 .vb 5407 6 10 11 7 5408 13 2 3 15 5409 12 0 1 14 5410 4 8 9 5 5411 .ve 5412 5413 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5414 .vb 5415 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5416 .ve 5417 5418 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5419 .vb 5420 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5421 .ve 5422 5423 Level: developer 5424 5425 Note: 5426 The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5427 degree of the basis. 5428 5429 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5430 @*/ 5431 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5432 { 5433 DMLabel label; 5434 PetscInt dim, depth = -1, eStart = -1, Nf; 5435 PetscBool vertexchart; 5436 5437 PetscFunctionBegin; 5438 PetscCall(DMGetDimension(dm, &dim)); 5439 if (dim < 1) PetscFunctionReturn(0); 5440 if (point < 0) { 5441 PetscInt sStart, sEnd; 5442 5443 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5444 point = sEnd - sStart ? sStart : point; 5445 } 5446 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5447 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5448 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5449 if (depth == 1) { 5450 eStart = point; 5451 } else if (depth == dim) { 5452 const PetscInt *cone; 5453 5454 PetscCall(DMPlexGetCone(dm, point, &cone)); 5455 if (dim == 2) eStart = cone[0]; 5456 else if (dim == 3) { 5457 const PetscInt *cone2; 5458 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5459 eStart = cone2[0]; 5460 } 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); 5461 } 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); 5462 { /* Determine whether the chart covers all points or just vertices. */ 5463 PetscInt pStart, pEnd, cStart, cEnd; 5464 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5465 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5466 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5467 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5468 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5469 } 5470 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5471 for (PetscInt d = 1; d <= dim; d++) { 5472 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5473 PetscInt *perm; 5474 5475 for (f = 0; f < Nf; ++f) { 5476 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5477 size += PetscPowInt(k + 1, d) * Nc; 5478 } 5479 PetscCall(PetscMalloc1(size, &perm)); 5480 for (f = 0; f < Nf; ++f) { 5481 switch (d) { 5482 case 1: 5483 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5484 /* 5485 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5486 We want [ vtx0; edge of length k-1; vtx1 ] 5487 */ 5488 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5489 for (i = 0; i < k - 1; i++) 5490 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5491 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5492 foffset = offset; 5493 break; 5494 case 2: 5495 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5496 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5497 /* The SEM order is 5498 5499 v_lb, {e_b}, v_rb, 5500 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5501 v_lt, reverse {e_t}, v_rt 5502 */ 5503 { 5504 const PetscInt of = 0; 5505 const PetscInt oeb = of + PetscSqr(k - 1); 5506 const PetscInt oer = oeb + (k - 1); 5507 const PetscInt oet = oer + (k - 1); 5508 const PetscInt oel = oet + (k - 1); 5509 const PetscInt ovlb = oel + (k - 1); 5510 const PetscInt ovrb = ovlb + 1; 5511 const PetscInt ovrt = ovrb + 1; 5512 const PetscInt ovlt = ovrt + 1; 5513 PetscInt o; 5514 5515 /* bottom */ 5516 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5517 for (o = oeb; o < oer; ++o) 5518 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5519 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5520 /* middle */ 5521 for (i = 0; i < k - 1; ++i) { 5522 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5523 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5524 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5525 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5526 } 5527 /* top */ 5528 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5529 for (o = oel - 1; o >= oet; --o) 5530 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5531 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5532 foffset = offset; 5533 } 5534 break; 5535 case 3: 5536 /* The original hex closure is 5537 5538 {c, 5539 f_b, f_t, f_f, f_b, f_r, f_l, 5540 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5541 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5542 */ 5543 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5544 /* The SEM order is 5545 Bottom Slice 5546 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5547 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5548 v_blb, {e_bb}, v_brb, 5549 5550 Middle Slice (j) 5551 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5552 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5553 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5554 5555 Top Slice 5556 v_tlf, {e_tf}, v_trf, 5557 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5558 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5559 */ 5560 { 5561 const PetscInt oc = 0; 5562 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5563 const PetscInt oft = ofb + PetscSqr(k - 1); 5564 const PetscInt off = oft + PetscSqr(k - 1); 5565 const PetscInt ofk = off + PetscSqr(k - 1); 5566 const PetscInt ofr = ofk + PetscSqr(k - 1); 5567 const PetscInt ofl = ofr + PetscSqr(k - 1); 5568 const PetscInt oebl = ofl + PetscSqr(k - 1); 5569 const PetscInt oebb = oebl + (k - 1); 5570 const PetscInt oebr = oebb + (k - 1); 5571 const PetscInt oebf = oebr + (k - 1); 5572 const PetscInt oetf = oebf + (k - 1); 5573 const PetscInt oetr = oetf + (k - 1); 5574 const PetscInt oetb = oetr + (k - 1); 5575 const PetscInt oetl = oetb + (k - 1); 5576 const PetscInt oerf = oetl + (k - 1); 5577 const PetscInt oelf = oerf + (k - 1); 5578 const PetscInt oelb = oelf + (k - 1); 5579 const PetscInt oerb = oelb + (k - 1); 5580 const PetscInt ovblf = oerb + (k - 1); 5581 const PetscInt ovblb = ovblf + 1; 5582 const PetscInt ovbrb = ovblb + 1; 5583 const PetscInt ovbrf = ovbrb + 1; 5584 const PetscInt ovtlf = ovbrf + 1; 5585 const PetscInt ovtrf = ovtlf + 1; 5586 const PetscInt ovtrb = ovtrf + 1; 5587 const PetscInt ovtlb = ovtrb + 1; 5588 PetscInt o, n; 5589 5590 /* Bottom Slice */ 5591 /* bottom */ 5592 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5593 for (o = oetf - 1; o >= oebf; --o) 5594 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5595 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5596 /* middle */ 5597 for (i = 0; i < k - 1; ++i) { 5598 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5599 for (n = 0; n < k - 1; ++n) { 5600 o = ofb + n * (k - 1) + i; 5601 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5602 } 5603 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5604 } 5605 /* top */ 5606 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5607 for (o = oebb; o < oebr; ++o) 5608 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5609 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5610 5611 /* Middle Slice */ 5612 for (j = 0; j < k - 1; ++j) { 5613 /* bottom */ 5614 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5615 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5616 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5617 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5618 /* middle */ 5619 for (i = 0; i < k - 1; ++i) { 5620 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5621 for (n = 0; n < k - 1; ++n) 5622 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5623 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5624 } 5625 /* top */ 5626 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5627 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5628 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5629 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5630 } 5631 5632 /* Top Slice */ 5633 /* bottom */ 5634 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5635 for (o = oetf; o < oetr; ++o) 5636 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5637 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5638 /* middle */ 5639 for (i = 0; i < k - 1; ++i) { 5640 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5641 for (n = 0; n < k - 1; ++n) 5642 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5643 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5644 } 5645 /* top */ 5646 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5647 for (o = oetl - 1; o >= oetb; --o) 5648 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5649 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5650 5651 foffset = offset; 5652 } 5653 break; 5654 default: 5655 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5656 } 5657 } 5658 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5659 /* Check permutation */ 5660 { 5661 PetscInt *check; 5662 5663 PetscCall(PetscMalloc1(size, &check)); 5664 for (i = 0; i < size; ++i) { 5665 check[i] = -1; 5666 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5667 } 5668 for (i = 0; i < size; ++i) check[perm[i]] = i; 5669 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5670 PetscCall(PetscFree(check)); 5671 } 5672 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5673 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5674 PetscInt *loc_perm; 5675 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5676 for (PetscInt i = 0; i < size; i++) { 5677 loc_perm[i] = perm[i]; 5678 loc_perm[size + i] = size + perm[i]; 5679 } 5680 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5681 } 5682 } 5683 PetscFunctionReturn(0); 5684 } 5685 5686 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5687 { 5688 PetscDS prob; 5689 PetscInt depth, Nf, h; 5690 DMLabel label; 5691 5692 PetscFunctionBeginHot; 5693 PetscCall(DMGetDS(dm, &prob)); 5694 Nf = prob->Nf; 5695 label = dm->depthLabel; 5696 *dspace = NULL; 5697 if (field < Nf) { 5698 PetscObject disc = prob->disc[field]; 5699 5700 if (disc->classid == PETSCFE_CLASSID) { 5701 PetscDualSpace dsp; 5702 5703 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5704 PetscCall(DMLabelGetNumValues(label, &depth)); 5705 PetscCall(DMLabelGetValue(label, point, &h)); 5706 h = depth - 1 - h; 5707 if (h) { 5708 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5709 } else { 5710 *dspace = dsp; 5711 } 5712 } 5713 } 5714 PetscFunctionReturn(0); 5715 } 5716 5717 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5718 { 5719 PetscScalar *array; 5720 const PetscScalar *vArray; 5721 const PetscInt *cone, *coneO; 5722 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5723 5724 PetscFunctionBeginHot; 5725 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5726 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5727 PetscCall(DMPlexGetCone(dm, point, &cone)); 5728 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5729 if (!values || !*values) { 5730 if ((point >= pStart) && (point < pEnd)) { 5731 PetscInt dof; 5732 5733 PetscCall(PetscSectionGetDof(section, point, &dof)); 5734 size += dof; 5735 } 5736 for (p = 0; p < numPoints; ++p) { 5737 const PetscInt cp = cone[p]; 5738 PetscInt dof; 5739 5740 if ((cp < pStart) || (cp >= pEnd)) continue; 5741 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5742 size += dof; 5743 } 5744 if (!values) { 5745 if (csize) *csize = size; 5746 PetscFunctionReturn(0); 5747 } 5748 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5749 } else { 5750 array = *values; 5751 } 5752 size = 0; 5753 PetscCall(VecGetArrayRead(v, &vArray)); 5754 if ((point >= pStart) && (point < pEnd)) { 5755 PetscInt dof, off, d; 5756 const PetscScalar *varr; 5757 5758 PetscCall(PetscSectionGetDof(section, point, &dof)); 5759 PetscCall(PetscSectionGetOffset(section, point, &off)); 5760 varr = &vArray[off]; 5761 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5762 size += dof; 5763 } 5764 for (p = 0; p < numPoints; ++p) { 5765 const PetscInt cp = cone[p]; 5766 PetscInt o = coneO[p]; 5767 PetscInt dof, off, d; 5768 const PetscScalar *varr; 5769 5770 if ((cp < pStart) || (cp >= pEnd)) continue; 5771 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5772 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5773 varr = &vArray[off]; 5774 if (o >= 0) { 5775 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5776 } else { 5777 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5778 } 5779 size += dof; 5780 } 5781 PetscCall(VecRestoreArrayRead(v, &vArray)); 5782 if (!*values) { 5783 if (csize) *csize = size; 5784 *values = array; 5785 } else { 5786 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5787 *csize = size; 5788 } 5789 PetscFunctionReturn(0); 5790 } 5791 5792 /* Compress out points not in the section */ 5793 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5794 { 5795 const PetscInt np = *numPoints; 5796 PetscInt pStart, pEnd, p, q; 5797 5798 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5799 for (p = 0, q = 0; p < np; ++p) { 5800 const PetscInt r = points[p * 2]; 5801 if ((r >= pStart) && (r < pEnd)) { 5802 points[q * 2] = r; 5803 points[q * 2 + 1] = points[p * 2 + 1]; 5804 ++q; 5805 } 5806 } 5807 *numPoints = q; 5808 return 0; 5809 } 5810 5811 /* Compressed closure does not apply closure permutation */ 5812 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5813 { 5814 const PetscInt *cla = NULL; 5815 PetscInt np, *pts = NULL; 5816 5817 PetscFunctionBeginHot; 5818 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5819 if (*clPoints) { 5820 PetscInt dof, off; 5821 5822 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5823 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5824 PetscCall(ISGetIndices(*clPoints, &cla)); 5825 np = dof / 2; 5826 pts = (PetscInt *)&cla[off]; 5827 } else { 5828 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5829 PetscCall(CompressPoints_Private(section, &np, pts)); 5830 } 5831 *numPoints = np; 5832 *points = pts; 5833 *clp = cla; 5834 PetscFunctionReturn(0); 5835 } 5836 5837 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5838 { 5839 PetscFunctionBeginHot; 5840 if (!*clPoints) { 5841 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5842 } else { 5843 PetscCall(ISRestoreIndices(*clPoints, clp)); 5844 } 5845 *numPoints = 0; 5846 *points = NULL; 5847 *clSec = NULL; 5848 *clPoints = NULL; 5849 *clp = NULL; 5850 PetscFunctionReturn(0); 5851 } 5852 5853 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5854 { 5855 PetscInt offset = 0, p; 5856 const PetscInt **perms = NULL; 5857 const PetscScalar **flips = NULL; 5858 5859 PetscFunctionBeginHot; 5860 *size = 0; 5861 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5862 for (p = 0; p < numPoints; p++) { 5863 const PetscInt point = points[2 * p]; 5864 const PetscInt *perm = perms ? perms[p] : NULL; 5865 const PetscScalar *flip = flips ? flips[p] : NULL; 5866 PetscInt dof, off, d; 5867 const PetscScalar *varr; 5868 5869 PetscCall(PetscSectionGetDof(section, point, &dof)); 5870 PetscCall(PetscSectionGetOffset(section, point, &off)); 5871 varr = &vArray[off]; 5872 if (clperm) { 5873 if (perm) { 5874 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5875 } else { 5876 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5877 } 5878 if (flip) { 5879 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5880 } 5881 } else { 5882 if (perm) { 5883 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5884 } else { 5885 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5886 } 5887 if (flip) { 5888 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5889 } 5890 } 5891 offset += dof; 5892 } 5893 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5894 *size = offset; 5895 PetscFunctionReturn(0); 5896 } 5897 5898 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[]) 5899 { 5900 PetscInt offset = 0, f; 5901 5902 PetscFunctionBeginHot; 5903 *size = 0; 5904 for (f = 0; f < numFields; ++f) { 5905 PetscInt p; 5906 const PetscInt **perms = NULL; 5907 const PetscScalar **flips = NULL; 5908 5909 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5910 for (p = 0; p < numPoints; p++) { 5911 const PetscInt point = points[2 * p]; 5912 PetscInt fdof, foff, b; 5913 const PetscScalar *varr; 5914 const PetscInt *perm = perms ? perms[p] : NULL; 5915 const PetscScalar *flip = flips ? flips[p] : NULL; 5916 5917 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5918 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5919 varr = &vArray[foff]; 5920 if (clperm) { 5921 if (perm) { 5922 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5923 } else { 5924 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5925 } 5926 if (flip) { 5927 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5928 } 5929 } else { 5930 if (perm) { 5931 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5932 } else { 5933 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5934 } 5935 if (flip) { 5936 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5937 } 5938 } 5939 offset += fdof; 5940 } 5941 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5942 } 5943 *size = offset; 5944 PetscFunctionReturn(0); 5945 } 5946 5947 /*@C 5948 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5949 5950 Not collective 5951 5952 Input Parameters: 5953 + dm - The `DM` 5954 . section - The section describing the layout in v, or NULL to use the default section 5955 . v - The local vector 5956 - point - The point in the `DM` 5957 5958 Input/Output Parameters: 5959 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5960 - values - An array to use for the values, or NULL to have it allocated automatically; 5961 if the user provided NULL, it is a borrowed array and should not be freed 5962 5963 Level: intermediate 5964 5965 Notes: 5966 `DMPlexVecGetClosure()`/`DMPlexVecRestoreClosure()` only allocates the values array if it set to NULL in the 5967 calling function. This is because `DMPlexVecGetClosure()` is typically called in the inner loop of a `Vec` or `Mat` 5968 assembly function, and a user may already have allocated storage for this operation. 5969 5970 A typical use could be 5971 .vb 5972 values = NULL; 5973 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5974 for (cl = 0; cl < clSize; ++cl) { 5975 <Compute on closure> 5976 } 5977 PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5978 .ve 5979 or 5980 .vb 5981 PetscMalloc1(clMaxSize, &values); 5982 for (p = pStart; p < pEnd; ++p) { 5983 clSize = clMaxSize; 5984 PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5985 for (cl = 0; cl < clSize; ++cl) { 5986 <Compute on closure> 5987 } 5988 } 5989 PetscFree(values); 5990 .ve 5991 5992 Fortran Note: 5993 The csize argument is not present in the Fortran binding since it is internal to the array. 5994 5995 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5996 @*/ 5997 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5998 { 5999 PetscSection clSection; 6000 IS clPoints; 6001 PetscInt *points = NULL; 6002 const PetscInt *clp, *perm; 6003 PetscInt depth, numFields, numPoints, asize; 6004 6005 PetscFunctionBeginHot; 6006 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6007 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6008 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6009 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6010 PetscCall(DMPlexGetDepth(dm, &depth)); 6011 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6012 if (depth == 1 && numFields < 2) { 6013 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6014 PetscFunctionReturn(0); 6015 } 6016 /* Get points */ 6017 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6018 /* Get sizes */ 6019 asize = 0; 6020 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 6021 PetscInt dof; 6022 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6023 asize += dof; 6024 } 6025 if (values) { 6026 const PetscScalar *vArray; 6027 PetscInt size; 6028 6029 if (*values) { 6030 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); 6031 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 6032 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 6033 PetscCall(VecGetArrayRead(v, &vArray)); 6034 /* Get values */ 6035 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 6036 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 6037 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 6038 /* Cleanup array */ 6039 PetscCall(VecRestoreArrayRead(v, &vArray)); 6040 } 6041 if (csize) *csize = asize; 6042 /* Cleanup points */ 6043 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6044 PetscFunctionReturn(0); 6045 } 6046 6047 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 6048 { 6049 DMLabel depthLabel; 6050 PetscSection clSection; 6051 IS clPoints; 6052 PetscScalar *array; 6053 const PetscScalar *vArray; 6054 PetscInt *points = NULL; 6055 const PetscInt *clp, *perm = NULL; 6056 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 6057 6058 PetscFunctionBeginHot; 6059 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6060 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6061 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6062 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6063 PetscCall(DMPlexGetDepth(dm, &mdepth)); 6064 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 6065 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6066 if (mdepth == 1 && numFields < 2) { 6067 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 6068 PetscFunctionReturn(0); 6069 } 6070 /* Get points */ 6071 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6072 for (clsize = 0, p = 0; p < Np; p++) { 6073 PetscInt dof; 6074 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6075 clsize += dof; 6076 } 6077 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 6078 /* Filter points */ 6079 for (p = 0; p < numPoints * 2; p += 2) { 6080 PetscInt dep; 6081 6082 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 6083 if (dep != depth) continue; 6084 points[Np * 2 + 0] = points[p]; 6085 points[Np * 2 + 1] = points[p + 1]; 6086 ++Np; 6087 } 6088 /* Get array */ 6089 if (!values || !*values) { 6090 PetscInt asize = 0, dof; 6091 6092 for (p = 0; p < Np * 2; p += 2) { 6093 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 6094 asize += dof; 6095 } 6096 if (!values) { 6097 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6098 if (csize) *csize = asize; 6099 PetscFunctionReturn(0); 6100 } 6101 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6102 } else { 6103 array = *values; 6104 } 6105 PetscCall(VecGetArrayRead(v, &vArray)); 6106 /* Get values */ 6107 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6108 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6109 /* Cleanup points */ 6110 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6111 /* Cleanup array */ 6112 PetscCall(VecRestoreArrayRead(v, &vArray)); 6113 if (!*values) { 6114 if (csize) *csize = size; 6115 *values = array; 6116 } else { 6117 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6118 *csize = size; 6119 } 6120 PetscFunctionReturn(0); 6121 } 6122 6123 /*@C 6124 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6125 6126 Not collective 6127 6128 Input Parameters: 6129 + dm - The `DM` 6130 . section - The section describing the layout in v, or NULL to use the default section 6131 . v - The local vector 6132 . point - The point in the `DM` 6133 . csize - The number of values in the closure, or NULL 6134 - values - The array of values, which is a borrowed array and should not be freed 6135 6136 Level: intermediate 6137 6138 Note: 6139 The array values are discarded and not copied back into v. In order to copy values back to v, use `DMPlexVecSetClosure()` 6140 6141 Fortran Note: 6142 The csize argument is not present in the Fortran binding since it is internal to the array. 6143 6144 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6145 @*/ 6146 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6147 { 6148 PetscInt size = 0; 6149 6150 PetscFunctionBegin; 6151 /* Should work without recalculating size */ 6152 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6153 *values = NULL; 6154 PetscFunctionReturn(0); 6155 } 6156 6157 static inline void add(PetscScalar *x, PetscScalar y) 6158 { 6159 *x += y; 6160 } 6161 static inline void insert(PetscScalar *x, PetscScalar y) 6162 { 6163 *x = y; 6164 } 6165 6166 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[]) 6167 { 6168 PetscInt cdof; /* The number of constraints on this point */ 6169 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6170 PetscScalar *a; 6171 PetscInt off, cind = 0, k; 6172 6173 PetscFunctionBegin; 6174 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6175 PetscCall(PetscSectionGetOffset(section, point, &off)); 6176 a = &array[off]; 6177 if (!cdof || setBC) { 6178 if (clperm) { 6179 if (perm) { 6180 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6181 } else { 6182 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6183 } 6184 } else { 6185 if (perm) { 6186 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6187 } else { 6188 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6189 } 6190 } 6191 } else { 6192 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6193 if (clperm) { 6194 if (perm) { 6195 for (k = 0; k < dof; ++k) { 6196 if ((cind < cdof) && (k == cdofs[cind])) { 6197 ++cind; 6198 continue; 6199 } 6200 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6201 } 6202 } else { 6203 for (k = 0; k < dof; ++k) { 6204 if ((cind < cdof) && (k == cdofs[cind])) { 6205 ++cind; 6206 continue; 6207 } 6208 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6209 } 6210 } 6211 } else { 6212 if (perm) { 6213 for (k = 0; k < dof; ++k) { 6214 if ((cind < cdof) && (k == cdofs[cind])) { 6215 ++cind; 6216 continue; 6217 } 6218 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6219 } 6220 } else { 6221 for (k = 0; k < dof; ++k) { 6222 if ((cind < cdof) && (k == cdofs[cind])) { 6223 ++cind; 6224 continue; 6225 } 6226 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6227 } 6228 } 6229 } 6230 } 6231 PetscFunctionReturn(0); 6232 } 6233 6234 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[]) 6235 { 6236 PetscInt cdof; /* The number of constraints on this point */ 6237 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6238 PetscScalar *a; 6239 PetscInt off, cind = 0, k; 6240 6241 PetscFunctionBegin; 6242 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6243 PetscCall(PetscSectionGetOffset(section, point, &off)); 6244 a = &array[off]; 6245 if (cdof) { 6246 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6247 if (clperm) { 6248 if (perm) { 6249 for (k = 0; k < dof; ++k) { 6250 if ((cind < cdof) && (k == cdofs[cind])) { 6251 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6252 cind++; 6253 } 6254 } 6255 } else { 6256 for (k = 0; k < dof; ++k) { 6257 if ((cind < cdof) && (k == cdofs[cind])) { 6258 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6259 cind++; 6260 } 6261 } 6262 } 6263 } else { 6264 if (perm) { 6265 for (k = 0; k < dof; ++k) { 6266 if ((cind < cdof) && (k == cdofs[cind])) { 6267 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6268 cind++; 6269 } 6270 } 6271 } else { 6272 for (k = 0; k < dof; ++k) { 6273 if ((cind < cdof) && (k == cdofs[cind])) { 6274 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6275 cind++; 6276 } 6277 } 6278 } 6279 } 6280 } 6281 PetscFunctionReturn(0); 6282 } 6283 6284 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[]) 6285 { 6286 PetscScalar *a; 6287 PetscInt fdof, foff, fcdof, foffset = *offset; 6288 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6289 PetscInt cind = 0, b; 6290 6291 PetscFunctionBegin; 6292 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6293 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6294 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6295 a = &array[foff]; 6296 if (!fcdof || setBC) { 6297 if (clperm) { 6298 if (perm) { 6299 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6300 } else { 6301 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6302 } 6303 } else { 6304 if (perm) { 6305 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6306 } else { 6307 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6308 } 6309 } 6310 } else { 6311 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6312 if (clperm) { 6313 if (perm) { 6314 for (b = 0; b < fdof; b++) { 6315 if ((cind < fcdof) && (b == fcdofs[cind])) { 6316 ++cind; 6317 continue; 6318 } 6319 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6320 } 6321 } else { 6322 for (b = 0; b < fdof; b++) { 6323 if ((cind < fcdof) && (b == fcdofs[cind])) { 6324 ++cind; 6325 continue; 6326 } 6327 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6328 } 6329 } 6330 } else { 6331 if (perm) { 6332 for (b = 0; b < fdof; b++) { 6333 if ((cind < fcdof) && (b == fcdofs[cind])) { 6334 ++cind; 6335 continue; 6336 } 6337 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6338 } 6339 } else { 6340 for (b = 0; b < fdof; b++) { 6341 if ((cind < fcdof) && (b == fcdofs[cind])) { 6342 ++cind; 6343 continue; 6344 } 6345 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6346 } 6347 } 6348 } 6349 } 6350 *offset += fdof; 6351 PetscFunctionReturn(0); 6352 } 6353 6354 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[]) 6355 { 6356 PetscScalar *a; 6357 PetscInt fdof, foff, fcdof, foffset = *offset; 6358 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6359 PetscInt Nc, cind = 0, ncind = 0, b; 6360 PetscBool ncSet, fcSet; 6361 6362 PetscFunctionBegin; 6363 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6364 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6365 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6366 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6367 a = &array[foff]; 6368 if (fcdof) { 6369 /* We just override fcdof and fcdofs with Ncc and comps */ 6370 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6371 if (clperm) { 6372 if (perm) { 6373 if (comps) { 6374 for (b = 0; b < fdof; b++) { 6375 ncSet = fcSet = PETSC_FALSE; 6376 if (b % Nc == comps[ncind]) { 6377 ncind = (ncind + 1) % Ncc; 6378 ncSet = PETSC_TRUE; 6379 } 6380 if ((cind < fcdof) && (b == fcdofs[cind])) { 6381 ++cind; 6382 fcSet = PETSC_TRUE; 6383 } 6384 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6385 } 6386 } else { 6387 for (b = 0; b < fdof; b++) { 6388 if ((cind < fcdof) && (b == fcdofs[cind])) { 6389 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6390 ++cind; 6391 } 6392 } 6393 } 6394 } else { 6395 if (comps) { 6396 for (b = 0; b < fdof; b++) { 6397 ncSet = fcSet = PETSC_FALSE; 6398 if (b % Nc == comps[ncind]) { 6399 ncind = (ncind + 1) % Ncc; 6400 ncSet = PETSC_TRUE; 6401 } 6402 if ((cind < fcdof) && (b == fcdofs[cind])) { 6403 ++cind; 6404 fcSet = PETSC_TRUE; 6405 } 6406 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6407 } 6408 } else { 6409 for (b = 0; b < fdof; b++) { 6410 if ((cind < fcdof) && (b == fcdofs[cind])) { 6411 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6412 ++cind; 6413 } 6414 } 6415 } 6416 } 6417 } else { 6418 if (perm) { 6419 if (comps) { 6420 for (b = 0; b < fdof; b++) { 6421 ncSet = fcSet = PETSC_FALSE; 6422 if (b % Nc == comps[ncind]) { 6423 ncind = (ncind + 1) % Ncc; 6424 ncSet = PETSC_TRUE; 6425 } 6426 if ((cind < fcdof) && (b == fcdofs[cind])) { 6427 ++cind; 6428 fcSet = PETSC_TRUE; 6429 } 6430 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6431 } 6432 } else { 6433 for (b = 0; b < fdof; b++) { 6434 if ((cind < fcdof) && (b == fcdofs[cind])) { 6435 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6436 ++cind; 6437 } 6438 } 6439 } 6440 } else { 6441 if (comps) { 6442 for (b = 0; b < fdof; b++) { 6443 ncSet = fcSet = PETSC_FALSE; 6444 if (b % Nc == comps[ncind]) { 6445 ncind = (ncind + 1) % Ncc; 6446 ncSet = PETSC_TRUE; 6447 } 6448 if ((cind < fcdof) && (b == fcdofs[cind])) { 6449 ++cind; 6450 fcSet = PETSC_TRUE; 6451 } 6452 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6453 } 6454 } else { 6455 for (b = 0; b < fdof; b++) { 6456 if ((cind < fcdof) && (b == fcdofs[cind])) { 6457 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6458 ++cind; 6459 } 6460 } 6461 } 6462 } 6463 } 6464 } 6465 *offset += fdof; 6466 PetscFunctionReturn(0); 6467 } 6468 6469 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6470 { 6471 PetscScalar *array; 6472 const PetscInt *cone, *coneO; 6473 PetscInt pStart, pEnd, p, numPoints, off, dof; 6474 6475 PetscFunctionBeginHot; 6476 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6477 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6478 PetscCall(DMPlexGetCone(dm, point, &cone)); 6479 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6480 PetscCall(VecGetArray(v, &array)); 6481 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6482 const PetscInt cp = !p ? point : cone[p - 1]; 6483 const PetscInt o = !p ? 0 : coneO[p - 1]; 6484 6485 if ((cp < pStart) || (cp >= pEnd)) { 6486 dof = 0; 6487 continue; 6488 } 6489 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6490 /* ADD_VALUES */ 6491 { 6492 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6493 PetscScalar *a; 6494 PetscInt cdof, coff, cind = 0, k; 6495 6496 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6497 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6498 a = &array[coff]; 6499 if (!cdof) { 6500 if (o >= 0) { 6501 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6502 } else { 6503 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6504 } 6505 } else { 6506 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6507 if (o >= 0) { 6508 for (k = 0; k < dof; ++k) { 6509 if ((cind < cdof) && (k == cdofs[cind])) { 6510 ++cind; 6511 continue; 6512 } 6513 a[k] += values[off + k]; 6514 } 6515 } else { 6516 for (k = 0; k < dof; ++k) { 6517 if ((cind < cdof) && (k == cdofs[cind])) { 6518 ++cind; 6519 continue; 6520 } 6521 a[k] += values[off + dof - k - 1]; 6522 } 6523 } 6524 } 6525 } 6526 } 6527 PetscCall(VecRestoreArray(v, &array)); 6528 PetscFunctionReturn(0); 6529 } 6530 6531 /*@C 6532 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6533 6534 Not collective 6535 6536 Input Parameters: 6537 + dm - The `DM` 6538 . section - The section describing the layout in v, or NULL to use the default section 6539 . v - The local vector 6540 . point - The point in the DM 6541 . values - The array of values 6542 - mode - The insert mode. One of `INSERT_ALL_VALUES`, `ADD_ALL_VALUES`, `INSERT_VALUES`, `ADD_VALUES`, `INSERT_BC_VALUES`, and `ADD_BC_VALUES`, 6543 where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions. 6544 6545 Level: intermediate 6546 6547 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6548 @*/ 6549 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6550 { 6551 PetscSection clSection; 6552 IS clPoints; 6553 PetscScalar *array; 6554 PetscInt *points = NULL; 6555 const PetscInt *clp, *clperm = NULL; 6556 PetscInt depth, numFields, numPoints, p, clsize; 6557 6558 PetscFunctionBeginHot; 6559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6560 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6561 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6562 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6563 PetscCall(DMPlexGetDepth(dm, &depth)); 6564 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6565 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6566 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6567 PetscFunctionReturn(0); 6568 } 6569 /* Get points */ 6570 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6571 for (clsize = 0, p = 0; p < numPoints; p++) { 6572 PetscInt dof; 6573 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6574 clsize += dof; 6575 } 6576 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6577 /* Get array */ 6578 PetscCall(VecGetArray(v, &array)); 6579 /* Get values */ 6580 if (numFields > 0) { 6581 PetscInt offset = 0, f; 6582 for (f = 0; f < numFields; ++f) { 6583 const PetscInt **perms = NULL; 6584 const PetscScalar **flips = NULL; 6585 6586 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6587 switch (mode) { 6588 case INSERT_VALUES: 6589 for (p = 0; p < numPoints; p++) { 6590 const PetscInt point = points[2 * p]; 6591 const PetscInt *perm = perms ? perms[p] : NULL; 6592 const PetscScalar *flip = flips ? flips[p] : NULL; 6593 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6594 } 6595 break; 6596 case INSERT_ALL_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_TRUE, clperm, values, &offset, array); 6602 } 6603 break; 6604 case INSERT_BC_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 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6610 } 6611 break; 6612 case ADD_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 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6618 } 6619 break; 6620 case ADD_ALL_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_TRUE, clperm, values, &offset, array); 6626 } 6627 break; 6628 case ADD_BC_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 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6634 } 6635 break; 6636 default: 6637 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6638 } 6639 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6640 } 6641 } else { 6642 PetscInt dof, off; 6643 const PetscInt **perms = NULL; 6644 const PetscScalar **flips = NULL; 6645 6646 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6647 switch (mode) { 6648 case INSERT_VALUES: 6649 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6650 const PetscInt point = points[2 * p]; 6651 const PetscInt *perm = perms ? perms[p] : NULL; 6652 const PetscScalar *flip = flips ? flips[p] : NULL; 6653 PetscCall(PetscSectionGetDof(section, point, &dof)); 6654 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6655 } 6656 break; 6657 case INSERT_ALL_VALUES: 6658 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6659 const PetscInt point = points[2 * p]; 6660 const PetscInt *perm = perms ? perms[p] : NULL; 6661 const PetscScalar *flip = flips ? flips[p] : NULL; 6662 PetscCall(PetscSectionGetDof(section, point, &dof)); 6663 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6664 } 6665 break; 6666 case INSERT_BC_VALUES: 6667 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6668 const PetscInt point = points[2 * p]; 6669 const PetscInt *perm = perms ? perms[p] : NULL; 6670 const PetscScalar *flip = flips ? flips[p] : NULL; 6671 PetscCall(PetscSectionGetDof(section, point, &dof)); 6672 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6673 } 6674 break; 6675 case ADD_VALUES: 6676 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6677 const PetscInt point = points[2 * p]; 6678 const PetscInt *perm = perms ? perms[p] : NULL; 6679 const PetscScalar *flip = flips ? flips[p] : NULL; 6680 PetscCall(PetscSectionGetDof(section, point, &dof)); 6681 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6682 } 6683 break; 6684 case ADD_ALL_VALUES: 6685 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6686 const PetscInt point = points[2 * p]; 6687 const PetscInt *perm = perms ? perms[p] : NULL; 6688 const PetscScalar *flip = flips ? flips[p] : NULL; 6689 PetscCall(PetscSectionGetDof(section, point, &dof)); 6690 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6691 } 6692 break; 6693 case ADD_BC_VALUES: 6694 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6695 const PetscInt point = points[2 * p]; 6696 const PetscInt *perm = perms ? perms[p] : NULL; 6697 const PetscScalar *flip = flips ? flips[p] : NULL; 6698 PetscCall(PetscSectionGetDof(section, point, &dof)); 6699 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6700 } 6701 break; 6702 default: 6703 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6704 } 6705 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6706 } 6707 /* Cleanup points */ 6708 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6709 /* Cleanup array */ 6710 PetscCall(VecRestoreArray(v, &array)); 6711 PetscFunctionReturn(0); 6712 } 6713 6714 PetscErrorCode DMPlexVecSetStar(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6715 { 6716 const PetscInt *supp, *cone; 6717 PetscScalar *a; 6718 PetscInt dim, Ns, dof, off, n = 0; 6719 6720 PetscFunctionBegin; 6721 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6722 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6723 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6724 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6725 if (PetscDefined(USE_DEBUG)) { 6726 PetscInt vStart, vEnd; 6727 6728 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 6729 PetscCheck(point >= vStart && point < vEnd, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " must be a vertex in [%" PetscInt_FMT ", %" PetscInt_FMT "]", point, vStart, vEnd); 6730 } 6731 PetscValidScalarPointer(values, 5); 6732 6733 PetscCall(DMGetDimension(dm, &dim)); 6734 PetscCall(DMPlexGetSupportSize(dm, point, &Ns)); 6735 PetscCall(DMPlexGetSupport(dm, point, &supp)); 6736 PetscCheck(Ns == 2 * dim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " has support size %" PetscInt_FMT " != %" PetscInt_FMT, point, Ns, 2 * dim); 6737 PetscCall(VecGetArray(v, &a)); 6738 PetscCall(PetscSectionGetDof(section, point, &dof)); 6739 PetscCall(PetscSectionGetOffset(section, point, &off)); 6740 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6741 for (PetscInt d = 0; d < dim; ++d) { 6742 // Left edge 6743 PetscCall(DMPlexGetCone(dm, supp[2 * d + 0], &cone)); 6744 PetscCall(PetscSectionGetDof(section, cone[0], &dof)); 6745 PetscCall(PetscSectionGetOffset(section, cone[0], &off)); 6746 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6747 // Right edge 6748 PetscCall(DMPlexGetCone(dm, supp[2 * d + 1], &cone)); 6749 PetscCall(PetscSectionGetDof(section, cone[1], &dof)); 6750 PetscCall(PetscSectionGetOffset(section, cone[1], &off)); 6751 for (PetscInt i = 0; i < dof; ++i) a[off + i] = values[n++]; 6752 } 6753 PetscCall(VecRestoreArray(v, &a)); 6754 PetscFunctionReturn(0); 6755 } 6756 6757 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6758 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6759 { 6760 PetscFunctionBegin; 6761 *contains = PETSC_TRUE; 6762 if (label) { 6763 PetscInt fdof; 6764 6765 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6766 if (!*contains) { 6767 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6768 *offset += fdof; 6769 PetscFunctionReturn(0); 6770 } 6771 } 6772 PetscFunctionReturn(0); 6773 } 6774 6775 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6776 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) 6777 { 6778 PetscSection clSection; 6779 IS clPoints; 6780 PetscScalar *array; 6781 PetscInt *points = NULL; 6782 const PetscInt *clp; 6783 PetscInt numFields, numPoints, p; 6784 PetscInt offset = 0, f; 6785 6786 PetscFunctionBeginHot; 6787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6788 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6789 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6790 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6791 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6792 /* Get points */ 6793 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6794 /* Get array */ 6795 PetscCall(VecGetArray(v, &array)); 6796 /* Get values */ 6797 for (f = 0; f < numFields; ++f) { 6798 const PetscInt **perms = NULL; 6799 const PetscScalar **flips = NULL; 6800 PetscBool contains; 6801 6802 if (!fieldActive[f]) { 6803 for (p = 0; p < numPoints * 2; p += 2) { 6804 PetscInt fdof; 6805 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6806 offset += fdof; 6807 } 6808 continue; 6809 } 6810 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6811 switch (mode) { 6812 case INSERT_VALUES: 6813 for (p = 0; p < numPoints; p++) { 6814 const PetscInt point = points[2 * p]; 6815 const PetscInt *perm = perms ? perms[p] : NULL; 6816 const PetscScalar *flip = flips ? flips[p] : NULL; 6817 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6818 if (!contains) continue; 6819 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6820 } 6821 break; 6822 case INSERT_ALL_VALUES: 6823 for (p = 0; p < numPoints; p++) { 6824 const PetscInt point = points[2 * p]; 6825 const PetscInt *perm = perms ? perms[p] : NULL; 6826 const PetscScalar *flip = flips ? flips[p] : NULL; 6827 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6828 if (!contains) continue; 6829 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6830 } 6831 break; 6832 case INSERT_BC_VALUES: 6833 for (p = 0; p < numPoints; p++) { 6834 const PetscInt point = points[2 * p]; 6835 const PetscInt *perm = perms ? perms[p] : NULL; 6836 const PetscScalar *flip = flips ? flips[p] : NULL; 6837 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6838 if (!contains) continue; 6839 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6840 } 6841 break; 6842 case ADD_VALUES: 6843 for (p = 0; p < numPoints; p++) { 6844 const PetscInt point = points[2 * p]; 6845 const PetscInt *perm = perms ? perms[p] : NULL; 6846 const PetscScalar *flip = flips ? flips[p] : NULL; 6847 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6848 if (!contains) continue; 6849 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6850 } 6851 break; 6852 case ADD_ALL_VALUES: 6853 for (p = 0; p < numPoints; p++) { 6854 const PetscInt point = points[2 * p]; 6855 const PetscInt *perm = perms ? perms[p] : NULL; 6856 const PetscScalar *flip = flips ? flips[p] : NULL; 6857 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6858 if (!contains) continue; 6859 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6860 } 6861 break; 6862 default: 6863 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6864 } 6865 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6866 } 6867 /* Cleanup points */ 6868 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6869 /* Cleanup array */ 6870 PetscCall(VecRestoreArray(v, &array)); 6871 PetscFunctionReturn(0); 6872 } 6873 6874 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6875 { 6876 PetscMPIInt rank; 6877 PetscInt i, j; 6878 6879 PetscFunctionBegin; 6880 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6881 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6882 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6883 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6884 numCIndices = numCIndices ? numCIndices : numRIndices; 6885 if (!values) PetscFunctionReturn(0); 6886 for (i = 0; i < numRIndices; i++) { 6887 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6888 for (j = 0; j < numCIndices; j++) { 6889 #if defined(PETSC_USE_COMPLEX) 6890 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6891 #else 6892 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6893 #endif 6894 } 6895 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6896 } 6897 PetscFunctionReturn(0); 6898 } 6899 6900 /* 6901 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6902 6903 Input Parameters: 6904 + section - The section for this data layout 6905 . islocal - Is the section (and thus indices being requested) local or global? 6906 . point - The point contributing dofs with these indices 6907 . off - The global offset of this point 6908 . loff - The local offset of each field 6909 . setBC - The flag determining whether to include indices of boundary values 6910 . perm - A permutation of the dofs on this point, or NULL 6911 - indperm - A permutation of the entire indices array, or NULL 6912 6913 Output Parameter: 6914 . indices - Indices for dofs on this point 6915 6916 Level: developer 6917 6918 Note: The indices could be local or global, depending on the value of 'off'. 6919 */ 6920 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6921 { 6922 PetscInt dof; /* The number of unknowns on this point */ 6923 PetscInt cdof; /* The number of constraints on this point */ 6924 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6925 PetscInt cind = 0, k; 6926 6927 PetscFunctionBegin; 6928 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6929 PetscCall(PetscSectionGetDof(section, point, &dof)); 6930 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6931 if (!cdof || setBC) { 6932 for (k = 0; k < dof; ++k) { 6933 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6934 const PetscInt ind = indperm ? indperm[preind] : preind; 6935 6936 indices[ind] = off + k; 6937 } 6938 } else { 6939 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6940 for (k = 0; k < dof; ++k) { 6941 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6942 const PetscInt ind = indperm ? indperm[preind] : preind; 6943 6944 if ((cind < cdof) && (k == cdofs[cind])) { 6945 /* Insert check for returning constrained indices */ 6946 indices[ind] = -(off + k + 1); 6947 ++cind; 6948 } else { 6949 indices[ind] = off + k - (islocal ? 0 : cind); 6950 } 6951 } 6952 } 6953 *loff += dof; 6954 PetscFunctionReturn(0); 6955 } 6956 6957 /* 6958 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6959 6960 Input Parameters: 6961 + section - a section (global or local) 6962 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6963 . point - point within section 6964 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6965 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6966 . setBC - identify constrained (boundary condition) points via involution. 6967 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6968 . permsoff - offset 6969 - indperm - index permutation 6970 6971 Output Parameter: 6972 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6973 . indices - array to hold indices (as defined by section) of each dof associated with point 6974 6975 Notes: 6976 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6977 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6978 in the local vector. 6979 6980 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6981 significant). It is invalid to call with a global section and setBC=true. 6982 6983 Developer Note: 6984 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6985 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6986 offset could be obtained from the section instead of passing it explicitly as we do now. 6987 6988 Example: 6989 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6990 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6991 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6992 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. 6993 6994 Level: developer 6995 */ 6996 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[]) 6997 { 6998 PetscInt numFields, foff, f; 6999 7000 PetscFunctionBegin; 7001 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 7002 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7003 for (f = 0, foff = 0; f < numFields; ++f) { 7004 PetscInt fdof, cfdof; 7005 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7006 PetscInt cind = 0, b; 7007 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7008 7009 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7010 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7011 if (!cfdof || setBC) { 7012 for (b = 0; b < fdof; ++b) { 7013 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7014 const PetscInt ind = indperm ? indperm[preind] : preind; 7015 7016 indices[ind] = off + foff + b; 7017 } 7018 } else { 7019 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7020 for (b = 0; b < fdof; ++b) { 7021 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7022 const PetscInt ind = indperm ? indperm[preind] : preind; 7023 7024 if ((cind < cfdof) && (b == fcdofs[cind])) { 7025 indices[ind] = -(off + foff + b + 1); 7026 ++cind; 7027 } else { 7028 indices[ind] = off + foff + b - (islocal ? 0 : cind); 7029 } 7030 } 7031 } 7032 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 7033 foffs[f] += fdof; 7034 } 7035 PetscFunctionReturn(0); 7036 } 7037 7038 /* 7039 This version believes the globalSection offsets for each field, rather than just the point offset 7040 7041 . foffs - The offset into 'indices' for each field, since it is segregated by field 7042 7043 Notes: 7044 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 7045 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 7046 */ 7047 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 7048 { 7049 PetscInt numFields, foff, f; 7050 7051 PetscFunctionBegin; 7052 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7053 for (f = 0; f < numFields; ++f) { 7054 PetscInt fdof, cfdof; 7055 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 7056 PetscInt cind = 0, b; 7057 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 7058 7059 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 7060 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 7061 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 7062 if (!cfdof) { 7063 for (b = 0; b < fdof; ++b) { 7064 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7065 const PetscInt ind = indperm ? indperm[preind] : preind; 7066 7067 indices[ind] = foff + b; 7068 } 7069 } else { 7070 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 7071 for (b = 0; b < fdof; ++b) { 7072 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 7073 const PetscInt ind = indperm ? indperm[preind] : preind; 7074 7075 if ((cind < cfdof) && (b == fcdofs[cind])) { 7076 indices[ind] = -(foff + b + 1); 7077 ++cind; 7078 } else { 7079 indices[ind] = foff + b - cind; 7080 } 7081 } 7082 } 7083 foffs[f] += fdof; 7084 } 7085 PetscFunctionReturn(0); 7086 } 7087 7088 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) 7089 { 7090 Mat cMat; 7091 PetscSection aSec, cSec; 7092 IS aIS; 7093 PetscInt aStart = -1, aEnd = -1; 7094 const PetscInt *anchors; 7095 PetscInt numFields, f, p, q, newP = 0; 7096 PetscInt newNumPoints = 0, newNumIndices = 0; 7097 PetscInt *newPoints, *indices, *newIndices; 7098 PetscInt maxAnchor, maxDof; 7099 PetscInt newOffsets[32]; 7100 PetscInt *pointMatOffsets[32]; 7101 PetscInt *newPointOffsets[32]; 7102 PetscScalar *pointMat[32]; 7103 PetscScalar *newValues = NULL, *tmpValues; 7104 PetscBool anyConstrained = PETSC_FALSE; 7105 7106 PetscFunctionBegin; 7107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7108 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7109 PetscCall(PetscSectionGetNumFields(section, &numFields)); 7110 7111 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 7112 /* if there are point-to-point constraints */ 7113 if (aSec) { 7114 PetscCall(PetscArrayzero(newOffsets, 32)); 7115 PetscCall(ISGetIndices(aIS, &anchors)); 7116 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 7117 /* figure out how many points are going to be in the new element matrix 7118 * (we allow double counting, because it's all just going to be summed 7119 * into the global matrix anyway) */ 7120 for (p = 0; p < 2 * numPoints; p += 2) { 7121 PetscInt b = points[p]; 7122 PetscInt bDof = 0, bSecDof; 7123 7124 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7125 if (!bSecDof) continue; 7126 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7127 if (bDof) { 7128 /* this point is constrained */ 7129 /* it is going to be replaced by its anchors */ 7130 PetscInt bOff, q; 7131 7132 anyConstrained = PETSC_TRUE; 7133 newNumPoints += bDof; 7134 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7135 for (q = 0; q < bDof; q++) { 7136 PetscInt a = anchors[bOff + q]; 7137 PetscInt aDof; 7138 7139 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7140 newNumIndices += aDof; 7141 for (f = 0; f < numFields; ++f) { 7142 PetscInt fDof; 7143 7144 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7145 newOffsets[f + 1] += fDof; 7146 } 7147 } 7148 } else { 7149 /* this point is not constrained */ 7150 newNumPoints++; 7151 newNumIndices += bSecDof; 7152 for (f = 0; f < numFields; ++f) { 7153 PetscInt fDof; 7154 7155 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7156 newOffsets[f + 1] += fDof; 7157 } 7158 } 7159 } 7160 } 7161 if (!anyConstrained) { 7162 if (outNumPoints) *outNumPoints = 0; 7163 if (outNumIndices) *outNumIndices = 0; 7164 if (outPoints) *outPoints = NULL; 7165 if (outValues) *outValues = NULL; 7166 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7167 PetscFunctionReturn(0); 7168 } 7169 7170 if (outNumPoints) *outNumPoints = newNumPoints; 7171 if (outNumIndices) *outNumIndices = newNumIndices; 7172 7173 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7174 7175 if (!outPoints && !outValues) { 7176 if (offsets) { 7177 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7178 } 7179 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7180 PetscFunctionReturn(0); 7181 } 7182 7183 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7184 7185 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7186 7187 /* workspaces */ 7188 if (numFields) { 7189 for (f = 0; f < numFields; f++) { 7190 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7191 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7192 } 7193 } else { 7194 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7195 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7196 } 7197 7198 /* get workspaces for the point-to-point matrices */ 7199 if (numFields) { 7200 PetscInt totalOffset, totalMatOffset; 7201 7202 for (p = 0; p < numPoints; p++) { 7203 PetscInt b = points[2 * p]; 7204 PetscInt bDof = 0, bSecDof; 7205 7206 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7207 if (!bSecDof) { 7208 for (f = 0; f < numFields; f++) { 7209 newPointOffsets[f][p + 1] = 0; 7210 pointMatOffsets[f][p + 1] = 0; 7211 } 7212 continue; 7213 } 7214 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7215 if (bDof) { 7216 for (f = 0; f < numFields; f++) { 7217 PetscInt fDof, q, bOff, allFDof = 0; 7218 7219 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7220 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7221 for (q = 0; q < bDof; q++) { 7222 PetscInt a = anchors[bOff + q]; 7223 PetscInt aFDof; 7224 7225 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7226 allFDof += aFDof; 7227 } 7228 newPointOffsets[f][p + 1] = allFDof; 7229 pointMatOffsets[f][p + 1] = fDof * allFDof; 7230 } 7231 } else { 7232 for (f = 0; f < numFields; f++) { 7233 PetscInt fDof; 7234 7235 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7236 newPointOffsets[f][p + 1] = fDof; 7237 pointMatOffsets[f][p + 1] = 0; 7238 } 7239 } 7240 } 7241 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7242 newPointOffsets[f][0] = totalOffset; 7243 pointMatOffsets[f][0] = totalMatOffset; 7244 for (p = 0; p < numPoints; p++) { 7245 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7246 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7247 } 7248 totalOffset = newPointOffsets[f][numPoints]; 7249 totalMatOffset = pointMatOffsets[f][numPoints]; 7250 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7251 } 7252 } else { 7253 for (p = 0; p < numPoints; p++) { 7254 PetscInt b = points[2 * p]; 7255 PetscInt bDof = 0, bSecDof; 7256 7257 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7258 if (!bSecDof) { 7259 newPointOffsets[0][p + 1] = 0; 7260 pointMatOffsets[0][p + 1] = 0; 7261 continue; 7262 } 7263 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7264 if (bDof) { 7265 PetscInt bOff, q, allDof = 0; 7266 7267 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7268 for (q = 0; q < bDof; q++) { 7269 PetscInt a = anchors[bOff + q], aDof; 7270 7271 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7272 allDof += aDof; 7273 } 7274 newPointOffsets[0][p + 1] = allDof; 7275 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7276 } else { 7277 newPointOffsets[0][p + 1] = bSecDof; 7278 pointMatOffsets[0][p + 1] = 0; 7279 } 7280 } 7281 newPointOffsets[0][0] = 0; 7282 pointMatOffsets[0][0] = 0; 7283 for (p = 0; p < numPoints; p++) { 7284 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7285 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7286 } 7287 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7288 } 7289 7290 /* output arrays */ 7291 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7292 7293 /* get the point-to-point matrices; construct newPoints */ 7294 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7295 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7296 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7297 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7298 if (numFields) { 7299 for (p = 0, newP = 0; p < numPoints; p++) { 7300 PetscInt b = points[2 * p]; 7301 PetscInt o = points[2 * p + 1]; 7302 PetscInt bDof = 0, bSecDof; 7303 7304 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7305 if (!bSecDof) continue; 7306 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7307 if (bDof) { 7308 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7309 7310 fStart[0] = 0; 7311 fEnd[0] = 0; 7312 for (f = 0; f < numFields; f++) { 7313 PetscInt fDof; 7314 7315 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7316 fStart[f + 1] = fStart[f] + fDof; 7317 fEnd[f + 1] = fStart[f + 1]; 7318 } 7319 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7320 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7321 7322 fAnchorStart[0] = 0; 7323 fAnchorEnd[0] = 0; 7324 for (f = 0; f < numFields; f++) { 7325 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7326 7327 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7328 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7329 } 7330 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7331 for (q = 0; q < bDof; q++) { 7332 PetscInt a = anchors[bOff + q], aOff; 7333 7334 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7335 newPoints[2 * (newP + q)] = a; 7336 newPoints[2 * (newP + q) + 1] = 0; 7337 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7338 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7339 } 7340 newP += bDof; 7341 7342 if (outValues) { 7343 /* get the point-to-point submatrix */ 7344 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])); 7345 } 7346 } else { 7347 newPoints[2 * newP] = b; 7348 newPoints[2 * newP + 1] = o; 7349 newP++; 7350 } 7351 } 7352 } else { 7353 for (p = 0; p < numPoints; p++) { 7354 PetscInt b = points[2 * p]; 7355 PetscInt o = points[2 * p + 1]; 7356 PetscInt bDof = 0, bSecDof; 7357 7358 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7359 if (!bSecDof) continue; 7360 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7361 if (bDof) { 7362 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7363 7364 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7365 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7366 7367 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7368 for (q = 0; q < bDof; q++) { 7369 PetscInt a = anchors[bOff + q], aOff; 7370 7371 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7372 7373 newPoints[2 * (newP + q)] = a; 7374 newPoints[2 * (newP + q) + 1] = 0; 7375 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7376 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7377 } 7378 newP += bDof; 7379 7380 /* get the point-to-point submatrix */ 7381 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7382 } else { 7383 newPoints[2 * newP] = b; 7384 newPoints[2 * newP + 1] = o; 7385 newP++; 7386 } 7387 } 7388 } 7389 7390 if (outValues) { 7391 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7392 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7393 /* multiply constraints on the right */ 7394 if (numFields) { 7395 for (f = 0; f < numFields; f++) { 7396 PetscInt oldOff = offsets[f]; 7397 7398 for (p = 0; p < numPoints; p++) { 7399 PetscInt cStart = newPointOffsets[f][p]; 7400 PetscInt b = points[2 * p]; 7401 PetscInt c, r, k; 7402 PetscInt dof; 7403 7404 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7405 if (!dof) continue; 7406 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7407 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7408 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7409 7410 for (r = 0; r < numIndices; r++) { 7411 for (c = 0; c < nCols; c++) { 7412 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7413 } 7414 } 7415 } else { 7416 /* copy this column as is */ 7417 for (r = 0; r < numIndices; r++) { 7418 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7419 } 7420 } 7421 oldOff += dof; 7422 } 7423 } 7424 } else { 7425 PetscInt oldOff = 0; 7426 for (p = 0; p < numPoints; p++) { 7427 PetscInt cStart = newPointOffsets[0][p]; 7428 PetscInt b = points[2 * p]; 7429 PetscInt c, r, k; 7430 PetscInt dof; 7431 7432 PetscCall(PetscSectionGetDof(section, b, &dof)); 7433 if (!dof) continue; 7434 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7435 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7436 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7437 7438 for (r = 0; r < numIndices; r++) { 7439 for (c = 0; c < nCols; c++) { 7440 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7441 } 7442 } 7443 } else { 7444 /* copy this column as is */ 7445 for (r = 0; r < numIndices; r++) { 7446 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7447 } 7448 } 7449 oldOff += dof; 7450 } 7451 } 7452 7453 if (multiplyLeft) { 7454 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7455 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7456 /* multiply constraints transpose on the left */ 7457 if (numFields) { 7458 for (f = 0; f < numFields; f++) { 7459 PetscInt oldOff = offsets[f]; 7460 7461 for (p = 0; p < numPoints; p++) { 7462 PetscInt rStart = newPointOffsets[f][p]; 7463 PetscInt b = points[2 * p]; 7464 PetscInt c, r, k; 7465 PetscInt dof; 7466 7467 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7468 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7469 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7470 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7471 7472 for (r = 0; r < nRows; r++) { 7473 for (c = 0; c < newNumIndices; c++) { 7474 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7475 } 7476 } 7477 } else { 7478 /* copy this row as is */ 7479 for (r = 0; r < dof; r++) { 7480 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7481 } 7482 } 7483 oldOff += dof; 7484 } 7485 } 7486 } else { 7487 PetscInt oldOff = 0; 7488 7489 for (p = 0; p < numPoints; p++) { 7490 PetscInt rStart = newPointOffsets[0][p]; 7491 PetscInt b = points[2 * p]; 7492 PetscInt c, r, k; 7493 PetscInt dof; 7494 7495 PetscCall(PetscSectionGetDof(section, b, &dof)); 7496 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7497 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7498 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7499 7500 for (r = 0; r < nRows; r++) { 7501 for (c = 0; c < newNumIndices; c++) { 7502 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7503 } 7504 } 7505 } else { 7506 /* copy this row as is */ 7507 for (r = 0; r < dof; r++) { 7508 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7509 } 7510 } 7511 oldOff += dof; 7512 } 7513 } 7514 7515 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7516 } else { 7517 newValues = tmpValues; 7518 } 7519 } 7520 7521 /* clean up */ 7522 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7523 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7524 7525 if (numFields) { 7526 for (f = 0; f < numFields; f++) { 7527 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7528 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7529 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7530 } 7531 } else { 7532 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7533 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7534 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7535 } 7536 PetscCall(ISRestoreIndices(aIS, &anchors)); 7537 7538 /* output */ 7539 if (outPoints) { 7540 *outPoints = newPoints; 7541 } else { 7542 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7543 } 7544 if (outValues) *outValues = newValues; 7545 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7546 PetscFunctionReturn(0); 7547 } 7548 7549 /*@C 7550 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7551 7552 Not collective 7553 7554 Input Parameters: 7555 + dm - The `DM` 7556 . section - The `PetscSection` describing the points (a local section) 7557 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7558 . point - The point defining the closure 7559 - useClPerm - Use the closure point permutation if available 7560 7561 Output Parameters: 7562 + numIndices - The number of dof indices in the closure of point with the input sections 7563 . indices - The dof indices 7564 . outOffsets - Array to write the field offsets into, or NULL 7565 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7566 7567 Level: advanced 7568 7569 Notes: 7570 Must call `DMPlexRestoreClosureIndices()` to free allocated memory 7571 7572 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7573 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7574 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7575 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7576 indices (with the above semantics) are implied. 7577 7578 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, 7579 `PetscSection`, `DMGetGlobalSection()` 7580 @*/ 7581 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7582 { 7583 /* Closure ordering */ 7584 PetscSection clSection; 7585 IS clPoints; 7586 const PetscInt *clp; 7587 PetscInt *points; 7588 const PetscInt *clperm = NULL; 7589 /* Dof permutation and sign flips */ 7590 const PetscInt **perms[32] = {NULL}; 7591 const PetscScalar **flips[32] = {NULL}; 7592 PetscScalar *valCopy = NULL; 7593 /* Hanging node constraints */ 7594 PetscInt *pointsC = NULL; 7595 PetscScalar *valuesC = NULL; 7596 PetscInt NclC, NiC; 7597 7598 PetscInt *idx; 7599 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7600 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7601 7602 PetscFunctionBeginHot; 7603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7604 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7605 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7606 if (numIndices) PetscValidIntPointer(numIndices, 6); 7607 if (indices) PetscValidPointer(indices, 7); 7608 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7609 if (values) PetscValidPointer(values, 9); 7610 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7611 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7612 PetscCall(PetscArrayzero(offsets, 32)); 7613 /* 1) Get points in closure */ 7614 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7615 if (useClPerm) { 7616 PetscInt depth, clsize; 7617 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7618 for (clsize = 0, p = 0; p < Ncl; p++) { 7619 PetscInt dof; 7620 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7621 clsize += dof; 7622 } 7623 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7624 } 7625 /* 2) Get number of indices on these points and field offsets from section */ 7626 for (p = 0; p < Ncl * 2; p += 2) { 7627 PetscInt dof, fdof; 7628 7629 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7630 for (f = 0; f < Nf; ++f) { 7631 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7632 offsets[f + 1] += fdof; 7633 } 7634 Ni += dof; 7635 } 7636 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7637 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7638 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7639 for (f = 0; f < PetscMax(1, Nf); ++f) { 7640 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7641 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7642 /* may need to apply sign changes to the element matrix */ 7643 if (values && flips[f]) { 7644 PetscInt foffset = offsets[f]; 7645 7646 for (p = 0; p < Ncl; ++p) { 7647 PetscInt pnt = points[2 * p], fdof; 7648 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7649 7650 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7651 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7652 if (flip) { 7653 PetscInt i, j, k; 7654 7655 if (!valCopy) { 7656 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7657 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7658 *values = valCopy; 7659 } 7660 for (i = 0; i < fdof; ++i) { 7661 PetscScalar fval = flip[i]; 7662 7663 for (k = 0; k < Ni; ++k) { 7664 valCopy[Ni * (foffset + i) + k] *= fval; 7665 valCopy[Ni * k + (foffset + i)] *= fval; 7666 } 7667 } 7668 } 7669 foffset += fdof; 7670 } 7671 } 7672 } 7673 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7674 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7675 if (NclC) { 7676 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7677 for (f = 0; f < PetscMax(1, Nf); ++f) { 7678 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7679 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7680 } 7681 for (f = 0; f < PetscMax(1, Nf); ++f) { 7682 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7683 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7684 } 7685 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7686 Ncl = NclC; 7687 Ni = NiC; 7688 points = pointsC; 7689 if (values) *values = valuesC; 7690 } 7691 /* 5) Calculate indices */ 7692 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7693 if (Nf) { 7694 PetscInt idxOff; 7695 PetscBool useFieldOffsets; 7696 7697 if (outOffsets) { 7698 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7699 } 7700 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7701 if (useFieldOffsets) { 7702 for (p = 0; p < Ncl; ++p) { 7703 const PetscInt pnt = points[p * 2]; 7704 7705 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7706 } 7707 } else { 7708 for (p = 0; p < Ncl; ++p) { 7709 const PetscInt pnt = points[p * 2]; 7710 7711 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7712 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7713 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7714 * global section. */ 7715 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7716 } 7717 } 7718 } else { 7719 PetscInt off = 0, idxOff; 7720 7721 for (p = 0; p < Ncl; ++p) { 7722 const PetscInt pnt = points[p * 2]; 7723 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7724 7725 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7726 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7727 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7728 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7729 } 7730 } 7731 /* 6) Cleanup */ 7732 for (f = 0; f < PetscMax(1, Nf); ++f) { 7733 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7734 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7735 } 7736 if (NclC) { 7737 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7738 } else { 7739 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7740 } 7741 7742 if (numIndices) *numIndices = Ni; 7743 if (indices) *indices = idx; 7744 PetscFunctionReturn(0); 7745 } 7746 7747 /*@C 7748 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7749 7750 Not collective 7751 7752 Input Parameters: 7753 + dm - The `DM` 7754 . section - The `PetscSection` describing the points (a local section) 7755 . idxSection - The `PetscSection` from which to obtain indices (may be local or global) 7756 . point - The point defining the closure 7757 - useClPerm - Use the closure point permutation if available 7758 7759 Output Parameters: 7760 + numIndices - The number of dof indices in the closure of point with the input sections 7761 . indices - The dof indices 7762 . outOffsets - Array to write the field offsets into, or NULL 7763 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7764 7765 Level: advanced 7766 7767 Notes: 7768 If values were modified, the user is responsible for calling `DMRestoreWorkArray`(dm, 0, `MPIU_SCALAR`, &values). 7769 7770 If idxSection is global, any constrained dofs (see `DMAddBoundary()`, for example) will get negative indices. The value 7771 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7772 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7773 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7774 indices (with the above semantics) are implied. 7775 7776 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7777 @*/ 7778 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7779 { 7780 PetscFunctionBegin; 7781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7782 PetscValidPointer(indices, 7); 7783 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7784 PetscFunctionReturn(0); 7785 } 7786 7787 /*@C 7788 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7789 7790 Not collective 7791 7792 Input Parameters: 7793 + dm - The `DM` 7794 . section - The section describing the layout in v, or NULL to use the default section 7795 . globalSection - The section describing the layout in v, or NULL to use the default global section 7796 . A - The matrix 7797 . point - The point in the `DM` 7798 . values - The array of values 7799 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7800 7801 Level: intermediate 7802 7803 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7804 @*/ 7805 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7806 { 7807 DM_Plex *mesh = (DM_Plex *)dm->data; 7808 PetscInt *indices; 7809 PetscInt numIndices; 7810 const PetscScalar *valuesOrig = values; 7811 PetscErrorCode ierr; 7812 7813 PetscFunctionBegin; 7814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7815 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7816 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7817 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7818 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7819 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7820 7821 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7822 7823 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7824 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7825 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7826 if (ierr) { 7827 PetscMPIInt rank; 7828 7829 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7830 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7831 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7832 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7833 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7834 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7835 } 7836 if (mesh->printFEM > 1) { 7837 PetscInt i; 7838 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7839 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7840 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7841 } 7842 7843 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7844 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7845 PetscFunctionReturn(0); 7846 } 7847 7848 /*@C 7849 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7850 7851 Not collective 7852 7853 Input Parameters: 7854 + dmRow - The `DM` for the row fields 7855 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7856 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7857 . dmCol - The `DM` for the column fields 7858 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7859 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7860 . A - The matrix 7861 . point - The point in the `DM` 7862 . values - The array of values 7863 - mode - The insert mode, where `INSERT_ALL_VALUES` and `ADD_ALL_VALUES` also overwrite boundary conditions 7864 7865 Level: intermediate 7866 7867 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7868 @*/ 7869 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7870 { 7871 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7872 PetscInt *indicesRow, *indicesCol; 7873 PetscInt numIndicesRow, numIndicesCol; 7874 const PetscScalar *valuesOrig = values; 7875 PetscErrorCode ierr; 7876 7877 PetscFunctionBegin; 7878 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7879 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7880 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7881 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7882 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7883 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7884 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7885 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7886 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7887 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7888 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7889 7890 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7891 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7892 7893 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7894 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7895 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7896 if (ierr) { 7897 PetscMPIInt rank; 7898 7899 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7900 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7901 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7902 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7903 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7904 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7905 } 7906 7907 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7908 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7909 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7910 PetscFunctionReturn(0); 7911 } 7912 7913 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7914 { 7915 DM_Plex *mesh = (DM_Plex *)dmf->data; 7916 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7917 PetscInt *cpoints = NULL; 7918 PetscInt *findices, *cindices; 7919 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7920 PetscInt foffsets[32], coffsets[32]; 7921 DMPolytopeType ct; 7922 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7923 PetscErrorCode ierr; 7924 7925 PetscFunctionBegin; 7926 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7927 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7928 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7929 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7930 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7931 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7932 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7933 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7934 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7935 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7936 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7937 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7938 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7939 PetscCall(PetscArrayzero(foffsets, 32)); 7940 PetscCall(PetscArrayzero(coffsets, 32)); 7941 /* Column indices */ 7942 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7943 maxFPoints = numCPoints; 7944 /* Compress out points not in the section */ 7945 /* TODO: Squeeze out points with 0 dof as well */ 7946 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7947 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7948 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7949 cpoints[q * 2] = cpoints[p]; 7950 cpoints[q * 2 + 1] = cpoints[p + 1]; 7951 ++q; 7952 } 7953 } 7954 numCPoints = q; 7955 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7956 PetscInt fdof; 7957 7958 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7959 if (!dof) continue; 7960 for (f = 0; f < numFields; ++f) { 7961 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7962 coffsets[f + 1] += fdof; 7963 } 7964 numCIndices += dof; 7965 } 7966 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7967 /* Row indices */ 7968 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7969 { 7970 DMPlexTransform tr; 7971 DMPolytopeType *rct; 7972 PetscInt *rsize, *rcone, *rornt, Nt; 7973 7974 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7975 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7976 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7977 numSubcells = rsize[Nt - 1]; 7978 PetscCall(DMPlexTransformDestroy(&tr)); 7979 } 7980 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7981 for (r = 0, q = 0; r < numSubcells; ++r) { 7982 /* TODO Map from coarse to fine cells */ 7983 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7984 /* Compress out points not in the section */ 7985 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7986 for (p = 0; p < numFPoints * 2; p += 2) { 7987 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7988 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7989 if (!dof) continue; 7990 for (s = 0; s < q; ++s) 7991 if (fpoints[p] == ftotpoints[s * 2]) break; 7992 if (s < q) continue; 7993 ftotpoints[q * 2] = fpoints[p]; 7994 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7995 ++q; 7996 } 7997 } 7998 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7999 } 8000 numFPoints = q; 8001 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8002 PetscInt fdof; 8003 8004 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8005 if (!dof) continue; 8006 for (f = 0; f < numFields; ++f) { 8007 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8008 foffsets[f + 1] += fdof; 8009 } 8010 numFIndices += dof; 8011 } 8012 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8013 8014 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8015 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8016 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8017 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8018 if (numFields) { 8019 const PetscInt **permsF[32] = {NULL}; 8020 const PetscInt **permsC[32] = {NULL}; 8021 8022 for (f = 0; f < numFields; f++) { 8023 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8024 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8025 } 8026 for (p = 0; p < numFPoints; p++) { 8027 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8028 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8029 } 8030 for (p = 0; p < numCPoints; p++) { 8031 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8032 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8033 } 8034 for (f = 0; f < numFields; f++) { 8035 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8036 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8037 } 8038 } else { 8039 const PetscInt **permsF = NULL; 8040 const PetscInt **permsC = NULL; 8041 8042 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8043 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8044 for (p = 0, off = 0; p < numFPoints; p++) { 8045 const PetscInt *perm = permsF ? permsF[p] : NULL; 8046 8047 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8048 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8049 } 8050 for (p = 0, off = 0; p < numCPoints; p++) { 8051 const PetscInt *perm = permsC ? permsC[p] : NULL; 8052 8053 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8054 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8055 } 8056 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8057 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8058 } 8059 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8060 /* TODO: flips */ 8061 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 8062 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 8063 if (ierr) { 8064 PetscMPIInt rank; 8065 8066 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 8067 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 8068 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 8069 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8070 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8071 } 8072 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8073 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8074 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 8075 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 8076 PetscFunctionReturn(0); 8077 } 8078 8079 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 8080 { 8081 PetscInt *fpoints = NULL, *ftotpoints = NULL; 8082 PetscInt *cpoints = NULL; 8083 PetscInt foffsets[32], coffsets[32]; 8084 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 8085 DMPolytopeType ct; 8086 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 8087 8088 PetscFunctionBegin; 8089 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 8090 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 8091 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 8092 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 8093 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 8094 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 8095 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 8096 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 8097 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 8098 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 8099 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 8100 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 8101 PetscCall(PetscArrayzero(foffsets, 32)); 8102 PetscCall(PetscArrayzero(coffsets, 32)); 8103 /* Column indices */ 8104 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8105 maxFPoints = numCPoints; 8106 /* Compress out points not in the section */ 8107 /* TODO: Squeeze out points with 0 dof as well */ 8108 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 8109 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 8110 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 8111 cpoints[q * 2] = cpoints[p]; 8112 cpoints[q * 2 + 1] = cpoints[p + 1]; 8113 ++q; 8114 } 8115 } 8116 numCPoints = q; 8117 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 8118 PetscInt fdof; 8119 8120 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 8121 if (!dof) continue; 8122 for (f = 0; f < numFields; ++f) { 8123 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 8124 coffsets[f + 1] += fdof; 8125 } 8126 numCIndices += dof; 8127 } 8128 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 8129 /* Row indices */ 8130 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 8131 { 8132 DMPlexTransform tr; 8133 DMPolytopeType *rct; 8134 PetscInt *rsize, *rcone, *rornt, Nt; 8135 8136 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 8137 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8138 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8139 numSubcells = rsize[Nt - 1]; 8140 PetscCall(DMPlexTransformDestroy(&tr)); 8141 } 8142 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8143 for (r = 0, q = 0; r < numSubcells; ++r) { 8144 /* TODO Map from coarse to fine cells */ 8145 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8146 /* Compress out points not in the section */ 8147 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8148 for (p = 0; p < numFPoints * 2; p += 2) { 8149 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8150 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8151 if (!dof) continue; 8152 for (s = 0; s < q; ++s) 8153 if (fpoints[p] == ftotpoints[s * 2]) break; 8154 if (s < q) continue; 8155 ftotpoints[q * 2] = fpoints[p]; 8156 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8157 ++q; 8158 } 8159 } 8160 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8161 } 8162 numFPoints = q; 8163 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8164 PetscInt fdof; 8165 8166 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8167 if (!dof) continue; 8168 for (f = 0; f < numFields; ++f) { 8169 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8170 foffsets[f + 1] += fdof; 8171 } 8172 numFIndices += dof; 8173 } 8174 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8175 8176 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8177 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8178 if (numFields) { 8179 const PetscInt **permsF[32] = {NULL}; 8180 const PetscInt **permsC[32] = {NULL}; 8181 8182 for (f = 0; f < numFields; f++) { 8183 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8184 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8185 } 8186 for (p = 0; p < numFPoints; p++) { 8187 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8188 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8189 } 8190 for (p = 0; p < numCPoints; p++) { 8191 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8192 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8193 } 8194 for (f = 0; f < numFields; f++) { 8195 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8196 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8197 } 8198 } else { 8199 const PetscInt **permsF = NULL; 8200 const PetscInt **permsC = NULL; 8201 8202 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8203 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8204 for (p = 0, off = 0; p < numFPoints; p++) { 8205 const PetscInt *perm = permsF ? permsF[p] : NULL; 8206 8207 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8208 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8209 } 8210 for (p = 0, off = 0; p < numCPoints; p++) { 8211 const PetscInt *perm = permsC ? permsC[p] : NULL; 8212 8213 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8214 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8215 } 8216 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8217 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8218 } 8219 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8220 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8221 PetscFunctionReturn(0); 8222 } 8223 8224 /*@C 8225 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8226 8227 Input Parameter: 8228 . dm - The `DMPLEX` object 8229 8230 Output Parameter: 8231 . cellHeight - The height of a cell 8232 8233 Level: developer 8234 8235 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetVTKCellHeight()` 8236 @*/ 8237 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8238 { 8239 DM_Plex *mesh = (DM_Plex *)dm->data; 8240 8241 PetscFunctionBegin; 8242 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8243 PetscValidIntPointer(cellHeight, 2); 8244 *cellHeight = mesh->vtkCellHeight; 8245 PetscFunctionReturn(0); 8246 } 8247 8248 /*@C 8249 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8250 8251 Input Parameters: 8252 + dm - The `DMPLEX` object 8253 - cellHeight - The height of a cell 8254 8255 Level: developer 8256 8257 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVTKCellHeight()` 8258 @*/ 8259 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8260 { 8261 DM_Plex *mesh = (DM_Plex *)dm->data; 8262 8263 PetscFunctionBegin; 8264 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8265 mesh->vtkCellHeight = cellHeight; 8266 PetscFunctionReturn(0); 8267 } 8268 8269 /*@ 8270 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8271 8272 Input Parameter: 8273 . dm - The `DMPLEX` object 8274 8275 Output Parameters: 8276 + gcStart - The first ghost cell, or NULL 8277 - gcEnd - The upper bound on ghost cells, or NULL 8278 8279 Level: advanced 8280 8281 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8282 @*/ 8283 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8284 { 8285 DMLabel ctLabel; 8286 8287 PetscFunctionBegin; 8288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8289 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8290 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8291 // Reset label for fast lookup 8292 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8293 PetscFunctionReturn(0); 8294 } 8295 8296 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8297 { 8298 PetscSection section, globalSection; 8299 PetscInt *numbers, p; 8300 8301 PetscFunctionBegin; 8302 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8303 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8304 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8305 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8306 PetscCall(PetscSectionSetUp(section)); 8307 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8308 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8309 for (p = pStart; p < pEnd; ++p) { 8310 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8311 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8312 else numbers[p - pStart] += shift; 8313 } 8314 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8315 if (globalSize) { 8316 PetscLayout layout; 8317 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8318 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8319 PetscCall(PetscLayoutDestroy(&layout)); 8320 } 8321 PetscCall(PetscSectionDestroy(§ion)); 8322 PetscCall(PetscSectionDestroy(&globalSection)); 8323 PetscFunctionReturn(0); 8324 } 8325 8326 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8327 { 8328 PetscInt cellHeight, cStart, cEnd; 8329 8330 PetscFunctionBegin; 8331 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8332 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8333 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8334 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8335 PetscFunctionReturn(0); 8336 } 8337 8338 /*@ 8339 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8340 8341 Input Parameter: 8342 . dm - The `DMPLEX` object 8343 8344 Output Parameter: 8345 . globalCellNumbers - Global cell numbers for all cells on this process 8346 8347 Level: developer 8348 8349 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetVertexNumbering()` 8350 @*/ 8351 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8352 { 8353 DM_Plex *mesh = (DM_Plex *)dm->data; 8354 8355 PetscFunctionBegin; 8356 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8357 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8358 *globalCellNumbers = mesh->globalCellNumbers; 8359 PetscFunctionReturn(0); 8360 } 8361 8362 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8363 { 8364 PetscInt vStart, vEnd; 8365 8366 PetscFunctionBegin; 8367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8368 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8369 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8370 PetscFunctionReturn(0); 8371 } 8372 8373 /*@ 8374 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8375 8376 Input Parameter: 8377 . dm - The `DMPLEX` object 8378 8379 Output Parameter: 8380 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8381 8382 Level: developer 8383 8384 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8385 @*/ 8386 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8387 { 8388 DM_Plex *mesh = (DM_Plex *)dm->data; 8389 8390 PetscFunctionBegin; 8391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8392 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8393 *globalVertexNumbers = mesh->globalVertexNumbers; 8394 PetscFunctionReturn(0); 8395 } 8396 8397 /*@ 8398 DMPlexCreatePointNumbering - Create a global numbering for all points. 8399 8400 Collective on dm 8401 8402 Input Parameter: 8403 . dm - The `DMPLEX` object 8404 8405 Output Parameter: 8406 . globalPointNumbers - Global numbers for all points on this process 8407 8408 Level: developer 8409 8410 Notes: 8411 The point numbering `IS` is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8412 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8413 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8414 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8415 8416 The partitioned mesh is 8417 ``` 8418 (2)--0--(3)--1--(4) (1)--0--(2) 8419 ``` 8420 and its global numbering is 8421 ``` 8422 (3)--0--(4)--1--(5)--2--(6) 8423 ``` 8424 Then the global numbering is provided as 8425 ``` 8426 [0] Number of indices in set 5 8427 [0] 0 0 8428 [0] 1 1 8429 [0] 2 3 8430 [0] 3 4 8431 [0] 4 -6 8432 [1] Number of indices in set 3 8433 [1] 0 2 8434 [1] 1 5 8435 [1] 2 6 8436 ``` 8437 8438 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellNumbering()` 8439 @*/ 8440 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8441 { 8442 IS nums[4]; 8443 PetscInt depths[4], gdepths[4], starts[4]; 8444 PetscInt depth, d, shift = 0; 8445 PetscBool empty = PETSC_FALSE; 8446 8447 PetscFunctionBegin; 8448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8449 PetscCall(DMPlexGetDepth(dm, &depth)); 8450 // For unstratified meshes use dim instead of depth 8451 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8452 // If any stratum is empty, we must mark all empty 8453 for (d = 0; d <= depth; ++d) { 8454 PetscInt end; 8455 8456 depths[d] = depth - d; 8457 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8458 if (!(starts[d] - end)) empty = PETSC_TRUE; 8459 } 8460 if (empty) 8461 for (d = 0; d <= depth; ++d) { 8462 depths[d] = -1; 8463 starts[d] = -1; 8464 } 8465 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8466 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8467 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]); 8468 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8469 for (d = 0; d <= depth; ++d) { 8470 PetscInt pStart, pEnd, gsize; 8471 8472 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8473 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8474 shift += gsize; 8475 } 8476 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8477 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8478 PetscFunctionReturn(0); 8479 } 8480 8481 /*@ 8482 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8483 8484 Input Parameter: 8485 . dm - The `DMPLEX` object 8486 8487 Output Parameter: 8488 . ranks - The rank field 8489 8490 Options Database Key: 8491 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8492 8493 Level: intermediate 8494 8495 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8496 @*/ 8497 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8498 { 8499 DM rdm; 8500 PetscFE fe; 8501 PetscScalar *r; 8502 PetscMPIInt rank; 8503 DMPolytopeType ct; 8504 PetscInt dim, cStart, cEnd, c; 8505 PetscBool simplex; 8506 8507 PetscFunctionBeginUser; 8508 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8509 PetscValidPointer(ranks, 2); 8510 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8511 PetscCall(DMClone(dm, &rdm)); 8512 PetscCall(DMGetDimension(rdm, &dim)); 8513 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8514 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8515 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8516 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8517 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8518 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8519 PetscCall(PetscFEDestroy(&fe)); 8520 PetscCall(DMCreateDS(rdm)); 8521 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8522 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8523 PetscCall(VecGetArray(*ranks, &r)); 8524 for (c = cStart; c < cEnd; ++c) { 8525 PetscScalar *lr; 8526 8527 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8528 if (lr) *lr = rank; 8529 } 8530 PetscCall(VecRestoreArray(*ranks, &r)); 8531 PetscCall(DMDestroy(&rdm)); 8532 PetscFunctionReturn(0); 8533 } 8534 8535 /*@ 8536 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8537 8538 Input Parameters: 8539 + dm - The DMPlex 8540 - label - The DMLabel 8541 8542 Output Parameter: 8543 . val - The label value field 8544 8545 Options Database Keys: 8546 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8547 8548 Level: intermediate 8549 8550 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMView()` 8551 @*/ 8552 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8553 { 8554 DM rdm; 8555 PetscFE fe; 8556 PetscScalar *v; 8557 PetscInt dim, cStart, cEnd, c; 8558 8559 PetscFunctionBeginUser; 8560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8561 PetscValidPointer(label, 2); 8562 PetscValidPointer(val, 3); 8563 PetscCall(DMClone(dm, &rdm)); 8564 PetscCall(DMGetDimension(rdm, &dim)); 8565 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8566 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8567 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8568 PetscCall(PetscFEDestroy(&fe)); 8569 PetscCall(DMCreateDS(rdm)); 8570 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8571 PetscCall(DMCreateGlobalVector(rdm, val)); 8572 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8573 PetscCall(VecGetArray(*val, &v)); 8574 for (c = cStart; c < cEnd; ++c) { 8575 PetscScalar *lv; 8576 PetscInt cval; 8577 8578 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8579 PetscCall(DMLabelGetValue(label, c, &cval)); 8580 *lv = cval; 8581 } 8582 PetscCall(VecRestoreArray(*val, &v)); 8583 PetscCall(DMDestroy(&rdm)); 8584 PetscFunctionReturn(0); 8585 } 8586 8587 /*@ 8588 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8589 8590 Input Parameter: 8591 . dm - The `DMPLEX` object 8592 8593 Level: developer 8594 8595 Notes: 8596 This is a useful diagnostic when creating meshes programmatically. 8597 8598 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8599 8600 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8601 @*/ 8602 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8603 { 8604 PetscSection coneSection, supportSection; 8605 const PetscInt *cone, *support; 8606 PetscInt coneSize, c, supportSize, s; 8607 PetscInt pStart, pEnd, p, pp, csize, ssize; 8608 PetscBool storagecheck = PETSC_TRUE; 8609 8610 PetscFunctionBegin; 8611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8612 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8613 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8614 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8615 /* Check that point p is found in the support of its cone points, and vice versa */ 8616 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8617 for (p = pStart; p < pEnd; ++p) { 8618 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8619 PetscCall(DMPlexGetCone(dm, p, &cone)); 8620 for (c = 0; c < coneSize; ++c) { 8621 PetscBool dup = PETSC_FALSE; 8622 PetscInt d; 8623 for (d = c - 1; d >= 0; --d) { 8624 if (cone[c] == cone[d]) { 8625 dup = PETSC_TRUE; 8626 break; 8627 } 8628 } 8629 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8630 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8631 for (s = 0; s < supportSize; ++s) { 8632 if (support[s] == p) break; 8633 } 8634 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8635 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8636 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8637 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8638 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8639 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8640 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8641 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]); 8642 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8643 } 8644 } 8645 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8646 if (p != pp) { 8647 storagecheck = PETSC_FALSE; 8648 continue; 8649 } 8650 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8651 PetscCall(DMPlexGetSupport(dm, p, &support)); 8652 for (s = 0; s < supportSize; ++s) { 8653 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8654 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8655 for (c = 0; c < coneSize; ++c) { 8656 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8657 if (cone[c] != pp) { 8658 c = 0; 8659 break; 8660 } 8661 if (cone[c] == p) break; 8662 } 8663 if (c >= coneSize) { 8664 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8665 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8666 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8667 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8668 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8669 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8670 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8671 } 8672 } 8673 } 8674 if (storagecheck) { 8675 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8676 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8677 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8678 } 8679 PetscFunctionReturn(0); 8680 } 8681 8682 /* 8683 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. 8684 */ 8685 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8686 { 8687 DMPolytopeType cct; 8688 PetscInt ptpoints[4]; 8689 const PetscInt *cone, *ccone, *ptcone; 8690 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8691 8692 PetscFunctionBegin; 8693 *unsplit = 0; 8694 switch (ct) { 8695 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8696 ptpoints[npt++] = c; 8697 break; 8698 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8699 PetscCall(DMPlexGetCone(dm, c, &cone)); 8700 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8701 for (cp = 0; cp < coneSize; ++cp) { 8702 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8703 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8704 } 8705 break; 8706 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8707 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8708 PetscCall(DMPlexGetCone(dm, c, &cone)); 8709 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8710 for (cp = 0; cp < coneSize; ++cp) { 8711 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8712 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8713 for (ccp = 0; ccp < cconeSize; ++ccp) { 8714 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8715 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8716 PetscInt p; 8717 for (p = 0; p < npt; ++p) 8718 if (ptpoints[p] == ccone[ccp]) break; 8719 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8720 } 8721 } 8722 } 8723 break; 8724 default: 8725 break; 8726 } 8727 for (pt = 0; pt < npt; ++pt) { 8728 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8729 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8730 } 8731 PetscFunctionReturn(0); 8732 } 8733 8734 /*@ 8735 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8736 8737 Input Parameters: 8738 + dm - The `DMPLEX` object 8739 - cellHeight - Normally 0 8740 8741 Level: developer 8742 8743 Notes: 8744 This is a useful diagnostic when creating meshes programmatically. 8745 Currently applicable only to homogeneous simplex or tensor meshes. 8746 8747 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8748 8749 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8750 @*/ 8751 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8752 { 8753 DMPlexInterpolatedFlag interp; 8754 DMPolytopeType ct; 8755 PetscInt vStart, vEnd, cStart, cEnd, c; 8756 8757 PetscFunctionBegin; 8758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8759 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8760 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8761 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8762 for (c = cStart; c < cEnd; ++c) { 8763 PetscInt *closure = NULL; 8764 PetscInt coneSize, closureSize, cl, Nv = 0; 8765 8766 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8767 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8768 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8769 if (interp == DMPLEX_INTERPOLATED_FULL) { 8770 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8771 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)); 8772 } 8773 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8774 for (cl = 0; cl < closureSize * 2; cl += 2) { 8775 const PetscInt p = closure[cl]; 8776 if ((p >= vStart) && (p < vEnd)) ++Nv; 8777 } 8778 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8779 /* Special Case: Tensor faces with identified vertices */ 8780 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8781 PetscInt unsplit; 8782 8783 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8784 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8785 } 8786 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)); 8787 } 8788 PetscFunctionReturn(0); 8789 } 8790 8791 /*@ 8792 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8793 8794 Collective on dm 8795 8796 Input Parameters: 8797 + dm - The `DMPLEX` object 8798 - cellHeight - Normally 0 8799 8800 Level: developer 8801 8802 Notes: 8803 This is a useful diagnostic when creating meshes programmatically. 8804 This routine is only relevant for meshes that are fully interpolated across all ranks. 8805 It will error out if a partially interpolated mesh is given on some rank. 8806 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8807 8808 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8809 8810 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8811 @*/ 8812 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8813 { 8814 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8815 DMPlexInterpolatedFlag interpEnum; 8816 8817 PetscFunctionBegin; 8818 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8819 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8820 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8821 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8822 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8823 PetscFunctionReturn(0); 8824 } 8825 8826 PetscCall(DMGetDimension(dm, &dim)); 8827 PetscCall(DMPlexGetDepth(dm, &depth)); 8828 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8829 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8830 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8831 for (c = cStart; c < cEnd; ++c) { 8832 const PetscInt *cone, *ornt, *faceSizes, *faces; 8833 const DMPolytopeType *faceTypes; 8834 DMPolytopeType ct; 8835 PetscInt numFaces, coneSize, f; 8836 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8837 8838 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8839 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8840 if (unsplit) continue; 8841 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8842 PetscCall(DMPlexGetCone(dm, c, &cone)); 8843 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8844 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8845 for (cl = 0; cl < closureSize * 2; cl += 2) { 8846 const PetscInt p = closure[cl]; 8847 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8848 } 8849 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8850 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); 8851 for (f = 0; f < numFaces; ++f) { 8852 DMPolytopeType fct; 8853 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8854 8855 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8856 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8857 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8858 const PetscInt p = fclosure[cl]; 8859 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8860 } 8861 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]); 8862 for (v = 0; v < fnumCorners; ++v) { 8863 if (fclosure[v] != faces[fOff + v]) { 8864 PetscInt v1; 8865 8866 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8867 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8868 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8869 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8870 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8871 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]); 8872 } 8873 } 8874 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8875 fOff += faceSizes[f]; 8876 } 8877 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8878 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8879 } 8880 } 8881 PetscFunctionReturn(0); 8882 } 8883 8884 /*@ 8885 DMPlexCheckGeometry - Check the geometry of mesh cells 8886 8887 Input Parameter: 8888 . dm - The `DMPLEX` object 8889 8890 Level: developer 8891 8892 Notes: 8893 This is a useful diagnostic when creating meshes programmatically. 8894 8895 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8896 8897 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMSetFromOptions()` 8898 @*/ 8899 PetscErrorCode DMPlexCheckGeometry(DM dm) 8900 { 8901 Vec coordinates; 8902 PetscReal detJ, J[9], refVol = 1.0; 8903 PetscReal vol; 8904 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8905 8906 PetscFunctionBegin; 8907 PetscCall(DMGetDimension(dm, &dim)); 8908 PetscCall(DMGetCoordinateDim(dm, &dE)); 8909 if (dim != dE) PetscFunctionReturn(0); 8910 PetscCall(DMPlexGetDepth(dm, &depth)); 8911 for (d = 0; d < dim; ++d) refVol *= 2.0; 8912 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8913 /* Make sure local coordinates are created, because that step is collective */ 8914 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8915 if (!coordinates) PetscFunctionReturn(0); 8916 for (c = cStart; c < cEnd; ++c) { 8917 DMPolytopeType ct; 8918 PetscInt unsplit; 8919 PetscBool ignoreZeroVol = PETSC_FALSE; 8920 8921 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8922 switch (ct) { 8923 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8924 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8925 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8926 ignoreZeroVol = PETSC_TRUE; 8927 break; 8928 default: 8929 break; 8930 } 8931 switch (ct) { 8932 case DM_POLYTOPE_TRI_PRISM: 8933 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8934 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8935 case DM_POLYTOPE_PYRAMID: 8936 continue; 8937 default: 8938 break; 8939 } 8940 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8941 if (unsplit) continue; 8942 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8943 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); 8944 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8945 /* This should work with periodicity since DG coordinates should be used */ 8946 if (depth > 1) { 8947 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8948 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); 8949 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8950 } 8951 } 8952 PetscFunctionReturn(0); 8953 } 8954 8955 /*@ 8956 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8957 8958 Collective on dm 8959 8960 Input Parameters: 8961 + dm - The `DMPLEX` object 8962 . pointSF - The `PetscSF`, or NULL for `PointSF` attached to `DM` 8963 - allowExtraRoots - Flag to allow extra points not present in the `DM` 8964 8965 Level: developer 8966 8967 Notes: 8968 This is mainly intended for debugging/testing purposes. 8969 8970 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 8971 8972 Extra roots can come from priodic cuts, where additional points appear on the boundary 8973 8974 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMGetPointSF()`, `DMSetFromOptions()` 8975 @*/ 8976 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 8977 { 8978 PetscInt l, nleaves, nroots, overlap; 8979 const PetscInt *locals; 8980 const PetscSFNode *remotes; 8981 PetscBool distributed; 8982 MPI_Comm comm; 8983 PetscMPIInt rank; 8984 8985 PetscFunctionBegin; 8986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8987 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8988 else pointSF = dm->sf; 8989 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8990 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8991 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8992 { 8993 PetscMPIInt mpiFlag; 8994 8995 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8996 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8997 } 8998 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8999 PetscCall(DMPlexIsDistributed(dm, &distributed)); 9000 if (!distributed) { 9001 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); 9002 PetscFunctionReturn(0); 9003 } 9004 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); 9005 PetscCall(DMPlexGetOverlap(dm, &overlap)); 9006 9007 /* Check SF graph is compatible with DMPlex chart */ 9008 { 9009 PetscInt pStart, pEnd, maxLeaf; 9010 9011 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 9012 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 9013 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 9014 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 9015 } 9016 9017 /* Check Point SF has no local points referenced */ 9018 for (l = 0; l < nleaves; l++) { 9019 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); 9020 } 9021 9022 /* Check there are no cells in interface */ 9023 if (!overlap) { 9024 PetscInt cellHeight, cStart, cEnd; 9025 9026 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9027 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9028 for (l = 0; l < nleaves; ++l) { 9029 const PetscInt point = locals ? locals[l] : l; 9030 9031 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 9032 } 9033 } 9034 9035 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 9036 { 9037 const PetscInt *rootdegree; 9038 9039 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9040 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9041 for (l = 0; l < nleaves; ++l) { 9042 const PetscInt point = locals ? locals[l] : l; 9043 const PetscInt *cone; 9044 PetscInt coneSize, c, idx; 9045 9046 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 9047 PetscCall(DMPlexGetCone(dm, point, &cone)); 9048 for (c = 0; c < coneSize; ++c) { 9049 if (!rootdegree[cone[c]]) { 9050 if (locals) { 9051 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 9052 } else { 9053 idx = (cone[c] < nleaves) ? cone[c] : -1; 9054 } 9055 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 9056 } 9057 } 9058 } 9059 } 9060 PetscFunctionReturn(0); 9061 } 9062 9063 /*@ 9064 DMPlexCheck - Perform various checks of Plex sanity 9065 9066 Input Parameter: 9067 . dm - The `DMPLEX` object 9068 9069 Level: developer 9070 9071 Notes: 9072 This is a useful diagnostic when creating meshes programmatically. 9073 9074 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 9075 9076 Currently does not include DMPlexCheckCellShape(). 9077 9078 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, DMCreate(), DMSetFromOptions() 9079 @*/ 9080 PetscErrorCode DMPlexCheck(DM dm) 9081 { 9082 PetscInt cellHeight; 9083 9084 PetscFunctionBegin; 9085 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9086 PetscCall(DMPlexCheckSymmetry(dm)); 9087 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 9088 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 9089 PetscCall(DMPlexCheckGeometry(dm)); 9090 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 9091 PetscCall(DMPlexCheckInterfaceCones(dm)); 9092 PetscFunctionReturn(0); 9093 } 9094 9095 typedef struct cell_stats { 9096 PetscReal min, max, sum, squaresum; 9097 PetscInt count; 9098 } cell_stats_t; 9099 9100 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 9101 { 9102 PetscInt i, N = *len; 9103 9104 for (i = 0; i < N; i++) { 9105 cell_stats_t *A = (cell_stats_t *)a; 9106 cell_stats_t *B = (cell_stats_t *)b; 9107 9108 B->min = PetscMin(A->min, B->min); 9109 B->max = PetscMax(A->max, B->max); 9110 B->sum += A->sum; 9111 B->squaresum += A->squaresum; 9112 B->count += A->count; 9113 } 9114 } 9115 9116 /*@ 9117 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 9118 9119 Collective on dm 9120 9121 Input Parameters: 9122 + dm - The `DMPLEX` object 9123 . output - If true, statistics will be displayed on stdout 9124 - condLimit - Display all cells above this condition number, or `PETSC_DETERMINE` for no cell output 9125 9126 Level: developer 9127 9128 Notes: 9129 This is mainly intended for debugging/testing purposes. 9130 9131 For the complete list of DMPlexCheck* functions, see `DMSetFromOptions()`. 9132 9133 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 9134 @*/ 9135 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 9136 { 9137 DM dmCoarse; 9138 cell_stats_t stats, globalStats; 9139 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9140 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9141 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9142 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9143 PetscMPIInt rank, size; 9144 9145 PetscFunctionBegin; 9146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9147 stats.min = PETSC_MAX_REAL; 9148 stats.max = PETSC_MIN_REAL; 9149 stats.sum = stats.squaresum = 0.; 9150 stats.count = 0; 9151 9152 PetscCallMPI(MPI_Comm_size(comm, &size)); 9153 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9154 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9155 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9156 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9157 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9158 for (c = cStart; c < cEnd; c++) { 9159 PetscInt i; 9160 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9161 9162 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9163 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9164 for (i = 0; i < PetscSqr(cdim); ++i) { 9165 frobJ += J[i] * J[i]; 9166 frobInvJ += invJ[i] * invJ[i]; 9167 } 9168 cond2 = frobJ * frobInvJ; 9169 cond = PetscSqrtReal(cond2); 9170 9171 stats.min = PetscMin(stats.min, cond); 9172 stats.max = PetscMax(stats.max, cond); 9173 stats.sum += cond; 9174 stats.squaresum += cond2; 9175 stats.count++; 9176 if (output && cond > limit) { 9177 PetscSection coordSection; 9178 Vec coordsLocal; 9179 PetscScalar *coords = NULL; 9180 PetscInt Nv, d, clSize, cl, *closure = NULL; 9181 9182 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9183 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9184 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9185 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9186 for (i = 0; i < Nv / cdim; ++i) { 9187 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9188 for (d = 0; d < cdim; ++d) { 9189 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9190 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9191 } 9192 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9193 } 9194 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9195 for (cl = 0; cl < clSize * 2; cl += 2) { 9196 const PetscInt edge = closure[cl]; 9197 9198 if ((edge >= eStart) && (edge < eEnd)) { 9199 PetscReal len; 9200 9201 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9202 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9203 } 9204 } 9205 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9206 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9207 } 9208 } 9209 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9210 9211 if (size > 1) { 9212 PetscMPIInt blockLengths[2] = {4, 1}; 9213 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9214 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9215 MPI_Op statReduce; 9216 9217 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9218 PetscCallMPI(MPI_Type_commit(&statType)); 9219 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9220 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9221 PetscCallMPI(MPI_Op_free(&statReduce)); 9222 PetscCallMPI(MPI_Type_free(&statType)); 9223 } else { 9224 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9225 } 9226 if (rank == 0) { 9227 count = globalStats.count; 9228 min = globalStats.min; 9229 max = globalStats.max; 9230 mean = globalStats.sum / globalStats.count; 9231 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9232 } 9233 9234 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)); 9235 PetscCall(PetscFree2(J, invJ)); 9236 9237 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9238 if (dmCoarse) { 9239 PetscBool isplex; 9240 9241 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9242 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9243 } 9244 PetscFunctionReturn(0); 9245 } 9246 9247 /*@ 9248 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9249 orthogonal quality below given tolerance. 9250 9251 Collective on dm 9252 9253 Input Parameters: 9254 + dm - The `DMPLEX` object 9255 . fv - Optional `PetscFV` object for pre-computed cell/face centroid information 9256 - atol - [0, 1] Absolute tolerance for tagging cells. 9257 9258 Output Parameters: 9259 + OrthQual - Vec containing orthogonal quality per cell 9260 - OrthQualLabel - `DMLabel` tagging cells below atol with `DM_ADAPT_REFINE` 9261 9262 Options Database Keys: 9263 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only `PETSCVIEWERASCII` is supported. 9264 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9265 9266 Level: intermediate 9267 9268 Notes: 9269 Orthogonal quality is given by the following formula: 9270 9271 $ \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]$ 9272 9273 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 9274 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9275 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9276 calculating the cosine of the angle between these vectors. 9277 9278 Orthogonal quality ranges from 1 (best) to 0 (worst). 9279 9280 This routine is mainly useful for FVM, however is not restricted to only FVM. The `PetscFV` object is optionally used to check for 9281 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9282 9283 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9284 9285 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexCheckCellShape()`, `DMCreateLabel()`, `PetscFV`, `DMLabel`, `Vec` 9286 @*/ 9287 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9288 { 9289 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9290 PetscInt *idx; 9291 PetscScalar *oqVals; 9292 const PetscScalar *cellGeomArr, *faceGeomArr; 9293 PetscReal *ci, *fi, *Ai; 9294 MPI_Comm comm; 9295 Vec cellgeom, facegeom; 9296 DM dmFace, dmCell; 9297 IS glob; 9298 ISLocalToGlobalMapping ltog; 9299 PetscViewer vwr; 9300 9301 PetscFunctionBegin; 9302 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9303 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9304 PetscValidPointer(OrthQual, 4); 9305 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9306 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9307 PetscCall(DMGetDimension(dm, &nc)); 9308 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9309 { 9310 DMPlexInterpolatedFlag interpFlag; 9311 9312 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9313 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9314 PetscMPIInt rank; 9315 9316 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9317 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9318 } 9319 } 9320 if (OrthQualLabel) { 9321 PetscValidPointer(OrthQualLabel, 5); 9322 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9323 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9324 } else { 9325 *OrthQualLabel = NULL; 9326 } 9327 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9328 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9329 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9330 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9331 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9332 PetscCall(VecCreate(comm, OrthQual)); 9333 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9334 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9335 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9336 PetscCall(VecSetUp(*OrthQual)); 9337 PetscCall(ISDestroy(&glob)); 9338 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9339 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9340 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9341 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9342 PetscCall(VecGetDM(cellgeom, &dmCell)); 9343 PetscCall(VecGetDM(facegeom, &dmFace)); 9344 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9345 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9346 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9347 PetscInt cellarr[2], *adj = NULL; 9348 PetscScalar *cArr, *fArr; 9349 PetscReal minvalc = 1.0, minvalf = 1.0; 9350 PetscFVCellGeom *cg; 9351 9352 idx[cellIter] = cell - cStart; 9353 cellarr[0] = cell; 9354 /* Make indexing into cellGeom easier */ 9355 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9356 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9357 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9358 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9359 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9360 PetscInt i; 9361 const PetscInt neigh = adj[cellneigh]; 9362 PetscReal normci = 0, normfi = 0, normai = 0; 9363 PetscFVCellGeom *cgneigh; 9364 PetscFVFaceGeom *fg; 9365 9366 /* Don't count ourselves in the neighbor list */ 9367 if (neigh == cell) continue; 9368 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9369 cellarr[1] = neigh; 9370 { 9371 PetscInt numcovpts; 9372 const PetscInt *covpts; 9373 9374 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9375 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9376 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9377 } 9378 9379 /* Compute c_i, f_i and their norms */ 9380 for (i = 0; i < nc; i++) { 9381 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9382 fi[i] = fg->centroid[i] - cg->centroid[i]; 9383 Ai[i] = fg->normal[i]; 9384 normci += PetscPowReal(ci[i], 2); 9385 normfi += PetscPowReal(fi[i], 2); 9386 normai += PetscPowReal(Ai[i], 2); 9387 } 9388 normci = PetscSqrtReal(normci); 9389 normfi = PetscSqrtReal(normfi); 9390 normai = PetscSqrtReal(normai); 9391 9392 /* Normalize and compute for each face-cell-normal pair */ 9393 for (i = 0; i < nc; i++) { 9394 ci[i] = ci[i] / normci; 9395 fi[i] = fi[i] / normfi; 9396 Ai[i] = Ai[i] / normai; 9397 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9398 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9399 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9400 } 9401 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9402 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9403 } 9404 PetscCall(PetscFree(adj)); 9405 PetscCall(PetscFree2(cArr, fArr)); 9406 /* Defer to cell if they're equal */ 9407 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9408 if (OrthQualLabel) { 9409 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9410 } 9411 } 9412 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9413 PetscCall(VecAssemblyBegin(*OrthQual)); 9414 PetscCall(VecAssemblyEnd(*OrthQual)); 9415 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9416 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9417 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9418 if (OrthQualLabel) { 9419 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9420 } 9421 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9422 PetscCall(PetscViewerDestroy(&vwr)); 9423 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9424 PetscFunctionReturn(0); 9425 } 9426 9427 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9428 * interpolator construction */ 9429 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9430 { 9431 PetscSection section, newSection, gsection; 9432 PetscSF sf; 9433 PetscBool hasConstraints, ghasConstraints; 9434 9435 PetscFunctionBegin; 9436 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9437 PetscValidPointer(odm, 2); 9438 PetscCall(DMGetLocalSection(dm, §ion)); 9439 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9440 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9441 if (!ghasConstraints) { 9442 PetscCall(PetscObjectReference((PetscObject)dm)); 9443 *odm = dm; 9444 PetscFunctionReturn(0); 9445 } 9446 PetscCall(DMClone(dm, odm)); 9447 PetscCall(DMCopyFields(dm, *odm)); 9448 PetscCall(DMGetLocalSection(*odm, &newSection)); 9449 PetscCall(DMGetPointSF(*odm, &sf)); 9450 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9451 PetscCall(DMSetGlobalSection(*odm, gsection)); 9452 PetscCall(PetscSectionDestroy(&gsection)); 9453 PetscFunctionReturn(0); 9454 } 9455 9456 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9457 { 9458 DM dmco, dmfo; 9459 Mat interpo; 9460 Vec rscale; 9461 Vec cglobalo, clocal; 9462 Vec fglobal, fglobalo, flocal; 9463 PetscBool regular; 9464 9465 PetscFunctionBegin; 9466 PetscCall(DMGetFullDM(dmc, &dmco)); 9467 PetscCall(DMGetFullDM(dmf, &dmfo)); 9468 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9469 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9470 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9471 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9472 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9473 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9474 PetscCall(VecSet(cglobalo, 0.)); 9475 PetscCall(VecSet(clocal, 0.)); 9476 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9477 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9478 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9479 PetscCall(VecSet(fglobal, 0.)); 9480 PetscCall(VecSet(fglobalo, 0.)); 9481 PetscCall(VecSet(flocal, 0.)); 9482 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9483 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9484 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9485 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9486 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9487 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9488 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9489 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9490 *shift = fglobal; 9491 PetscCall(VecDestroy(&flocal)); 9492 PetscCall(VecDestroy(&fglobalo)); 9493 PetscCall(VecDestroy(&clocal)); 9494 PetscCall(VecDestroy(&cglobalo)); 9495 PetscCall(VecDestroy(&rscale)); 9496 PetscCall(MatDestroy(&interpo)); 9497 PetscCall(DMDestroy(&dmfo)); 9498 PetscCall(DMDestroy(&dmco)); 9499 PetscFunctionReturn(0); 9500 } 9501 9502 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9503 { 9504 PetscObject shifto; 9505 Vec shift; 9506 9507 PetscFunctionBegin; 9508 if (!interp) { 9509 Vec rscale; 9510 9511 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9512 PetscCall(VecDestroy(&rscale)); 9513 } else { 9514 PetscCall(PetscObjectReference((PetscObject)interp)); 9515 } 9516 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9517 if (!shifto) { 9518 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9519 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9520 shifto = (PetscObject)shift; 9521 PetscCall(VecDestroy(&shift)); 9522 } 9523 shift = (Vec)shifto; 9524 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9525 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9526 PetscCall(MatDestroy(&interp)); 9527 PetscFunctionReturn(0); 9528 } 9529 9530 /* Pointwise interpolation 9531 Just code FEM for now 9532 u^f = I u^c 9533 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9534 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9535 I_{ij} = psi^f_i phi^c_j 9536 */ 9537 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9538 { 9539 PetscSection gsc, gsf; 9540 PetscInt m, n; 9541 void *ctx; 9542 DM cdm; 9543 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9544 9545 PetscFunctionBegin; 9546 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9547 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9548 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9549 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9550 9551 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9552 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9553 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9554 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9555 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9556 9557 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9558 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9559 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9560 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9561 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9562 if (scaling) { 9563 /* Use naive scaling */ 9564 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9565 } 9566 PetscFunctionReturn(0); 9567 } 9568 9569 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9570 { 9571 VecScatter ctx; 9572 9573 PetscFunctionBegin; 9574 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9575 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9576 PetscCall(VecScatterDestroy(&ctx)); 9577 PetscFunctionReturn(0); 9578 } 9579 9580 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[]) 9581 { 9582 const PetscInt Nc = uOff[1] - uOff[0]; 9583 PetscInt c; 9584 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9585 } 9586 9587 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9588 { 9589 DM dmc; 9590 PetscDS ds; 9591 Vec ones, locmass; 9592 IS cellIS; 9593 PetscFormKey key; 9594 PetscInt depth; 9595 9596 PetscFunctionBegin; 9597 PetscCall(DMClone(dm, &dmc)); 9598 PetscCall(DMCopyDisc(dm, dmc)); 9599 PetscCall(DMGetDS(dmc, &ds)); 9600 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9601 PetscCall(DMCreateGlobalVector(dmc, mass)); 9602 PetscCall(DMGetLocalVector(dmc, &ones)); 9603 PetscCall(DMGetLocalVector(dmc, &locmass)); 9604 PetscCall(DMPlexGetDepth(dmc, &depth)); 9605 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9606 PetscCall(VecSet(locmass, 0.0)); 9607 PetscCall(VecSet(ones, 1.0)); 9608 key.label = NULL; 9609 key.value = 0; 9610 key.field = 0; 9611 key.part = 0; 9612 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9613 PetscCall(ISDestroy(&cellIS)); 9614 PetscCall(VecSet(*mass, 0.0)); 9615 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9616 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9617 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9618 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9619 PetscCall(DMDestroy(&dmc)); 9620 PetscFunctionReturn(0); 9621 } 9622 9623 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9624 { 9625 PetscSection gsc, gsf; 9626 PetscInt m, n; 9627 void *ctx; 9628 DM cdm; 9629 PetscBool regular; 9630 9631 PetscFunctionBegin; 9632 if (dmFine == dmCoarse) { 9633 DM dmc; 9634 PetscDS ds; 9635 PetscWeakForm wf; 9636 Vec u; 9637 IS cellIS; 9638 PetscFormKey key; 9639 PetscInt depth; 9640 9641 PetscCall(DMClone(dmFine, &dmc)); 9642 PetscCall(DMCopyDisc(dmFine, dmc)); 9643 PetscCall(DMGetDS(dmc, &ds)); 9644 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9645 PetscCall(PetscWeakFormClear(wf)); 9646 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9647 PetscCall(DMCreateMatrix(dmc, mass)); 9648 PetscCall(DMGetLocalVector(dmc, &u)); 9649 PetscCall(DMPlexGetDepth(dmc, &depth)); 9650 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9651 PetscCall(MatZeroEntries(*mass)); 9652 key.label = NULL; 9653 key.value = 0; 9654 key.field = 0; 9655 key.part = 0; 9656 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9657 PetscCall(ISDestroy(&cellIS)); 9658 PetscCall(DMRestoreLocalVector(dmc, &u)); 9659 PetscCall(DMDestroy(&dmc)); 9660 } else { 9661 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9662 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9663 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9664 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9665 9666 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9667 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9668 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9669 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9670 9671 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9672 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9673 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9674 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9675 } 9676 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9677 PetscFunctionReturn(0); 9678 } 9679 9680 /*@ 9681 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9682 9683 Input Parameter: 9684 . dm - The `DMPLEX` object 9685 9686 Output Parameter: 9687 . regular - The flag 9688 9689 Level: intermediate 9690 9691 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetRegularRefinement()` 9692 @*/ 9693 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9694 { 9695 PetscFunctionBegin; 9696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9697 PetscValidBoolPointer(regular, 2); 9698 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9699 PetscFunctionReturn(0); 9700 } 9701 9702 /*@ 9703 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9704 9705 Input Parameters: 9706 + dm - The `DMPLEX` object 9707 - regular - The flag 9708 9709 Level: intermediate 9710 9711 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetRegularRefinement()` 9712 @*/ 9713 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9714 { 9715 PetscFunctionBegin; 9716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9717 ((DM_Plex *)dm->data)->regularRefinement = regular; 9718 PetscFunctionReturn(0); 9719 } 9720 9721 /*@ 9722 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9723 call DMPlexGetAnchors() directly: if there are anchors, then `DMPlexGetAnchors()` is called during `DMGetDefaultConstraints()`. 9724 9725 Not Collective 9726 9727 Input Parameter: 9728 . dm - The `DMPLEX` object 9729 9730 Output Parameters: 9731 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9732 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9733 9734 Level: intermediate 9735 9736 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()`, `IS`, `PetscSection` 9737 @*/ 9738 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9739 { 9740 DM_Plex *plex = (DM_Plex *)dm->data; 9741 9742 PetscFunctionBegin; 9743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9744 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9745 if (anchorSection) *anchorSection = plex->anchorSection; 9746 if (anchorIS) *anchorIS = plex->anchorIS; 9747 PetscFunctionReturn(0); 9748 } 9749 9750 /*@ 9751 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9752 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9753 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9754 9755 Collective on dm 9756 9757 Input Parameters: 9758 + dm - The `DMPLEX` object 9759 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. 9760 Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9761 - anchorIS - The list of all anchor points. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 9762 9763 Level: intermediate 9764 9765 Notes: 9766 After specifying the layout of constraints with `DMPlexSetAnchors()`, one specifies the constraints by calling 9767 `DMGetDefaultConstraints()` and filling in the entries in the constraint matrix. 9768 9769 The reference counts of anchorSection and anchorIS are incremented. 9770 9771 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9772 @*/ 9773 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9774 { 9775 DM_Plex *plex = (DM_Plex *)dm->data; 9776 PetscMPIInt result; 9777 9778 PetscFunctionBegin; 9779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9780 if (anchorSection) { 9781 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9782 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9783 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9784 } 9785 if (anchorIS) { 9786 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9787 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9788 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9789 } 9790 9791 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9792 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9793 plex->anchorSection = anchorSection; 9794 9795 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9796 PetscCall(ISDestroy(&plex->anchorIS)); 9797 plex->anchorIS = anchorIS; 9798 9799 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9800 PetscInt size, a, pStart, pEnd; 9801 const PetscInt *anchors; 9802 9803 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9804 PetscCall(ISGetLocalSize(anchorIS, &size)); 9805 PetscCall(ISGetIndices(anchorIS, &anchors)); 9806 for (a = 0; a < size; a++) { 9807 PetscInt p; 9808 9809 p = anchors[a]; 9810 if (p >= pStart && p < pEnd) { 9811 PetscInt dof; 9812 9813 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9814 if (dof) { 9815 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9816 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9817 } 9818 } 9819 } 9820 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9821 } 9822 /* reset the generic constraints */ 9823 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9824 PetscFunctionReturn(0); 9825 } 9826 9827 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9828 { 9829 PetscSection anchorSection; 9830 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9831 9832 PetscFunctionBegin; 9833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9834 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9835 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9836 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9837 if (numFields) { 9838 PetscInt f; 9839 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9840 9841 for (f = 0; f < numFields; f++) { 9842 PetscInt numComp; 9843 9844 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9845 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9846 } 9847 } 9848 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9849 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9850 pStart = PetscMax(pStart, sStart); 9851 pEnd = PetscMin(pEnd, sEnd); 9852 pEnd = PetscMax(pStart, pEnd); 9853 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9854 for (p = pStart; p < pEnd; p++) { 9855 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9856 if (dof) { 9857 PetscCall(PetscSectionGetDof(section, p, &dof)); 9858 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9859 for (f = 0; f < numFields; f++) { 9860 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9861 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9862 } 9863 } 9864 } 9865 PetscCall(PetscSectionSetUp(*cSec)); 9866 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9867 PetscFunctionReturn(0); 9868 } 9869 9870 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9871 { 9872 PetscSection aSec; 9873 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9874 const PetscInt *anchors; 9875 PetscInt numFields, f; 9876 IS aIS; 9877 MatType mtype; 9878 PetscBool iscuda, iskokkos; 9879 9880 PetscFunctionBegin; 9881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9882 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9883 PetscCall(PetscSectionGetStorageSize(section, &n)); 9884 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9885 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9886 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9887 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9888 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9889 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9890 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9891 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9892 else mtype = MATSEQAIJ; 9893 PetscCall(MatSetType(*cMat, mtype)); 9894 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9895 PetscCall(ISGetIndices(aIS, &anchors)); 9896 /* cSec will be a subset of aSec and section */ 9897 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9898 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9899 PetscCall(PetscMalloc1(m + 1, &i)); 9900 i[0] = 0; 9901 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9902 for (p = pStart; p < pEnd; p++) { 9903 PetscInt rDof, rOff, r; 9904 9905 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9906 if (!rDof) continue; 9907 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9908 if (numFields) { 9909 for (f = 0; f < numFields; f++) { 9910 annz = 0; 9911 for (r = 0; r < rDof; r++) { 9912 a = anchors[rOff + r]; 9913 if (a < sStart || a >= sEnd) continue; 9914 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9915 annz += aDof; 9916 } 9917 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9918 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9919 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9920 } 9921 } else { 9922 annz = 0; 9923 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9924 for (q = 0; q < dof; q++) { 9925 a = anchors[rOff + q]; 9926 if (a < sStart || a >= sEnd) continue; 9927 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9928 annz += aDof; 9929 } 9930 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9931 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9932 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9933 } 9934 } 9935 nnz = i[m]; 9936 PetscCall(PetscMalloc1(nnz, &j)); 9937 offset = 0; 9938 for (p = pStart; p < pEnd; p++) { 9939 if (numFields) { 9940 for (f = 0; f < numFields; f++) { 9941 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9942 for (q = 0; q < dof; q++) { 9943 PetscInt rDof, rOff, r; 9944 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9945 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9946 for (r = 0; r < rDof; r++) { 9947 PetscInt s; 9948 9949 a = anchors[rOff + r]; 9950 if (a < sStart || a >= sEnd) continue; 9951 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9952 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9953 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9954 } 9955 } 9956 } 9957 } else { 9958 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9959 for (q = 0; q < dof; q++) { 9960 PetscInt rDof, rOff, r; 9961 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9962 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9963 for (r = 0; r < rDof; r++) { 9964 PetscInt s; 9965 9966 a = anchors[rOff + r]; 9967 if (a < sStart || a >= sEnd) continue; 9968 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9969 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9970 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9971 } 9972 } 9973 } 9974 } 9975 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9976 PetscCall(PetscFree(i)); 9977 PetscCall(PetscFree(j)); 9978 PetscCall(ISRestoreIndices(aIS, &anchors)); 9979 PetscFunctionReturn(0); 9980 } 9981 9982 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9983 { 9984 DM_Plex *plex = (DM_Plex *)dm->data; 9985 PetscSection anchorSection, section, cSec; 9986 Mat cMat; 9987 9988 PetscFunctionBegin; 9989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9990 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9991 if (anchorSection) { 9992 PetscInt Nf; 9993 9994 PetscCall(DMGetLocalSection(dm, §ion)); 9995 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9996 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9997 PetscCall(DMGetNumFields(dm, &Nf)); 9998 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9999 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 10000 PetscCall(PetscSectionDestroy(&cSec)); 10001 PetscCall(MatDestroy(&cMat)); 10002 } 10003 PetscFunctionReturn(0); 10004 } 10005 10006 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 10007 { 10008 IS subis; 10009 PetscSection section, subsection; 10010 10011 PetscFunctionBegin; 10012 PetscCall(DMGetLocalSection(dm, §ion)); 10013 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 10014 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 10015 /* Create subdomain */ 10016 PetscCall(DMPlexFilter(dm, label, value, subdm)); 10017 /* Create submodel */ 10018 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 10019 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 10020 PetscCall(DMSetLocalSection(*subdm, subsection)); 10021 PetscCall(PetscSectionDestroy(&subsection)); 10022 PetscCall(DMCopyDisc(dm, *subdm)); 10023 /* Create map from submodel to global model */ 10024 if (is) { 10025 PetscSection sectionGlobal, subsectionGlobal; 10026 IS spIS; 10027 const PetscInt *spmap; 10028 PetscInt *subIndices; 10029 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 10030 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 10031 10032 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 10033 PetscCall(ISGetIndices(spIS, &spmap)); 10034 PetscCall(PetscSectionGetNumFields(section, &Nf)); 10035 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 10036 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 10037 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 10038 for (p = pStart; p < pEnd; ++p) { 10039 PetscInt gdof, pSubSize = 0; 10040 10041 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 10042 if (gdof > 0) { 10043 for (f = 0; f < Nf; ++f) { 10044 PetscInt fdof, fcdof; 10045 10046 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 10047 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 10048 pSubSize += fdof - fcdof; 10049 } 10050 subSize += pSubSize; 10051 if (pSubSize) { 10052 if (bs < 0) { 10053 bs = pSubSize; 10054 } else if (bs != pSubSize) { 10055 /* Layout does not admit a pointwise block size */ 10056 bs = 1; 10057 } 10058 } 10059 } 10060 } 10061 /* Must have same blocksize on all procs (some might have no points) */ 10062 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 10063 bsLocal[1] = bs; 10064 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 10065 if (bsMinMax[0] != bsMinMax[1]) { 10066 bs = 1; 10067 } else { 10068 bs = bsMinMax[0]; 10069 } 10070 PetscCall(PetscMalloc1(subSize, &subIndices)); 10071 for (p = pStart; p < pEnd; ++p) { 10072 PetscInt gdof, goff; 10073 10074 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 10075 if (gdof > 0) { 10076 const PetscInt point = spmap[p]; 10077 10078 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 10079 for (f = 0; f < Nf; ++f) { 10080 PetscInt fdof, fcdof, fc, f2, poff = 0; 10081 10082 /* Can get rid of this loop by storing field information in the global section */ 10083 for (f2 = 0; f2 < f; ++f2) { 10084 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 10085 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 10086 poff += fdof - fcdof; 10087 } 10088 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 10089 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 10090 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 10091 } 10092 } 10093 } 10094 PetscCall(ISRestoreIndices(spIS, &spmap)); 10095 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 10096 if (bs > 1) { 10097 /* We need to check that the block size does not come from non-contiguous fields */ 10098 PetscInt i, j, set = 1; 10099 for (i = 0; i < subSize; i += bs) { 10100 for (j = 0; j < bs; ++j) { 10101 if (subIndices[i + j] != subIndices[i] + j) { 10102 set = 0; 10103 break; 10104 } 10105 } 10106 } 10107 if (set) PetscCall(ISSetBlockSize(*is, bs)); 10108 } 10109 /* Attach nullspace */ 10110 for (f = 0; f < Nf; ++f) { 10111 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 10112 if ((*subdm)->nullspaceConstructors[f]) break; 10113 } 10114 if (f < Nf) { 10115 MatNullSpace nullSpace; 10116 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 10117 10118 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 10119 PetscCall(MatNullSpaceDestroy(&nullSpace)); 10120 } 10121 } 10122 PetscFunctionReturn(0); 10123 } 10124 10125 /*@ 10126 DMPlexMonitorThroughput - Report the cell throughput of FE integration 10127 10128 Input Parameters: 10129 + dm - The `DM` 10130 - dummy - unused argument 10131 10132 Options Database Key: 10133 . -dm_plex_monitor_throughput - Activate the monitor 10134 10135 Level: developer 10136 10137 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMSetFromOptions()`, `DMPlexCreate()` 10138 @*/ 10139 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10140 { 10141 #if defined(PETSC_USE_LOG) 10142 PetscStageLog stageLog; 10143 PetscLogEvent event; 10144 PetscLogStage stage; 10145 PetscEventPerfInfo eventInfo; 10146 PetscReal cellRate, flopRate; 10147 PetscInt cStart, cEnd, Nf, N; 10148 const char *name; 10149 #endif 10150 10151 PetscFunctionBegin; 10152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10153 #if defined(PETSC_USE_LOG) 10154 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10155 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10156 PetscCall(DMGetNumFields(dm, &Nf)); 10157 PetscCall(PetscLogGetStageLog(&stageLog)); 10158 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10159 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10160 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10161 N = (cEnd - cStart) * Nf * eventInfo.count; 10162 flopRate = eventInfo.flops / eventInfo.time; 10163 cellRate = N / eventInfo.time; 10164 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))); 10165 #else 10166 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10167 #endif 10168 PetscFunctionReturn(0); 10169 } 10170