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