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