1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 35 { 36 DMPolytopeType ct; 37 PetscInt cStart, cEnd; 38 39 PetscFunctionBegin; 40 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 41 if (cEnd <= cStart) { 42 *simplex = PETSC_FALSE; 43 PetscFunctionReturn(0); 44 } 45 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 46 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 47 PetscFunctionReturn(0); 48 } 49 50 /*@ 51 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 52 53 Input Parameters: 54 + dm - The DMPlex object 55 - height - The cell height in the Plex, 0 is the default 56 57 Output Parameters: 58 + cStart - The first "normal" cell 59 - cEnd - The upper bound on "normal"" cells 60 61 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 62 63 Level: developer 64 65 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 66 @*/ 67 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 68 { 69 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 70 PetscInt cS, cE, c; 71 72 PetscFunctionBegin; 73 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 74 for (c = cS; c < cE; ++c) { 75 DMPolytopeType cct; 76 77 PetscCall(DMPlexGetCellType(dm, c, &cct)); 78 if ((PetscInt)cct < 0) break; 79 switch (cct) { 80 case DM_POLYTOPE_POINT: 81 case DM_POLYTOPE_SEGMENT: 82 case DM_POLYTOPE_TRIANGLE: 83 case DM_POLYTOPE_QUADRILATERAL: 84 case DM_POLYTOPE_TETRAHEDRON: 85 case DM_POLYTOPE_HEXAHEDRON: 86 ct = cct; 87 break; 88 default: 89 break; 90 } 91 if (ct != DM_POLYTOPE_UNKNOWN) break; 92 } 93 if (ct != DM_POLYTOPE_UNKNOWN) { 94 DMLabel ctLabel; 95 96 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 97 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 98 // Reset label for fast lookup 99 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 100 } 101 if (cStart) *cStart = cS; 102 if (cEnd) *cEnd = cE; 103 PetscFunctionReturn(0); 104 } 105 106 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 107 { 108 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 109 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 110 111 PetscFunctionBegin; 112 *ft = PETSC_VTK_INVALID; 113 PetscCall(DMGetCoordinateDim(dm, &cdim)); 114 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 115 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 116 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 117 if (field >= 0) { 118 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 119 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 120 } else { 121 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 122 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 123 } 124 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 125 if (globalvcdof[0]) { 126 *sStart = vStart; 127 *sEnd = vEnd; 128 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 129 else *ft = PETSC_VTK_POINT_FIELD; 130 } else if (globalvcdof[1]) { 131 *sStart = cStart; 132 *sEnd = cEnd; 133 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 134 else *ft = PETSC_VTK_CELL_FIELD; 135 } else { 136 if (field >= 0) { 137 const char *fieldname; 138 139 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 140 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 141 } else { 142 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 143 } 144 } 145 PetscFunctionReturn(0); 146 } 147 148 /*@ 149 DMPlexVecView1D - Plot many 1D solutions on the same line graph 150 151 Collective on dm 152 153 Input Parameters: 154 + dm - The DMPlex 155 . n - The number of vectors 156 . u - The array of local vectors 157 - viewer - The Draw viewer 158 159 Level: advanced 160 161 .seealso: `VecViewFromOptions()`, `VecView()` 162 @*/ 163 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 164 { 165 PetscDS ds; 166 PetscDraw draw = NULL; 167 PetscDrawLG lg; 168 Vec coordinates; 169 const PetscScalar *coords, **sol; 170 PetscReal *vals; 171 PetscInt *Nc; 172 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 173 char **names; 174 175 PetscFunctionBegin; 176 PetscCall(DMGetDS(dm, &ds)); 177 PetscCall(PetscDSGetNumFields(ds, &Nf)); 178 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 179 PetscCall(PetscDSGetComponents(ds, &Nc)); 180 181 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 182 if (!draw) PetscFunctionReturn(0); 183 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 184 185 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 186 for (i = 0, l = 0; i < n; ++i) { 187 const char *vname; 188 189 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 190 for (f = 0; f < Nf; ++f) { 191 PetscObject disc; 192 const char *fname; 193 char tmpname[PETSC_MAX_PATH_LEN]; 194 195 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 196 /* TODO Create names for components */ 197 for (c = 0; c < Nc[f]; ++c, ++l) { 198 PetscCall(PetscObjectGetName(disc, &fname)); 199 PetscCall(PetscStrcpy(tmpname, vname)); 200 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 201 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 202 PetscCall(PetscStrallocpy(tmpname, &names[l])); 203 } 204 } 205 } 206 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 207 /* Just add P_1 support for now */ 208 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 209 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 210 PetscCall(VecGetArrayRead(coordinates, &coords)); 211 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 212 for (v = vStart; v < vEnd; ++v) { 213 PetscScalar *x, *svals; 214 215 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 216 for (i = 0; i < n; ++i) { 217 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 218 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 219 } 220 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 221 } 222 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 223 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 224 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 225 PetscCall(PetscFree3(sol, names, vals)); 226 227 PetscCall(PetscDrawLGDraw(lg)); 228 PetscCall(PetscDrawLGDestroy(&lg)); 229 PetscFunctionReturn(0); 230 } 231 232 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 233 { 234 DM dm; 235 236 PetscFunctionBegin; 237 PetscCall(VecGetDM(u, &dm)); 238 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 239 PetscFunctionReturn(0); 240 } 241 242 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 243 { 244 DM dm; 245 PetscSection s; 246 PetscDraw draw, popup; 247 DM cdm; 248 PetscSection coordSection; 249 Vec coordinates; 250 const PetscScalar *coords, *array; 251 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 252 PetscReal vbound[2], time; 253 PetscBool flg; 254 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 255 const char *name; 256 char title[PETSC_MAX_PATH_LEN]; 257 258 PetscFunctionBegin; 259 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 260 PetscCall(VecGetDM(v, &dm)); 261 PetscCall(DMGetCoordinateDim(dm, &dim)); 262 PetscCall(DMGetLocalSection(dm, &s)); 263 PetscCall(PetscSectionGetNumFields(s, &Nf)); 264 PetscCall(DMGetCoarsenLevel(dm, &level)); 265 PetscCall(DMGetCoordinateDM(dm, &cdm)); 266 PetscCall(DMGetLocalSection(cdm, &coordSection)); 267 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 268 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 269 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 270 271 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 272 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 273 274 PetscCall(VecGetLocalSize(coordinates, &N)); 275 PetscCall(VecGetArrayRead(coordinates, &coords)); 276 for (c = 0; c < N; c += dim) { 277 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 278 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 279 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 280 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 281 } 282 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 283 PetscCall(PetscDrawClear(draw)); 284 285 /* Could implement something like DMDASelectFields() */ 286 for (f = 0; f < Nf; ++f) { 287 DM fdm = dm; 288 Vec fv = v; 289 IS fis; 290 char prefix[PETSC_MAX_PATH_LEN]; 291 const char *fname; 292 293 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 294 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 295 296 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 297 else prefix[0] = '\0'; 298 if (Nf > 1) { 299 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 300 PetscCall(VecGetSubVector(v, fis, &fv)); 301 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 302 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 303 } 304 for (comp = 0; comp < Nc; ++comp, ++w) { 305 PetscInt nmax = 2; 306 307 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 308 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 309 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 310 PetscCall(PetscDrawSetTitle(draw, title)); 311 312 /* TODO Get max and min only for this component */ 313 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 314 if (!flg) { 315 PetscCall(VecMin(fv, NULL, &vbound[0])); 316 PetscCall(VecMax(fv, NULL, &vbound[1])); 317 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 318 } 319 PetscCall(PetscDrawGetPopup(draw, &popup)); 320 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 321 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 322 323 PetscCall(VecGetArrayRead(fv, &array)); 324 for (c = cStart; c < cEnd; ++c) { 325 PetscScalar *coords = NULL, *a = NULL; 326 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 327 328 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 329 if (a) { 330 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 331 color[1] = color[2] = color[3] = color[0]; 332 } else { 333 PetscScalar *vals = NULL; 334 PetscInt numVals, va; 335 336 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 337 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 338 switch (numVals / Nc) { 339 case 3: /* P1 Triangle */ 340 case 4: /* P1 Quadrangle */ 341 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 342 break; 343 case 6: /* P2 Triangle */ 344 case 8: /* P2 Quadrangle */ 345 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 346 break; 347 default: 348 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 349 } 350 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 351 } 352 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 353 switch (numCoords) { 354 case 6: 355 case 12: /* Localized triangle */ 356 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 357 break; 358 case 8: 359 case 16: /* Localized quadrilateral */ 360 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 361 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 362 break; 363 default: 364 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 365 } 366 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 367 } 368 PetscCall(VecRestoreArrayRead(fv, &array)); 369 PetscCall(PetscDrawFlush(draw)); 370 PetscCall(PetscDrawPause(draw)); 371 PetscCall(PetscDrawSave(draw)); 372 } 373 if (Nf > 1) { 374 PetscCall(VecRestoreSubVector(v, fis, &fv)); 375 PetscCall(ISDestroy(&fis)); 376 PetscCall(DMDestroy(&fdm)); 377 } 378 } 379 PetscFunctionReturn(0); 380 } 381 382 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 383 { 384 DM dm; 385 PetscDraw draw; 386 PetscInt dim; 387 PetscBool isnull; 388 389 PetscFunctionBegin; 390 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 391 PetscCall(PetscDrawIsNull(draw, &isnull)); 392 if (isnull) PetscFunctionReturn(0); 393 394 PetscCall(VecGetDM(v, &dm)); 395 PetscCall(DMGetCoordinateDim(dm, &dim)); 396 switch (dim) { 397 case 1: 398 PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); 399 break; 400 case 2: 401 PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); 402 break; 403 default: 404 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 405 } 406 PetscFunctionReturn(0); 407 } 408 409 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 410 { 411 DM dm; 412 Vec locv; 413 const char *name; 414 PetscSection section; 415 PetscInt pStart, pEnd; 416 PetscInt numFields; 417 PetscViewerVTKFieldType ft; 418 419 PetscFunctionBegin; 420 PetscCall(VecGetDM(v, &dm)); 421 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 422 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 423 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 424 PetscCall(VecCopy(v, locv)); 425 PetscCall(DMGetLocalSection(dm, §ion)); 426 PetscCall(PetscSectionGetNumFields(section, &numFields)); 427 if (!numFields) { 428 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 429 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 430 } else { 431 PetscInt f; 432 433 for (f = 0; f < numFields; f++) { 434 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 435 if (ft == PETSC_VTK_INVALID) continue; 436 PetscCall(PetscObjectReference((PetscObject)locv)); 437 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 438 } 439 PetscCall(VecDestroy(&locv)); 440 } 441 PetscFunctionReturn(0); 442 } 443 444 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 445 { 446 DM dm; 447 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 448 449 PetscFunctionBegin; 450 PetscCall(VecGetDM(v, &dm)); 451 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 453 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 454 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 455 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 456 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 457 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 458 PetscInt i, numFields; 459 PetscObject fe; 460 PetscBool fem = PETSC_FALSE; 461 Vec locv = v; 462 const char *name; 463 PetscInt step; 464 PetscReal time; 465 466 PetscCall(DMGetNumFields(dm, &numFields)); 467 for (i = 0; i < numFields; i++) { 468 PetscCall(DMGetField(dm, i, NULL, &fe)); 469 if (fe->classid == PETSCFE_CLASSID) { 470 fem = PETSC_TRUE; 471 break; 472 } 473 } 474 if (fem) { 475 PetscObject isZero; 476 477 PetscCall(DMGetLocalVector(dm, &locv)); 478 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 479 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 480 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 481 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 482 PetscCall(VecCopy(v, locv)); 483 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 484 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 485 } 486 if (isvtk) { 487 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 488 } else if (ishdf5) { 489 #if defined(PETSC_HAVE_HDF5) 490 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 491 #else 492 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 493 #endif 494 } else if (isdraw) { 495 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 496 } else if (isglvis) { 497 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 498 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 499 PetscCall(VecView_GLVis(locv, viewer)); 500 } else if (iscgns) { 501 #if defined(PETSC_HAVE_CGNS) 502 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 503 #else 504 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 505 #endif 506 } 507 if (fem) { 508 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 509 PetscCall(DMRestoreLocalVector(dm, &locv)); 510 } 511 } else { 512 PetscBool isseq; 513 514 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 515 if (isseq) PetscCall(VecView_Seq(v, viewer)); 516 else PetscCall(VecView_MPI(v, viewer)); 517 } 518 PetscFunctionReturn(0); 519 } 520 521 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 522 { 523 DM dm; 524 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 525 526 PetscFunctionBegin; 527 PetscCall(VecGetDM(v, &dm)); 528 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 529 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 530 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 532 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 533 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 534 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 535 if (isvtk || isdraw || isglvis || iscgns) { 536 Vec locv; 537 PetscObject isZero; 538 const char *name; 539 540 PetscCall(DMGetLocalVector(dm, &locv)); 541 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 542 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 543 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 544 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 545 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 546 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 547 PetscCall(VecView_Plex_Local(locv, viewer)); 548 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 549 PetscCall(DMRestoreLocalVector(dm, &locv)); 550 } else if (ishdf5) { 551 #if defined(PETSC_HAVE_HDF5) 552 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 553 #else 554 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 555 #endif 556 } else if (isexodusii) { 557 #if defined(PETSC_HAVE_EXODUSII) 558 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 559 #else 560 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 561 #endif 562 } else { 563 PetscBool isseq; 564 565 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 566 if (isseq) PetscCall(VecView_Seq(v, viewer)); 567 else PetscCall(VecView_MPI(v, viewer)); 568 } 569 PetscFunctionReturn(0); 570 } 571 572 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 573 { 574 DM dm; 575 MPI_Comm comm; 576 PetscViewerFormat format; 577 Vec v; 578 PetscBool isvtk, ishdf5; 579 580 PetscFunctionBegin; 581 PetscCall(VecGetDM(originalv, &dm)); 582 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 583 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 584 PetscCall(PetscViewerGetFormat(viewer, &format)); 585 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 586 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 587 if (format == PETSC_VIEWER_NATIVE) { 588 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 589 /* this need a better fix */ 590 if (dm->useNatural) { 591 if (dm->sfNatural) { 592 const char *vecname; 593 PetscInt n, nroots; 594 595 PetscCall(VecGetLocalSize(originalv, &n)); 596 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 597 if (n == nroots) { 598 PetscCall(DMGetGlobalVector(dm, &v)); 599 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 600 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 601 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 602 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 603 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 604 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 605 } else v = originalv; 606 } else v = originalv; 607 608 if (ishdf5) { 609 #if defined(PETSC_HAVE_HDF5) 610 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 611 #else 612 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 613 #endif 614 } else if (isvtk) { 615 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 616 } else { 617 PetscBool isseq; 618 619 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 620 if (isseq) PetscCall(VecView_Seq(v, viewer)); 621 else PetscCall(VecView_MPI(v, viewer)); 622 } 623 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 636 if (ishdf5) { 637 DM dmBC; 638 Vec gv; 639 const char *name; 640 641 PetscCall(DMGetOutputDM(dm, &dmBC)); 642 PetscCall(DMGetGlobalVector(dmBC, &gv)); 643 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 644 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 645 PetscCall(VecLoad_Default(gv, viewer)); 646 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 647 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 648 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 649 } else PetscCall(VecLoad_Default(v, viewer)); 650 PetscFunctionReturn(0); 651 } 652 653 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 654 { 655 DM dm; 656 PetscBool ishdf5, isexodusii; 657 658 PetscFunctionBegin; 659 PetscCall(VecGetDM(v, &dm)); 660 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 661 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 662 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 663 if (ishdf5) { 664 #if defined(PETSC_HAVE_HDF5) 665 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 666 #else 667 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 668 #endif 669 } else if (isexodusii) { 670 #if defined(PETSC_HAVE_EXODUSII) 671 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 672 #else 673 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 674 #endif 675 } else PetscCall(VecLoad_Default(v, viewer)); 676 PetscFunctionReturn(0); 677 } 678 679 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 680 { 681 DM dm; 682 PetscViewerFormat format; 683 PetscBool ishdf5; 684 685 PetscFunctionBegin; 686 PetscCall(VecGetDM(originalv, &dm)); 687 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 688 PetscCall(PetscViewerGetFormat(viewer, &format)); 689 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 690 if (format == PETSC_VIEWER_NATIVE) { 691 if (dm->useNatural) { 692 if (dm->sfNatural) { 693 if (ishdf5) { 694 #if defined(PETSC_HAVE_HDF5) 695 Vec v; 696 const char *vecname; 697 698 PetscCall(DMGetGlobalVector(dm, &v)); 699 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 700 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 701 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 702 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 703 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 704 PetscCall(DMRestoreGlobalVector(dm, &v)); 705 #else 706 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 707 #endif 708 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 709 } 710 } else PetscCall(VecLoad_Default(originalv, viewer)); 711 } 712 PetscFunctionReturn(0); 713 } 714 715 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 716 { 717 PetscSection coordSection; 718 Vec coordinates; 719 DMLabel depthLabel, celltypeLabel; 720 const char *name[4]; 721 const PetscScalar *a; 722 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 723 724 PetscFunctionBegin; 725 PetscCall(DMGetDimension(dm, &dim)); 726 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 727 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 728 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 729 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 730 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 731 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 732 PetscCall(VecGetArrayRead(coordinates, &a)); 733 name[0] = "vertex"; 734 name[1] = "edge"; 735 name[dim - 1] = "face"; 736 name[dim] = "cell"; 737 for (c = cStart; c < cEnd; ++c) { 738 PetscInt *closure = NULL; 739 PetscInt closureSize, cl, ct; 740 741 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 742 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 743 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 744 PetscCall(PetscViewerASCIIPushTab(viewer)); 745 for (cl = 0; cl < closureSize * 2; cl += 2) { 746 PetscInt point = closure[cl], depth, dof, off, d, p; 747 748 if ((point < pStart) || (point >= pEnd)) continue; 749 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 750 if (!dof) continue; 751 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 752 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 753 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 754 for (p = 0; p < dof / dim; ++p) { 755 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 756 for (d = 0; d < dim; ++d) { 757 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 758 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 759 } 760 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 761 } 762 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 763 } 764 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 765 PetscCall(PetscViewerASCIIPopTab(viewer)); 766 } 767 PetscCall(VecRestoreArrayRead(coordinates, &a)); 768 PetscFunctionReturn(0); 769 } 770 771 typedef enum { 772 CS_CARTESIAN, 773 CS_POLAR, 774 CS_CYLINDRICAL, 775 CS_SPHERICAL 776 } CoordSystem; 777 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 778 779 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 780 { 781 PetscInt i; 782 783 PetscFunctionBegin; 784 if (dim > 3) { 785 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 786 } else { 787 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 788 789 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 790 switch (cs) { 791 case CS_CARTESIAN: 792 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 793 break; 794 case CS_POLAR: 795 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 796 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 797 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 798 break; 799 case CS_CYLINDRICAL: 800 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 801 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 802 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 803 trcoords[2] = coords[2]; 804 break; 805 case CS_SPHERICAL: 806 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 807 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 808 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 809 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 810 break; 811 } 812 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 813 } 814 PetscFunctionReturn(0); 815 } 816 817 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 818 { 819 DM_Plex *mesh = (DM_Plex *)dm->data; 820 DM cdm, cdmCell; 821 PetscSection coordSection, coordSectionCell; 822 Vec coordinates, coordinatesCell; 823 PetscViewerFormat format; 824 825 PetscFunctionBegin; 826 PetscCall(DMGetCoordinateDM(dm, &cdm)); 827 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 828 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 829 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 830 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 831 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 832 PetscCall(PetscViewerGetFormat(viewer, &format)); 833 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 834 const char *name; 835 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 836 PetscInt pStart, pEnd, p, numLabels, l; 837 PetscMPIInt rank, size; 838 839 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 840 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 841 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 842 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 843 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 844 PetscCall(DMGetDimension(dm, &dim)); 845 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 846 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 847 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 848 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 849 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 850 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 851 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 852 for (p = pStart; p < pEnd; ++p) { 853 PetscInt dof, off, s; 854 855 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 856 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 857 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 858 } 859 PetscCall(PetscViewerFlush(viewer)); 860 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 861 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 862 for (p = pStart; p < pEnd; ++p) { 863 PetscInt dof, off, c; 864 865 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 866 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 867 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 868 } 869 PetscCall(PetscViewerFlush(viewer)); 870 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 871 if (coordSection && coordinates) { 872 CoordSystem cs = CS_CARTESIAN; 873 const PetscScalar *array, *arrayCell = NULL; 874 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 875 PetscMPIInt rank; 876 const char *name; 877 878 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 879 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 880 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 881 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 882 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 883 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 884 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 885 pStart = PetscMin(pvStart, pcStart); 886 pEnd = PetscMax(pvEnd, pcEnd); 887 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 888 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 889 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 890 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 891 892 PetscCall(VecGetArrayRead(coordinates, &array)); 893 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 894 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 895 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 896 for (p = pStart; p < pEnd; ++p) { 897 PetscInt dof, off; 898 899 if (p >= pvStart && p < pvEnd) { 900 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 901 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 902 if (dof) { 903 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 904 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 905 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 906 } 907 } 908 if (cdmCell && p >= pcStart && p < pcEnd) { 909 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 910 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 911 if (dof) { 912 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 913 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 914 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 915 } 916 } 917 } 918 PetscCall(PetscViewerFlush(viewer)); 919 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 920 PetscCall(VecRestoreArrayRead(coordinates, &array)); 921 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 922 } 923 PetscCall(DMGetNumLabels(dm, &numLabels)); 924 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 925 for (l = 0; l < numLabels; ++l) { 926 DMLabel label; 927 PetscBool isdepth; 928 const char *name; 929 930 PetscCall(DMGetLabelName(dm, l, &name)); 931 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 932 if (isdepth) continue; 933 PetscCall(DMGetLabel(dm, name, &label)); 934 PetscCall(DMLabelView(label, viewer)); 935 } 936 if (size > 1) { 937 PetscSF sf; 938 939 PetscCall(DMGetPointSF(dm, &sf)); 940 PetscCall(PetscSFView(sf, viewer)); 941 } 942 PetscCall(PetscViewerFlush(viewer)); 943 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 944 const char *name, *color; 945 const char *defcolors[3] = {"gray", "orange", "green"}; 946 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 947 char lname[PETSC_MAX_PATH_LEN]; 948 PetscReal scale = 2.0; 949 PetscReal tikzscale = 1.0; 950 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 951 double tcoords[3]; 952 PetscScalar *coords; 953 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 954 PetscMPIInt rank, size; 955 char **names, **colors, **lcolors; 956 PetscBool flg, lflg; 957 PetscBT wp = NULL; 958 PetscInt pEnd, pStart; 959 960 PetscCall(DMGetDimension(dm, &dim)); 961 PetscCall(DMPlexGetDepth(dm, &depth)); 962 PetscCall(DMGetNumLabels(dm, &numLabels)); 963 numLabels = PetscMax(numLabels, 10); 964 numColors = 10; 965 numLColors = 10; 966 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 967 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 968 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 969 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 970 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 971 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 972 n = 4; 973 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 974 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 975 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 976 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 977 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 978 if (!useLabels) numLabels = 0; 979 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 980 if (!useColors) { 981 numColors = 3; 982 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 983 } 984 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 985 if (!useColors) { 986 numLColors = 4; 987 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 988 } 989 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 990 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 991 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 992 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 993 if (depth < dim) plotEdges = PETSC_FALSE; 994 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 995 996 /* filter points with labelvalue != labeldefaultvalue */ 997 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 998 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 999 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 1000 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1001 if (lflg) { 1002 DMLabel lbl; 1003 1004 PetscCall(DMGetLabel(dm, lname, &lbl)); 1005 if (lbl) { 1006 PetscInt val, defval; 1007 1008 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 1009 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 1010 for (c = pStart; c < pEnd; c++) { 1011 PetscInt *closure = NULL; 1012 PetscInt closureSize; 1013 1014 PetscCall(DMLabelGetValue(lbl, c, &val)); 1015 if (val == defval) continue; 1016 1017 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1018 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 1019 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1020 } 1021 } 1022 } 1023 1024 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1025 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1026 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1028 \\documentclass[tikz]{standalone}\n\n\ 1029 \\usepackage{pgflibraryshapes}\n\ 1030 \\usetikzlibrary{backgrounds}\n\ 1031 \\usetikzlibrary{arrows}\n\ 1032 \\begin{document}\n")); 1033 if (size > 1) { 1034 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1035 for (p = 0; p < size; ++p) { 1036 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1037 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1038 } 1039 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1040 } 1041 if (drawHasse) { 1042 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1043 1044 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1045 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1046 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1047 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1048 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1049 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1050 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1051 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1052 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1053 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1054 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1055 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1056 } 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1058 1059 /* Plot vertices */ 1060 PetscCall(VecGetArray(coordinates, &coords)); 1061 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1062 for (v = vStart; v < vEnd; ++v) { 1063 PetscInt off, dof, d; 1064 PetscBool isLabeled = PETSC_FALSE; 1065 1066 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1067 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1068 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1069 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1070 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1071 for (d = 0; d < dof; ++d) { 1072 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1073 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1074 } 1075 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1076 if (dim == 3) { 1077 PetscReal tmp = tcoords[1]; 1078 tcoords[1] = tcoords[2]; 1079 tcoords[2] = -tmp; 1080 } 1081 for (d = 0; d < dof; ++d) { 1082 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1083 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1084 } 1085 if (drawHasse) color = colors[0 % numColors]; 1086 else color = colors[rank % numColors]; 1087 for (l = 0; l < numLabels; ++l) { 1088 PetscInt val; 1089 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1090 if (val >= 0) { 1091 color = lcolors[l % numLColors]; 1092 isLabeled = PETSC_TRUE; 1093 break; 1094 } 1095 } 1096 if (drawNumbers[0]) { 1097 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1098 } else if (drawColors[0]) { 1099 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1100 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1101 } 1102 PetscCall(VecRestoreArray(coordinates, &coords)); 1103 PetscCall(PetscViewerFlush(viewer)); 1104 /* Plot edges */ 1105 if (plotEdges) { 1106 PetscCall(VecGetArray(coordinates, &coords)); 1107 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1108 for (e = eStart; e < eEnd; ++e) { 1109 const PetscInt *cone; 1110 PetscInt coneSize, offA, offB, dof, d; 1111 1112 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1113 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1114 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1115 PetscCall(DMPlexGetCone(dm, e, &cone)); 1116 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1117 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1118 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1119 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1120 for (d = 0; d < dof; ++d) { 1121 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1122 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1123 } 1124 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1125 if (dim == 3) { 1126 PetscReal tmp = tcoords[1]; 1127 tcoords[1] = tcoords[2]; 1128 tcoords[2] = -tmp; 1129 } 1130 for (d = 0; d < dof; ++d) { 1131 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1132 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1133 } 1134 if (drawHasse) color = colors[1 % numColors]; 1135 else color = colors[rank % numColors]; 1136 for (l = 0; l < numLabels; ++l) { 1137 PetscInt val; 1138 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1139 if (val >= 0) { 1140 color = lcolors[l % numLColors]; 1141 break; 1142 } 1143 } 1144 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1145 } 1146 PetscCall(VecRestoreArray(coordinates, &coords)); 1147 PetscCall(PetscViewerFlush(viewer)); 1148 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1149 } 1150 /* Plot cells */ 1151 if (dim == 3 || !drawNumbers[1]) { 1152 for (e = eStart; e < eEnd; ++e) { 1153 const PetscInt *cone; 1154 1155 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1156 color = colors[rank % numColors]; 1157 for (l = 0; l < numLabels; ++l) { 1158 PetscInt val; 1159 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1160 if (val >= 0) { 1161 color = lcolors[l % numLColors]; 1162 break; 1163 } 1164 } 1165 PetscCall(DMPlexGetCone(dm, e, &cone)); 1166 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1167 } 1168 } else { 1169 DMPolytopeType ct; 1170 1171 /* Drawing a 2D polygon */ 1172 for (c = cStart; c < cEnd; ++c) { 1173 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1174 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1175 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1176 const PetscInt *cone; 1177 PetscInt coneSize, e; 1178 1179 PetscCall(DMPlexGetCone(dm, c, &cone)); 1180 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1181 for (e = 0; e < coneSize; ++e) { 1182 const PetscInt *econe; 1183 1184 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1185 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)); 1186 } 1187 } else { 1188 PetscInt *closure = NULL; 1189 PetscInt closureSize, Nv = 0, v; 1190 1191 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1192 for (p = 0; p < closureSize * 2; p += 2) { 1193 const PetscInt point = closure[p]; 1194 1195 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1196 } 1197 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1198 for (v = 0; v <= Nv; ++v) { 1199 const PetscInt vertex = closure[v % Nv]; 1200 1201 if (v > 0) { 1202 if (plotEdges) { 1203 const PetscInt *edge; 1204 PetscInt endpoints[2], ne; 1205 1206 endpoints[0] = closure[v - 1]; 1207 endpoints[1] = vertex; 1208 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1209 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1210 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1211 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1212 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1213 } 1214 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1215 } 1216 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1217 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1218 } 1219 } 1220 } 1221 for (c = cStart; c < cEnd; ++c) { 1222 double ccoords[3] = {0.0, 0.0, 0.0}; 1223 PetscBool isLabeled = PETSC_FALSE; 1224 PetscScalar *cellCoords = NULL; 1225 const PetscScalar *array; 1226 PetscInt numCoords, cdim, d; 1227 PetscBool isDG; 1228 1229 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1230 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1231 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1232 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1233 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1234 for (p = 0; p < numCoords / cdim; ++p) { 1235 for (d = 0; d < cdim; ++d) { 1236 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1237 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1238 } 1239 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1240 if (cdim == 3) { 1241 PetscReal tmp = tcoords[1]; 1242 tcoords[1] = tcoords[2]; 1243 tcoords[2] = -tmp; 1244 } 1245 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1246 } 1247 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1248 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1249 for (d = 0; d < cdim; ++d) { 1250 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1251 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1252 } 1253 if (drawHasse) color = colors[depth % numColors]; 1254 else color = colors[rank % numColors]; 1255 for (l = 0; l < numLabels; ++l) { 1256 PetscInt val; 1257 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1258 if (val >= 0) { 1259 color = lcolors[l % numLColors]; 1260 isLabeled = PETSC_TRUE; 1261 break; 1262 } 1263 } 1264 if (drawNumbers[dim]) { 1265 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1266 } else if (drawColors[dim]) { 1267 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1268 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1269 } 1270 if (drawHasse) { 1271 color = colors[depth % numColors]; 1272 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1273 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1274 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1275 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1277 1278 color = colors[1 % numColors]; 1279 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1280 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1281 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1282 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1283 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1284 1285 color = colors[0 % numColors]; 1286 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1287 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1288 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1289 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1290 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1291 1292 for (p = pStart; p < pEnd; ++p) { 1293 const PetscInt *cone; 1294 PetscInt coneSize, cp; 1295 1296 PetscCall(DMPlexGetCone(dm, p, &cone)); 1297 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1298 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1299 } 1300 } 1301 PetscCall(PetscViewerFlush(viewer)); 1302 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1303 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1304 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1305 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1306 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1307 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1308 PetscCall(PetscFree3(names, colors, lcolors)); 1309 PetscCall(PetscBTDestroy(&wp)); 1310 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1311 Vec cown, acown; 1312 VecScatter sct; 1313 ISLocalToGlobalMapping g2l; 1314 IS gid, acis; 1315 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1316 MPI_Group ggroup, ngroup; 1317 PetscScalar *array, nid; 1318 const PetscInt *idxs; 1319 PetscInt *idxs2, *start, *adjacency, *work; 1320 PetscInt64 lm[3], gm[3]; 1321 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1322 PetscMPIInt d1, d2, rank; 1323 1324 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1325 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1326 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1327 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1328 #endif 1329 if (ncomm != MPI_COMM_NULL) { 1330 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1331 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1332 d1 = 0; 1333 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1334 nid = d2; 1335 PetscCallMPI(MPI_Group_free(&ggroup)); 1336 PetscCallMPI(MPI_Group_free(&ngroup)); 1337 PetscCallMPI(MPI_Comm_free(&ncomm)); 1338 } else nid = 0.0; 1339 1340 /* Get connectivity */ 1341 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1342 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1343 1344 /* filter overlapped local cells */ 1345 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1346 PetscCall(ISGetIndices(gid, &idxs)); 1347 PetscCall(ISGetLocalSize(gid, &cum)); 1348 PetscCall(PetscMalloc1(cum, &idxs2)); 1349 for (c = cStart, cum = 0; c < cEnd; c++) { 1350 if (idxs[c - cStart] < 0) continue; 1351 idxs2[cum++] = idxs[c - cStart]; 1352 } 1353 PetscCall(ISRestoreIndices(gid, &idxs)); 1354 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1355 PetscCall(ISDestroy(&gid)); 1356 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1357 1358 /* support for node-aware cell locality */ 1359 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1360 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1361 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1362 PetscCall(VecGetArray(cown, &array)); 1363 for (c = 0; c < numVertices; c++) array[c] = nid; 1364 PetscCall(VecRestoreArray(cown, &array)); 1365 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1366 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1367 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1368 PetscCall(ISDestroy(&acis)); 1369 PetscCall(VecScatterDestroy(&sct)); 1370 PetscCall(VecDestroy(&cown)); 1371 1372 /* compute edgeCut */ 1373 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1374 PetscCall(PetscMalloc1(cum, &work)); 1375 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1376 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1377 PetscCall(ISDestroy(&gid)); 1378 PetscCall(VecGetArray(acown, &array)); 1379 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1380 PetscInt totl; 1381 1382 totl = start[c + 1] - start[c]; 1383 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1384 for (i = 0; i < totl; i++) { 1385 if (work[i] < 0) { 1386 ect += 1; 1387 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1388 } 1389 } 1390 } 1391 PetscCall(PetscFree(work)); 1392 PetscCall(VecRestoreArray(acown, &array)); 1393 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1394 lm[1] = -numVertices; 1395 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1396 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1397 lm[0] = ect; /* edgeCut */ 1398 lm[1] = ectn; /* node-aware edgeCut */ 1399 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1400 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1401 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1402 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1403 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1404 #else 1405 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1406 #endif 1407 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1408 PetscCall(PetscFree(start)); 1409 PetscCall(PetscFree(adjacency)); 1410 PetscCall(VecDestroy(&acown)); 1411 } else { 1412 const char *name; 1413 PetscInt *sizes, *hybsizes, *ghostsizes; 1414 PetscInt locDepth, depth, cellHeight, dim, d; 1415 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1416 PetscInt numLabels, l, maxSize = 17; 1417 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1418 MPI_Comm comm; 1419 PetscMPIInt size, rank; 1420 1421 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1422 PetscCallMPI(MPI_Comm_size(comm, &size)); 1423 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1424 PetscCall(DMGetDimension(dm, &dim)); 1425 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1426 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1427 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1428 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1429 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1430 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1431 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1432 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1433 gcNum = gcEnd - gcStart; 1434 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1435 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1436 for (d = 0; d <= depth; d++) { 1437 PetscInt Nc[2] = {0, 0}, ict; 1438 1439 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1440 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1441 ict = ct0; 1442 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1443 ct0 = (DMPolytopeType)ict; 1444 for (p = pStart; p < pEnd; ++p) { 1445 DMPolytopeType ct; 1446 1447 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1448 if (ct == ct0) ++Nc[0]; 1449 else ++Nc[1]; 1450 } 1451 if (size < maxSize) { 1452 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1453 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1454 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1455 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1456 for (p = 0; p < size; ++p) { 1457 if (rank == 0) { 1458 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1459 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1460 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1461 } 1462 } 1463 } else { 1464 PetscInt locMinMax[2]; 1465 1466 locMinMax[0] = Nc[0] + Nc[1]; 1467 locMinMax[1] = Nc[0] + Nc[1]; 1468 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1469 locMinMax[0] = Nc[1]; 1470 locMinMax[1] = Nc[1]; 1471 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1472 if (d == depth) { 1473 locMinMax[0] = gcNum; 1474 locMinMax[1] = gcNum; 1475 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1476 } 1477 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1478 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1479 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1480 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1481 } 1482 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1483 } 1484 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1485 { 1486 const PetscReal *maxCell; 1487 const PetscReal *L; 1488 PetscBool localized; 1489 1490 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1491 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1492 if (L || localized) { 1493 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1494 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1495 if (L) { 1496 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1497 for (d = 0; d < dim; ++d) { 1498 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1499 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1500 } 1501 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1502 } 1503 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1504 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1505 } 1506 } 1507 PetscCall(DMGetNumLabels(dm, &numLabels)); 1508 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1509 for (l = 0; l < numLabels; ++l) { 1510 DMLabel label; 1511 const char *name; 1512 IS valueIS; 1513 const PetscInt *values; 1514 PetscInt numValues, v; 1515 1516 PetscCall(DMGetLabelName(dm, l, &name)); 1517 PetscCall(DMGetLabel(dm, name, &label)); 1518 PetscCall(DMLabelGetNumValues(label, &numValues)); 1519 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1520 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1521 PetscCall(ISGetIndices(valueIS, &values)); 1522 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1523 for (v = 0; v < numValues; ++v) { 1524 PetscInt size; 1525 1526 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1527 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1528 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1529 } 1530 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1531 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1532 PetscCall(ISRestoreIndices(valueIS, &values)); 1533 PetscCall(ISDestroy(&valueIS)); 1534 } 1535 { 1536 char **labelNames; 1537 PetscInt Nl = numLabels; 1538 PetscBool flg; 1539 1540 PetscCall(PetscMalloc1(Nl, &labelNames)); 1541 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1542 for (l = 0; l < Nl; ++l) { 1543 DMLabel label; 1544 1545 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1546 if (flg) { 1547 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1548 PetscCall(DMLabelView(label, viewer)); 1549 } 1550 PetscCall(PetscFree(labelNames[l])); 1551 } 1552 PetscCall(PetscFree(labelNames)); 1553 } 1554 /* If no fields are specified, people do not want to see adjacency */ 1555 if (dm->Nf) { 1556 PetscInt f; 1557 1558 for (f = 0; f < dm->Nf; ++f) { 1559 const char *name; 1560 1561 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1562 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1563 PetscCall(PetscViewerASCIIPushTab(viewer)); 1564 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1565 if (dm->fields[f].adjacency[0]) { 1566 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1567 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1568 } else { 1569 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1570 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1571 } 1572 PetscCall(PetscViewerASCIIPopTab(viewer)); 1573 } 1574 } 1575 PetscCall(DMGetCoarseDM(dm, &cdm)); 1576 if (cdm) { 1577 PetscCall(PetscViewerASCIIPushTab(viewer)); 1578 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1579 PetscCall(PetscViewerASCIIPopTab(viewer)); 1580 } 1581 } 1582 PetscFunctionReturn(0); 1583 } 1584 1585 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1586 { 1587 DMPolytopeType ct; 1588 PetscMPIInt rank; 1589 PetscInt cdim; 1590 1591 PetscFunctionBegin; 1592 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1593 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1594 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1595 switch (ct) { 1596 case DM_POLYTOPE_SEGMENT: 1597 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1598 switch (cdim) { 1599 case 1: { 1600 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1601 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1602 1603 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1604 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1605 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1606 } break; 1607 case 2: { 1608 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1609 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1610 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1611 1612 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1613 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)); 1614 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)); 1615 } break; 1616 default: 1617 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1618 } 1619 break; 1620 case DM_POLYTOPE_TRIANGLE: 1621 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)); 1622 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1623 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1624 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1625 break; 1626 case DM_POLYTOPE_QUADRILATERAL: 1627 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)); 1628 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)); 1629 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1630 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1631 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1632 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1633 break; 1634 case DM_POLYTOPE_FV_GHOST: 1635 break; 1636 default: 1637 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1638 } 1639 PetscFunctionReturn(0); 1640 } 1641 1642 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1643 { 1644 DMPolytopeType ct; 1645 PetscReal centroid[2] = {0., 0.}; 1646 PetscMPIInt rank; 1647 PetscInt fillColor, v, e, d; 1648 1649 PetscFunctionBegin; 1650 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1651 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1652 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1653 switch (ct) { 1654 case DM_POLYTOPE_TRIANGLE: { 1655 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1656 1657 for (v = 0; v < 3; ++v) { 1658 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1659 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1660 } 1661 for (e = 0; e < 3; ++e) { 1662 refCoords[0] = refVertices[e * 2 + 0]; 1663 refCoords[1] = refVertices[e * 2 + 1]; 1664 for (d = 1; d <= edgeDiv; ++d) { 1665 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1666 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1667 } 1668 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1669 for (d = 0; d < edgeDiv; ++d) { 1670 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)); 1671 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1672 } 1673 } 1674 } break; 1675 default: 1676 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1677 } 1678 PetscFunctionReturn(0); 1679 } 1680 1681 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1682 { 1683 PetscDraw draw; 1684 DM cdm; 1685 PetscSection coordSection; 1686 Vec coordinates; 1687 const PetscScalar *coords; 1688 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1689 PetscReal *refCoords, *edgeCoords; 1690 PetscBool isnull, drawAffine = PETSC_TRUE; 1691 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1692 1693 PetscFunctionBegin; 1694 PetscCall(DMGetCoordinateDim(dm, &dim)); 1695 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1696 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1697 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1698 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1699 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1700 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1701 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1702 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1703 1704 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1705 PetscCall(PetscDrawIsNull(draw, &isnull)); 1706 if (isnull) PetscFunctionReturn(0); 1707 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1708 1709 PetscCall(VecGetLocalSize(coordinates, &N)); 1710 PetscCall(VecGetArrayRead(coordinates, &coords)); 1711 for (c = 0; c < N; c += dim) { 1712 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1713 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1714 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1715 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1716 } 1717 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1718 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1719 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1720 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1721 PetscCall(PetscDrawClear(draw)); 1722 1723 for (c = cStart; c < cEnd; ++c) { 1724 PetscScalar *coords = NULL; 1725 PetscInt numCoords; 1726 1727 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1728 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1729 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1730 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1731 } 1732 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1733 PetscCall(PetscDrawFlush(draw)); 1734 PetscCall(PetscDrawPause(draw)); 1735 PetscCall(PetscDrawSave(draw)); 1736 PetscFunctionReturn(0); 1737 } 1738 1739 #if defined(PETSC_HAVE_EXODUSII) 1740 #include <exodusII.h> 1741 #include <petscviewerexodusii.h> 1742 #endif 1743 1744 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1745 { 1746 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1747 char name[PETSC_MAX_PATH_LEN]; 1748 1749 PetscFunctionBegin; 1750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1751 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1752 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1753 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1754 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1755 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1756 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1757 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1758 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1759 if (iascii) { 1760 PetscViewerFormat format; 1761 PetscCall(PetscViewerGetFormat(viewer, &format)); 1762 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1763 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1764 } else if (ishdf5) { 1765 #if defined(PETSC_HAVE_HDF5) 1766 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1767 #else 1768 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1769 #endif 1770 } else if (isvtk) { 1771 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1772 } else if (isdraw) { 1773 PetscCall(DMPlexView_Draw(dm, viewer)); 1774 } else if (isglvis) { 1775 PetscCall(DMPlexView_GLVis(dm, viewer)); 1776 #if defined(PETSC_HAVE_EXODUSII) 1777 } else if (isexodus) { 1778 /* 1779 exodusII requires that all sets be part of exactly one cell set. 1780 If the dm does not have a "Cell Sets" label defined, we create one 1781 with ID 1, containig all cells. 1782 Note that if the Cell Sets label is defined but does not cover all cells, 1783 we may still have a problem. This should probably be checked here or in the viewer; 1784 */ 1785 PetscInt numCS; 1786 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1787 if (!numCS) { 1788 PetscInt cStart, cEnd, c; 1789 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1790 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1791 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1792 } 1793 PetscCall(DMView_PlexExodusII(dm, viewer)); 1794 #endif 1795 #if defined(PETSC_HAVE_CGNS) 1796 } else if (iscgns) { 1797 PetscCall(DMView_PlexCGNS(dm, viewer)); 1798 #endif 1799 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1800 /* Optionally view the partition */ 1801 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1802 if (flg) { 1803 Vec ranks; 1804 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1805 PetscCall(VecView(ranks, viewer)); 1806 PetscCall(VecDestroy(&ranks)); 1807 } 1808 /* Optionally view a label */ 1809 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1810 if (flg) { 1811 DMLabel label; 1812 Vec val; 1813 1814 PetscCall(DMGetLabel(dm, name, &label)); 1815 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1816 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1817 PetscCall(VecView(val, viewer)); 1818 PetscCall(VecDestroy(&val)); 1819 } 1820 PetscFunctionReturn(0); 1821 } 1822 1823 /*@ 1824 DMPlexTopologyView - Saves a DMPlex topology into a file 1825 1826 Collective on DM 1827 1828 Input Parameters: 1829 + dm - The DM whose topology is to be saved 1830 - viewer - The PetscViewer for saving 1831 1832 Level: advanced 1833 1834 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1835 @*/ 1836 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1837 { 1838 PetscBool ishdf5; 1839 1840 PetscFunctionBegin; 1841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1842 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1843 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1844 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1845 if (ishdf5) { 1846 #if defined(PETSC_HAVE_HDF5) 1847 PetscViewerFormat format; 1848 PetscCall(PetscViewerGetFormat(viewer, &format)); 1849 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1850 IS globalPointNumbering; 1851 1852 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1853 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1854 PetscCall(ISDestroy(&globalPointNumbering)); 1855 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1856 #else 1857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1858 #endif 1859 } 1860 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1861 PetscFunctionReturn(0); 1862 } 1863 1864 /*@ 1865 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1866 1867 Collective on DM 1868 1869 Input Parameters: 1870 + dm - The DM whose coordinates are to be saved 1871 - viewer - The PetscViewer for saving 1872 1873 Level: advanced 1874 1875 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1876 @*/ 1877 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1878 { 1879 PetscBool ishdf5; 1880 1881 PetscFunctionBegin; 1882 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1883 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1884 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1885 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1886 if (ishdf5) { 1887 #if defined(PETSC_HAVE_HDF5) 1888 PetscViewerFormat format; 1889 PetscCall(PetscViewerGetFormat(viewer, &format)); 1890 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1891 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1892 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1893 #else 1894 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1895 #endif 1896 } 1897 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1898 PetscFunctionReturn(0); 1899 } 1900 1901 /*@ 1902 DMPlexLabelsView - Saves DMPlex labels into a file 1903 1904 Collective on DM 1905 1906 Input Parameters: 1907 + dm - The DM whose labels are to be saved 1908 - viewer - The PetscViewer for saving 1909 1910 Level: advanced 1911 1912 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1913 @*/ 1914 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1915 { 1916 PetscBool ishdf5; 1917 1918 PetscFunctionBegin; 1919 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1920 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1921 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1922 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1923 if (ishdf5) { 1924 #if defined(PETSC_HAVE_HDF5) 1925 IS globalPointNumbering; 1926 PetscViewerFormat format; 1927 1928 PetscCall(PetscViewerGetFormat(viewer, &format)); 1929 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1930 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1931 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1932 PetscCall(ISDestroy(&globalPointNumbering)); 1933 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1934 #else 1935 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1936 #endif 1937 } 1938 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1939 PetscFunctionReturn(0); 1940 } 1941 1942 /*@ 1943 DMPlexSectionView - Saves a section associated with a DMPlex 1944 1945 Collective on DM 1946 1947 Input Parameters: 1948 + dm - The DM that contains the topology on which the section to be saved is defined 1949 . viewer - The PetscViewer for saving 1950 - sectiondm - The DM that contains the section to be saved 1951 1952 Level: advanced 1953 1954 Notes: 1955 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. 1956 1957 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. 1958 1959 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1960 @*/ 1961 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1962 { 1963 PetscBool ishdf5; 1964 1965 PetscFunctionBegin; 1966 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1967 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1968 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1969 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1970 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1971 if (ishdf5) { 1972 #if defined(PETSC_HAVE_HDF5) 1973 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1974 #else 1975 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1976 #endif 1977 } 1978 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1979 PetscFunctionReturn(0); 1980 } 1981 1982 /*@ 1983 DMPlexGlobalVectorView - Saves a global vector 1984 1985 Collective on DM 1986 1987 Input Parameters: 1988 + dm - The DM that represents the topology 1989 . viewer - The PetscViewer to save data with 1990 . sectiondm - The DM that contains the global section on which vec is defined 1991 - vec - The global vector to be saved 1992 1993 Level: advanced 1994 1995 Notes: 1996 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. 1997 1998 Typical calling sequence 1999 $ DMCreate(PETSC_COMM_WORLD, &dm); 2000 $ DMSetType(dm, DMPLEX); 2001 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2002 $ DMClone(dm, §iondm); 2003 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2004 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2005 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2006 $ PetscSectionSetChart(section, pStart, pEnd); 2007 $ PetscSectionSetUp(section); 2008 $ DMSetLocalSection(sectiondm, section); 2009 $ PetscSectionDestroy(§ion); 2010 $ DMGetGlobalVector(sectiondm, &vec); 2011 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2012 $ DMPlexTopologyView(dm, viewer); 2013 $ DMPlexSectionView(dm, viewer, sectiondm); 2014 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 2015 $ DMRestoreGlobalVector(sectiondm, &vec); 2016 $ DMDestroy(§iondm); 2017 $ DMDestroy(&dm); 2018 2019 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2020 @*/ 2021 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2022 { 2023 PetscBool ishdf5; 2024 2025 PetscFunctionBegin; 2026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2027 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2028 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2029 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2030 /* Check consistency */ 2031 { 2032 PetscSection section; 2033 PetscBool includesConstraints; 2034 PetscInt m, m1; 2035 2036 PetscCall(VecGetLocalSize(vec, &m1)); 2037 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2038 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2039 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2040 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2041 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2042 } 2043 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2044 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2045 if (ishdf5) { 2046 #if defined(PETSC_HAVE_HDF5) 2047 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2048 #else 2049 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2050 #endif 2051 } 2052 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2053 PetscFunctionReturn(0); 2054 } 2055 2056 /*@ 2057 DMPlexLocalVectorView - Saves a local vector 2058 2059 Collective on DM 2060 2061 Input Parameters: 2062 + dm - The DM that represents the topology 2063 . viewer - The PetscViewer to save data with 2064 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2065 - vec - The local vector to be saved 2066 2067 Level: advanced 2068 2069 Notes: 2070 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. 2071 2072 Typical calling sequence 2073 $ DMCreate(PETSC_COMM_WORLD, &dm); 2074 $ DMSetType(dm, DMPLEX); 2075 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2076 $ DMClone(dm, §iondm); 2077 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2078 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2079 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2080 $ PetscSectionSetChart(section, pStart, pEnd); 2081 $ PetscSectionSetUp(section); 2082 $ DMSetLocalSection(sectiondm, section); 2083 $ DMGetLocalVector(sectiondm, &vec); 2084 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2085 $ DMPlexTopologyView(dm, viewer); 2086 $ DMPlexSectionView(dm, viewer, sectiondm); 2087 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2088 $ DMRestoreLocalVector(sectiondm, &vec); 2089 $ DMDestroy(§iondm); 2090 $ DMDestroy(&dm); 2091 2092 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2093 @*/ 2094 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2095 { 2096 PetscBool ishdf5; 2097 2098 PetscFunctionBegin; 2099 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2100 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2101 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2102 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2103 /* Check consistency */ 2104 { 2105 PetscSection section; 2106 PetscBool includesConstraints; 2107 PetscInt m, m1; 2108 2109 PetscCall(VecGetLocalSize(vec, &m1)); 2110 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2111 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2112 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2113 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2114 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2115 } 2116 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2117 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2118 if (ishdf5) { 2119 #if defined(PETSC_HAVE_HDF5) 2120 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2121 #else 2122 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2123 #endif 2124 } 2125 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2126 PetscFunctionReturn(0); 2127 } 2128 2129 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2130 { 2131 PetscBool ishdf5; 2132 2133 PetscFunctionBegin; 2134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2135 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2136 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2137 if (ishdf5) { 2138 #if defined(PETSC_HAVE_HDF5) 2139 PetscViewerFormat format; 2140 PetscCall(PetscViewerGetFormat(viewer, &format)); 2141 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2142 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2143 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2144 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2145 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2146 PetscFunctionReturn(0); 2147 #else 2148 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2149 #endif 2150 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2151 } 2152 2153 /*@ 2154 DMPlexTopologyLoad - Loads a topology into a DMPlex 2155 2156 Collective on DM 2157 2158 Input Parameters: 2159 + dm - The DM into which the topology is loaded 2160 - viewer - The PetscViewer for the saved topology 2161 2162 Output Parameters: 2163 . 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 2164 2165 Level: advanced 2166 2167 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2168 @*/ 2169 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2170 { 2171 PetscBool ishdf5; 2172 2173 PetscFunctionBegin; 2174 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2175 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2176 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2177 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2178 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2179 if (ishdf5) { 2180 #if defined(PETSC_HAVE_HDF5) 2181 PetscViewerFormat format; 2182 PetscCall(PetscViewerGetFormat(viewer, &format)); 2183 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2184 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2185 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2186 #else 2187 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2188 #endif 2189 } 2190 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2191 PetscFunctionReturn(0); 2192 } 2193 2194 /*@ 2195 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2196 2197 Collective on DM 2198 2199 Input Parameters: 2200 + dm - The DM into which the coordinates are loaded 2201 . viewer - The PetscViewer for the saved coordinates 2202 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2203 2204 Level: advanced 2205 2206 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2207 @*/ 2208 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2209 { 2210 PetscBool ishdf5; 2211 2212 PetscFunctionBegin; 2213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2214 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2215 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2216 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2217 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2218 if (ishdf5) { 2219 #if defined(PETSC_HAVE_HDF5) 2220 PetscViewerFormat format; 2221 PetscCall(PetscViewerGetFormat(viewer, &format)); 2222 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2223 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2224 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2225 #else 2226 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2227 #endif 2228 } 2229 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2230 PetscFunctionReturn(0); 2231 } 2232 2233 /*@ 2234 DMPlexLabelsLoad - Loads labels into a DMPlex 2235 2236 Collective on DM 2237 2238 Input Parameters: 2239 + dm - The DM into which the labels are loaded 2240 . viewer - The PetscViewer for the saved labels 2241 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2242 2243 Level: advanced 2244 2245 Notes: 2246 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2247 2248 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2249 @*/ 2250 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2251 { 2252 PetscBool ishdf5; 2253 2254 PetscFunctionBegin; 2255 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2256 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2257 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2258 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2259 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2260 if (ishdf5) { 2261 #if defined(PETSC_HAVE_HDF5) 2262 PetscViewerFormat format; 2263 2264 PetscCall(PetscViewerGetFormat(viewer, &format)); 2265 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2266 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2267 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2268 #else 2269 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2270 #endif 2271 } 2272 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2273 PetscFunctionReturn(0); 2274 } 2275 2276 /*@ 2277 DMPlexSectionLoad - Loads section into a DMPlex 2278 2279 Collective on DM 2280 2281 Input Parameters: 2282 + dm - The DM that represents the topology 2283 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2284 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2285 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2286 2287 Output Parameters 2288 + 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) 2289 - 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) 2290 2291 Level: advanced 2292 2293 Notes: 2294 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. 2295 2296 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. 2297 2298 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. 2299 2300 Example using 2 processes: 2301 $ NX (number of points on dm): 4 2302 $ sectionA : the on-disk section 2303 $ vecA : a vector associated with sectionA 2304 $ sectionB : sectiondm's local section constructed in this function 2305 $ vecB (local) : a vector associated with sectiondm's local section 2306 $ vecB (global) : a vector associated with sectiondm's global section 2307 $ 2308 $ rank 0 rank 1 2309 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2310 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2311 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2312 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2313 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2314 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2315 $ sectionB->atlasDof : 1 0 1 | 1 3 2316 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2317 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2318 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2319 $ 2320 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2321 2322 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2323 @*/ 2324 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2325 { 2326 PetscBool ishdf5; 2327 2328 PetscFunctionBegin; 2329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2330 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2331 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2332 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2333 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2334 if (localDofSF) PetscValidPointer(localDofSF, 6); 2335 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2336 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2337 if (ishdf5) { 2338 #if defined(PETSC_HAVE_HDF5) 2339 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2340 #else 2341 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2342 #endif 2343 } 2344 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2345 PetscFunctionReturn(0); 2346 } 2347 2348 /*@ 2349 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2350 2351 Collective on DM 2352 2353 Input Parameters: 2354 + dm - The DM that represents the topology 2355 . viewer - The PetscViewer that represents the on-disk vector data 2356 . sectiondm - The DM that contains the global section on which vec is defined 2357 . sf - The SF that migrates the on-disk vector data into vec 2358 - vec - The global vector to set values of 2359 2360 Level: advanced 2361 2362 Notes: 2363 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. 2364 2365 Typical calling sequence 2366 $ DMCreate(PETSC_COMM_WORLD, &dm); 2367 $ DMSetType(dm, DMPLEX); 2368 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2369 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2370 $ DMClone(dm, §iondm); 2371 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2372 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2373 $ DMGetGlobalVector(sectiondm, &vec); 2374 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2375 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2376 $ DMRestoreGlobalVector(sectiondm, &vec); 2377 $ PetscSFDestroy(&gsf); 2378 $ PetscSFDestroy(&sfX); 2379 $ DMDestroy(§iondm); 2380 $ DMDestroy(&dm); 2381 2382 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2383 @*/ 2384 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2385 { 2386 PetscBool ishdf5; 2387 2388 PetscFunctionBegin; 2389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2390 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2391 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2392 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2393 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2394 /* Check consistency */ 2395 { 2396 PetscSection section; 2397 PetscBool includesConstraints; 2398 PetscInt m, m1; 2399 2400 PetscCall(VecGetLocalSize(vec, &m1)); 2401 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2402 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2403 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2404 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2405 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2406 } 2407 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2408 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2409 if (ishdf5) { 2410 #if defined(PETSC_HAVE_HDF5) 2411 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2412 #else 2413 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2414 #endif 2415 } 2416 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2417 PetscFunctionReturn(0); 2418 } 2419 2420 /*@ 2421 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2422 2423 Collective on DM 2424 2425 Input Parameters: 2426 + dm - The DM that represents the topology 2427 . viewer - The PetscViewer that represents the on-disk vector data 2428 . sectiondm - The DM that contains the local section on which vec is defined 2429 . sf - The SF that migrates the on-disk vector data into vec 2430 - vec - The local vector to set values of 2431 2432 Level: advanced 2433 2434 Notes: 2435 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. 2436 2437 Typical calling sequence 2438 $ DMCreate(PETSC_COMM_WORLD, &dm); 2439 $ DMSetType(dm, DMPLEX); 2440 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2441 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2442 $ DMClone(dm, §iondm); 2443 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2444 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2445 $ DMGetLocalVector(sectiondm, &vec); 2446 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2447 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2448 $ DMRestoreLocalVector(sectiondm, &vec); 2449 $ PetscSFDestroy(&lsf); 2450 $ PetscSFDestroy(&sfX); 2451 $ DMDestroy(§iondm); 2452 $ DMDestroy(&dm); 2453 2454 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2455 @*/ 2456 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2457 { 2458 PetscBool ishdf5; 2459 2460 PetscFunctionBegin; 2461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2462 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2463 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2464 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2465 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2466 /* Check consistency */ 2467 { 2468 PetscSection section; 2469 PetscBool includesConstraints; 2470 PetscInt m, m1; 2471 2472 PetscCall(VecGetLocalSize(vec, &m1)); 2473 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2474 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2475 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2476 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2477 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2478 } 2479 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2480 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2481 if (ishdf5) { 2482 #if defined(PETSC_HAVE_HDF5) 2483 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2484 #else 2485 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2486 #endif 2487 } 2488 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2489 PetscFunctionReturn(0); 2490 } 2491 2492 PetscErrorCode DMDestroy_Plex(DM dm) 2493 { 2494 DM_Plex *mesh = (DM_Plex *)dm->data; 2495 2496 PetscFunctionBegin; 2497 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2498 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2499 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2500 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2501 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2502 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2503 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2504 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2505 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2506 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2507 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2508 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2509 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2510 if (--mesh->refct > 0) PetscFunctionReturn(0); 2511 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2512 PetscCall(PetscFree(mesh->cones)); 2513 PetscCall(PetscFree(mesh->coneOrientations)); 2514 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2515 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2516 PetscCall(PetscFree(mesh->supports)); 2517 PetscCall(PetscFree(mesh->facesTmp)); 2518 PetscCall(PetscFree(mesh->tetgenOpts)); 2519 PetscCall(PetscFree(mesh->triangleOpts)); 2520 PetscCall(PetscFree(mesh->transformType)); 2521 PetscCall(PetscFree(mesh->distributionName)); 2522 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2523 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2524 PetscCall(ISDestroy(&mesh->subpointIS)); 2525 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2526 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2527 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2528 PetscCall(ISDestroy(&mesh->anchorIS)); 2529 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2530 PetscCall(PetscFree(mesh->parents)); 2531 PetscCall(PetscFree(mesh->childIDs)); 2532 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2533 PetscCall(PetscFree(mesh->children)); 2534 PetscCall(DMDestroy(&mesh->referenceTree)); 2535 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2536 PetscCall(PetscFree(mesh->neighbors)); 2537 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2538 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2539 PetscCall(PetscFree(mesh)); 2540 PetscFunctionReturn(0); 2541 } 2542 2543 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2544 { 2545 PetscSection sectionGlobal; 2546 PetscInt bs = -1, mbs; 2547 PetscInt localSize, localStart = 0; 2548 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2549 MatType mtype; 2550 ISLocalToGlobalMapping ltog; 2551 2552 PetscFunctionBegin; 2553 PetscCall(MatInitializePackage()); 2554 mtype = dm->mattype; 2555 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2556 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2557 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2558 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2559 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2560 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2561 PetscCall(MatSetType(*J, mtype)); 2562 PetscCall(MatSetFromOptions(*J)); 2563 PetscCall(MatGetBlockSize(*J, &mbs)); 2564 if (mbs > 1) bs = mbs; 2565 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2566 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2567 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2568 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2569 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2570 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2571 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2572 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2573 if (!isShell) { 2574 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2575 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2576 PetscInt pStart, pEnd, p, dof, cdof; 2577 2578 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2579 2580 PetscCall(PetscCalloc1(localSize, &pblocks)); 2581 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2582 for (p = pStart; p < pEnd; ++p) { 2583 PetscInt bdof, offset; 2584 2585 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2586 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2587 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2588 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2589 dof = dof < 0 ? -(dof + 1) : dof; 2590 bdof = cdof && (dof - cdof) ? 1 : dof; 2591 if (dof) { 2592 if (bs < 0) { 2593 bs = bdof; 2594 } else if (bs != bdof) { 2595 bs = 1; 2596 } 2597 } 2598 } 2599 /* Must have same blocksize on all procs (some might have no points) */ 2600 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2601 bsLocal[1] = bs; 2602 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2603 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2604 else bs = bsMinMax[0]; 2605 bs = PetscMax(1, bs); 2606 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2607 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2608 PetscCall(MatSetBlockSize(*J, bs)); 2609 PetscCall(MatSetUp(*J)); 2610 } else { 2611 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2612 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2613 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2614 } 2615 { // Consolidate blocks 2616 PetscInt nblocks = 0; 2617 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2618 if (pblocks[i] == 0) continue; 2619 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2620 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]); 2621 } 2622 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2623 } 2624 PetscCall(PetscFree(pblocks)); 2625 } 2626 PetscCall(MatSetDM(*J, dm)); 2627 PetscFunctionReturn(0); 2628 } 2629 2630 /*@ 2631 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2632 2633 Not collective 2634 2635 Input Parameter: 2636 . mesh - The DMPlex 2637 2638 Output Parameters: 2639 . subsection - The subdomain section 2640 2641 Level: developer 2642 2643 .seealso: 2644 @*/ 2645 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2646 { 2647 DM_Plex *mesh = (DM_Plex *)dm->data; 2648 2649 PetscFunctionBegin; 2650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2651 if (!mesh->subdomainSection) { 2652 PetscSection section; 2653 PetscSF sf; 2654 2655 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2656 PetscCall(DMGetLocalSection(dm, §ion)); 2657 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2658 PetscCall(PetscSFDestroy(&sf)); 2659 } 2660 *subsection = mesh->subdomainSection; 2661 PetscFunctionReturn(0); 2662 } 2663 2664 /*@ 2665 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2666 2667 Not collective 2668 2669 Input Parameter: 2670 . mesh - The DMPlex 2671 2672 Output Parameters: 2673 + pStart - The first mesh point 2674 - pEnd - The upper bound for mesh points 2675 2676 Level: beginner 2677 2678 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2679 @*/ 2680 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2681 { 2682 DM_Plex *mesh = (DM_Plex *)dm->data; 2683 2684 PetscFunctionBegin; 2685 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2686 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2687 PetscFunctionReturn(0); 2688 } 2689 2690 /*@ 2691 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2692 2693 Not collective 2694 2695 Input Parameters: 2696 + mesh - The DMPlex 2697 . pStart - The first mesh point 2698 - pEnd - The upper bound for mesh points 2699 2700 Output Parameters: 2701 2702 Level: beginner 2703 2704 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2705 @*/ 2706 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2707 { 2708 DM_Plex *mesh = (DM_Plex *)dm->data; 2709 2710 PetscFunctionBegin; 2711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2712 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2713 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2714 PetscFunctionReturn(0); 2715 } 2716 2717 /*@ 2718 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2719 2720 Not collective 2721 2722 Input Parameters: 2723 + mesh - The DMPlex 2724 - p - The point, which must lie in the chart set with DMPlexSetChart() 2725 2726 Output Parameter: 2727 . size - The cone size for point p 2728 2729 Level: beginner 2730 2731 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2732 @*/ 2733 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2734 { 2735 DM_Plex *mesh = (DM_Plex *)dm->data; 2736 2737 PetscFunctionBegin; 2738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2739 PetscValidIntPointer(size, 3); 2740 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2741 PetscFunctionReturn(0); 2742 } 2743 2744 /*@ 2745 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2746 2747 Not collective 2748 2749 Input Parameters: 2750 + mesh - The DMPlex 2751 . p - The point, which must lie in the chart set with DMPlexSetChart() 2752 - size - The cone size for point p 2753 2754 Output Parameter: 2755 2756 Note: 2757 This should be called after DMPlexSetChart(). 2758 2759 Level: beginner 2760 2761 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2762 @*/ 2763 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2764 { 2765 DM_Plex *mesh = (DM_Plex *)dm->data; 2766 2767 PetscFunctionBegin; 2768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2769 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2770 PetscFunctionReturn(0); 2771 } 2772 2773 /*@ 2774 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2775 2776 Not collective 2777 2778 Input Parameters: 2779 + mesh - The DMPlex 2780 . p - The point, which must lie in the chart set with DMPlexSetChart() 2781 - size - The additional cone size for point p 2782 2783 Output Parameter: 2784 2785 Note: 2786 This should be called after DMPlexSetChart(). 2787 2788 Level: beginner 2789 2790 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2791 @*/ 2792 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2793 { 2794 DM_Plex *mesh = (DM_Plex *)dm->data; 2795 PetscFunctionBegin; 2796 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2797 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2798 PetscFunctionReturn(0); 2799 } 2800 2801 /*@C 2802 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2803 2804 Not collective 2805 2806 Input Parameters: 2807 + dm - The DMPlex 2808 - p - The point, which must lie in the chart set with DMPlexSetChart() 2809 2810 Output Parameter: 2811 . cone - An array of points which are on the in-edges for point p 2812 2813 Level: beginner 2814 2815 Fortran Notes: 2816 Since it returns an array, this routine is only available in Fortran 90, and you must 2817 include petsc.h90 in your code. 2818 You must also call DMPlexRestoreCone() after you finish using the returned array. 2819 DMPlexRestoreCone() is not needed/available in C. 2820 2821 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2822 @*/ 2823 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2824 { 2825 DM_Plex *mesh = (DM_Plex *)dm->data; 2826 PetscInt off; 2827 2828 PetscFunctionBegin; 2829 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2830 PetscValidPointer(cone, 3); 2831 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2832 *cone = &mesh->cones[off]; 2833 PetscFunctionReturn(0); 2834 } 2835 2836 /*@C 2837 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2838 2839 Not collective 2840 2841 Input Parameters: 2842 + dm - The DMPlex 2843 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2844 2845 Output Parameters: 2846 + pConesSection - PetscSection describing the layout of pCones 2847 - pCones - An array of points which are on the in-edges for the point set p 2848 2849 Level: intermediate 2850 2851 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2852 @*/ 2853 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2854 { 2855 PetscSection cs, newcs; 2856 PetscInt *cones; 2857 PetscInt *newarr = NULL; 2858 PetscInt n; 2859 2860 PetscFunctionBegin; 2861 PetscCall(DMPlexGetCones(dm, &cones)); 2862 PetscCall(DMPlexGetConeSection(dm, &cs)); 2863 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2864 if (pConesSection) *pConesSection = newcs; 2865 if (pCones) { 2866 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2867 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2868 } 2869 PetscFunctionReturn(0); 2870 } 2871 2872 /*@ 2873 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2874 2875 Not collective 2876 2877 Input Parameters: 2878 + dm - The DMPlex 2879 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2880 2881 Output Parameter: 2882 . expandedPoints - An array of vertices recursively expanded from input points 2883 2884 Level: advanced 2885 2886 Notes: 2887 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2888 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2889 2890 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2891 @*/ 2892 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2893 { 2894 IS *expandedPointsAll; 2895 PetscInt depth; 2896 2897 PetscFunctionBegin; 2898 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2899 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2900 PetscValidPointer(expandedPoints, 3); 2901 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2902 *expandedPoints = expandedPointsAll[0]; 2903 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2904 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2905 PetscFunctionReturn(0); 2906 } 2907 2908 /*@ 2909 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). 2910 2911 Not collective 2912 2913 Input Parameters: 2914 + dm - The DMPlex 2915 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2916 2917 Output Parameters: 2918 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2919 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2920 - sections - (optional) An array of sections which describe mappings from points to their cone points 2921 2922 Level: advanced 2923 2924 Notes: 2925 Like DMPlexGetConeTuple() but recursive. 2926 2927 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. 2928 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2929 2930 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: 2931 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2932 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2933 2934 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2935 @*/ 2936 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2937 { 2938 const PetscInt *arr0 = NULL, *cone = NULL; 2939 PetscInt *arr = NULL, *newarr = NULL; 2940 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2941 IS *expandedPoints_; 2942 PetscSection *sections_; 2943 2944 PetscFunctionBegin; 2945 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2946 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2947 if (depth) PetscValidIntPointer(depth, 3); 2948 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2949 if (sections) PetscValidPointer(sections, 5); 2950 PetscCall(ISGetLocalSize(points, &n)); 2951 PetscCall(ISGetIndices(points, &arr0)); 2952 PetscCall(DMPlexGetDepth(dm, &depth_)); 2953 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2954 PetscCall(PetscCalloc1(depth_, §ions_)); 2955 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2956 for (d = depth_ - 1; d >= 0; d--) { 2957 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2958 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2959 for (i = 0; i < n; i++) { 2960 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2961 if (arr[i] >= start && arr[i] < end) { 2962 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2963 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2964 } else { 2965 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2966 } 2967 } 2968 PetscCall(PetscSectionSetUp(sections_[d])); 2969 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2970 PetscCall(PetscMalloc1(newn, &newarr)); 2971 for (i = 0; i < n; i++) { 2972 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2973 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2974 if (cn > 1) { 2975 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2976 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2977 } else { 2978 newarr[co] = arr[i]; 2979 } 2980 } 2981 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2982 arr = newarr; 2983 n = newn; 2984 } 2985 PetscCall(ISRestoreIndices(points, &arr0)); 2986 *depth = depth_; 2987 if (expandedPoints) *expandedPoints = expandedPoints_; 2988 else { 2989 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2990 PetscCall(PetscFree(expandedPoints_)); 2991 } 2992 if (sections) *sections = sections_; 2993 else { 2994 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2995 PetscCall(PetscFree(sections_)); 2996 } 2997 PetscFunctionReturn(0); 2998 } 2999 3000 /*@ 3001 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 3002 3003 Not collective 3004 3005 Input Parameters: 3006 + dm - The DMPlex 3007 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 3008 3009 Output Parameters: 3010 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 3011 . expandedPoints - (optional) An array of recursively expanded cones 3012 - sections - (optional) An array of sections which describe mappings from points to their cone points 3013 3014 Level: advanced 3015 3016 Notes: 3017 See DMPlexGetConeRecursive() for details. 3018 3019 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 3020 @*/ 3021 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 3022 { 3023 PetscInt d, depth_; 3024 3025 PetscFunctionBegin; 3026 PetscCall(DMPlexGetDepth(dm, &depth_)); 3027 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 3028 if (depth) *depth = 0; 3029 if (expandedPoints) { 3030 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 3031 PetscCall(PetscFree(*expandedPoints)); 3032 } 3033 if (sections) { 3034 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 3035 PetscCall(PetscFree(*sections)); 3036 } 3037 PetscFunctionReturn(0); 3038 } 3039 3040 /*@ 3041 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 3042 3043 Not collective 3044 3045 Input Parameters: 3046 + mesh - The DMPlex 3047 . p - The point, which must lie in the chart set with DMPlexSetChart() 3048 - cone - An array of points which are on the in-edges for point p 3049 3050 Output Parameter: 3051 3052 Note: 3053 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3054 3055 Level: beginner 3056 3057 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 3058 @*/ 3059 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 3060 { 3061 DM_Plex *mesh = (DM_Plex *)dm->data; 3062 PetscInt pStart, pEnd; 3063 PetscInt dof, off, c; 3064 3065 PetscFunctionBegin; 3066 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3067 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3068 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3069 if (dof) PetscValidIntPointer(cone, 3); 3070 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3071 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); 3072 for (c = 0; c < dof; ++c) { 3073 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); 3074 mesh->cones[off + c] = cone[c]; 3075 } 3076 PetscFunctionReturn(0); 3077 } 3078 3079 /*@C 3080 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3081 3082 Not collective 3083 3084 Input Parameters: 3085 + mesh - The DMPlex 3086 - p - The point, which must lie in the chart set with DMPlexSetChart() 3087 3088 Output Parameter: 3089 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3090 integer giving the prescription for cone traversal. 3091 3092 Level: beginner 3093 3094 Notes: 3095 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3096 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3097 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3098 with the identity. 3099 3100 Fortran Notes: 3101 Since it returns an array, this routine is only available in Fortran 90, and you must 3102 include petsc.h90 in your code. 3103 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3104 DMPlexRestoreConeOrientation() is not needed/available in C. 3105 3106 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3107 @*/ 3108 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3109 { 3110 DM_Plex *mesh = (DM_Plex *)dm->data; 3111 PetscInt off; 3112 3113 PetscFunctionBegin; 3114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3115 if (PetscDefined(USE_DEBUG)) { 3116 PetscInt dof; 3117 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3118 if (dof) PetscValidPointer(coneOrientation, 3); 3119 } 3120 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3121 3122 *coneOrientation = &mesh->coneOrientations[off]; 3123 PetscFunctionReturn(0); 3124 } 3125 3126 /*@ 3127 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3128 3129 Not collective 3130 3131 Input Parameters: 3132 + mesh - The DMPlex 3133 . p - The point, which must lie in the chart set with DMPlexSetChart() 3134 - coneOrientation - An array of orientations 3135 Output Parameter: 3136 3137 Notes: 3138 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3139 3140 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3141 3142 Level: beginner 3143 3144 .seealso: `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: `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 Notes: 3216 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3217 3218 .seealso: `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 /*@ 3238 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3239 3240 Not collective 3241 3242 Input Parameters: 3243 + mesh - The DMPlex 3244 - p - The point, which must lie in the chart set with DMPlexSetChart() 3245 3246 Output Parameter: 3247 . size - The support size for point p 3248 3249 Level: beginner 3250 3251 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3252 @*/ 3253 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3254 { 3255 DM_Plex *mesh = (DM_Plex *)dm->data; 3256 3257 PetscFunctionBegin; 3258 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3259 PetscValidIntPointer(size, 3); 3260 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3261 PetscFunctionReturn(0); 3262 } 3263 3264 /*@ 3265 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3266 3267 Not collective 3268 3269 Input Parameters: 3270 + mesh - The DMPlex 3271 . p - The point, which must lie in the chart set with DMPlexSetChart() 3272 - size - The support size for point p 3273 3274 Output Parameter: 3275 3276 Note: 3277 This should be called after DMPlexSetChart(). 3278 3279 Level: beginner 3280 3281 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3282 @*/ 3283 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3284 { 3285 DM_Plex *mesh = (DM_Plex *)dm->data; 3286 3287 PetscFunctionBegin; 3288 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3289 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3290 PetscFunctionReturn(0); 3291 } 3292 3293 /*@C 3294 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3295 3296 Not collective 3297 3298 Input Parameters: 3299 + mesh - The DMPlex 3300 - p - The point, which must lie in the chart set with DMPlexSetChart() 3301 3302 Output Parameter: 3303 . support - An array of points which are on the out-edges for point p 3304 3305 Level: beginner 3306 3307 Fortran Notes: 3308 Since it returns an array, this routine is only available in Fortran 90, and you must 3309 include petsc.h90 in your code. 3310 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3311 DMPlexRestoreSupport() is not needed/available in C. 3312 3313 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3314 @*/ 3315 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3316 { 3317 DM_Plex *mesh = (DM_Plex *)dm->data; 3318 PetscInt off; 3319 3320 PetscFunctionBegin; 3321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3322 PetscValidPointer(support, 3); 3323 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3324 *support = &mesh->supports[off]; 3325 PetscFunctionReturn(0); 3326 } 3327 3328 /*@ 3329 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3330 3331 Not collective 3332 3333 Input Parameters: 3334 + mesh - The DMPlex 3335 . p - The point, which must lie in the chart set with DMPlexSetChart() 3336 - support - An array of points which are on the out-edges for point p 3337 3338 Output Parameter: 3339 3340 Note: 3341 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3342 3343 Level: beginner 3344 3345 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3346 @*/ 3347 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3348 { 3349 DM_Plex *mesh = (DM_Plex *)dm->data; 3350 PetscInt pStart, pEnd; 3351 PetscInt dof, off, c; 3352 3353 PetscFunctionBegin; 3354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3355 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3356 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3357 if (dof) PetscValidIntPointer(support, 3); 3358 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3359 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); 3360 for (c = 0; c < dof; ++c) { 3361 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); 3362 mesh->supports[off + c] = support[c]; 3363 } 3364 PetscFunctionReturn(0); 3365 } 3366 3367 /*@ 3368 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3369 3370 Not collective 3371 3372 Input Parameters: 3373 + mesh - The DMPlex 3374 . p - The point, which must lie in the chart set with DMPlexSetChart() 3375 . supportPos - The local index in the cone where the point should be put 3376 - supportPoint - The mesh point to insert 3377 3378 Level: beginner 3379 3380 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3381 @*/ 3382 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3383 { 3384 DM_Plex *mesh = (DM_Plex *)dm->data; 3385 PetscInt pStart, pEnd; 3386 PetscInt dof, off; 3387 3388 PetscFunctionBegin; 3389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3390 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3391 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3392 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3393 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); 3394 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); 3395 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); 3396 mesh->supports[off + supportPos] = supportPoint; 3397 PetscFunctionReturn(0); 3398 } 3399 3400 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3401 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3402 { 3403 switch (ct) { 3404 case DM_POLYTOPE_SEGMENT: 3405 if (o == -1) return -2; 3406 break; 3407 case DM_POLYTOPE_TRIANGLE: 3408 if (o == -3) return -1; 3409 if (o == -2) return -3; 3410 if (o == -1) return -2; 3411 break; 3412 case DM_POLYTOPE_QUADRILATERAL: 3413 if (o == -4) return -2; 3414 if (o == -3) return -1; 3415 if (o == -2) return -4; 3416 if (o == -1) return -3; 3417 break; 3418 default: 3419 return o; 3420 } 3421 return o; 3422 } 3423 3424 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3425 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3426 { 3427 switch (ct) { 3428 case DM_POLYTOPE_SEGMENT: 3429 if ((o == -2) || (o == 1)) return -1; 3430 if (o == -1) return 0; 3431 break; 3432 case DM_POLYTOPE_TRIANGLE: 3433 if (o == -3) return -2; 3434 if (o == -2) return -1; 3435 if (o == -1) return -3; 3436 break; 3437 case DM_POLYTOPE_QUADRILATERAL: 3438 if (o == -4) return -2; 3439 if (o == -3) return -1; 3440 if (o == -2) return -4; 3441 if (o == -1) return -3; 3442 break; 3443 default: 3444 return o; 3445 } 3446 return o; 3447 } 3448 3449 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3450 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3451 { 3452 PetscInt pStart, pEnd, p; 3453 3454 PetscFunctionBegin; 3455 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3456 for (p = pStart; p < pEnd; ++p) { 3457 const PetscInt *cone, *ornt; 3458 PetscInt coneSize, c; 3459 3460 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3461 PetscCall(DMPlexGetCone(dm, p, &cone)); 3462 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3463 for (c = 0; c < coneSize; ++c) { 3464 DMPolytopeType ct; 3465 const PetscInt o = ornt[c]; 3466 3467 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3468 switch (ct) { 3469 case DM_POLYTOPE_SEGMENT: 3470 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3471 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3472 break; 3473 case DM_POLYTOPE_TRIANGLE: 3474 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3475 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3476 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3477 break; 3478 case DM_POLYTOPE_QUADRILATERAL: 3479 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3480 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3481 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3482 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3483 break; 3484 default: 3485 break; 3486 } 3487 } 3488 } 3489 PetscFunctionReturn(0); 3490 } 3491 3492 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3493 { 3494 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3495 PetscInt *closure; 3496 const PetscInt *tmp = NULL, *tmpO = NULL; 3497 PetscInt off = 0, tmpSize, t; 3498 3499 PetscFunctionBeginHot; 3500 if (ornt) { 3501 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3502 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3503 } 3504 if (*points) { 3505 closure = *points; 3506 } else { 3507 PetscInt maxConeSize, maxSupportSize; 3508 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3509 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3510 } 3511 if (useCone) { 3512 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3513 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3514 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3515 } else { 3516 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3517 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3518 } 3519 if (ct == DM_POLYTOPE_UNKNOWN) { 3520 closure[off++] = p; 3521 closure[off++] = 0; 3522 for (t = 0; t < tmpSize; ++t) { 3523 closure[off++] = tmp[t]; 3524 closure[off++] = tmpO ? tmpO[t] : 0; 3525 } 3526 } else { 3527 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3528 3529 /* We assume that cells with a valid type have faces with a valid type */ 3530 closure[off++] = p; 3531 closure[off++] = ornt; 3532 for (t = 0; t < tmpSize; ++t) { 3533 DMPolytopeType ft; 3534 3535 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3536 closure[off++] = tmp[arr[t]]; 3537 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3538 } 3539 } 3540 if (numPoints) *numPoints = tmpSize + 1; 3541 if (points) *points = closure; 3542 PetscFunctionReturn(0); 3543 } 3544 3545 /* We need a special tensor version because we want to allow duplicate points in the endcaps for hybrid cells */ 3546 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3547 { 3548 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3549 const PetscInt *cone, *ornt; 3550 PetscInt *pts, *closure = NULL; 3551 DMPolytopeType ft; 3552 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3553 PetscInt dim, coneSize, c, d, clSize, cl; 3554 3555 PetscFunctionBeginHot; 3556 PetscCall(DMGetDimension(dm, &dim)); 3557 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3558 PetscCall(DMPlexGetCone(dm, point, &cone)); 3559 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3560 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3561 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3562 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3563 maxSize = PetscMax(coneSeries, supportSeries); 3564 if (*points) { 3565 pts = *points; 3566 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3567 c = 0; 3568 pts[c++] = point; 3569 pts[c++] = o; 3570 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3571 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3572 for (cl = 0; cl < clSize * 2; cl += 2) { 3573 pts[c++] = closure[cl]; 3574 pts[c++] = closure[cl + 1]; 3575 } 3576 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3577 for (cl = 0; cl < clSize * 2; cl += 2) { 3578 pts[c++] = closure[cl]; 3579 pts[c++] = closure[cl + 1]; 3580 } 3581 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3582 for (d = 2; d < coneSize; ++d) { 3583 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3584 pts[c++] = cone[arr[d * 2 + 0]]; 3585 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3586 } 3587 if (dim >= 3) { 3588 for (d = 2; d < coneSize; ++d) { 3589 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3590 const PetscInt *fcone, *fornt; 3591 PetscInt fconeSize, fc, i; 3592 3593 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3594 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3595 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3596 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3597 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3598 for (fc = 0; fc < fconeSize; ++fc) { 3599 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3600 const PetscInt co = farr[fc * 2 + 1]; 3601 3602 for (i = 0; i < c; i += 2) 3603 if (pts[i] == cp) break; 3604 if (i == c) { 3605 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3606 pts[c++] = cp; 3607 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3608 } 3609 } 3610 } 3611 } 3612 *numPoints = c / 2; 3613 *points = pts; 3614 PetscFunctionReturn(0); 3615 } 3616 3617 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3618 { 3619 DMPolytopeType ct; 3620 PetscInt *closure, *fifo; 3621 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3622 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3623 PetscInt depth, maxSize; 3624 3625 PetscFunctionBeginHot; 3626 PetscCall(DMPlexGetDepth(dm, &depth)); 3627 if (depth == 1) { 3628 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3629 PetscFunctionReturn(0); 3630 } 3631 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3632 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3633 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3634 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3635 PetscFunctionReturn(0); 3636 } 3637 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3638 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3639 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3640 maxSize = PetscMax(coneSeries, supportSeries); 3641 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3642 if (*points) { 3643 closure = *points; 3644 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3645 closure[closureSize++] = p; 3646 closure[closureSize++] = ornt; 3647 fifo[fifoSize++] = p; 3648 fifo[fifoSize++] = ornt; 3649 fifo[fifoSize++] = ct; 3650 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3651 while (fifoSize - fifoStart) { 3652 const PetscInt q = fifo[fifoStart++]; 3653 const PetscInt o = fifo[fifoStart++]; 3654 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3655 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3656 const PetscInt *tmp, *tmpO; 3657 PetscInt tmpSize, t; 3658 3659 if (PetscDefined(USE_DEBUG)) { 3660 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3661 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); 3662 } 3663 if (useCone) { 3664 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3665 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3666 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3667 } else { 3668 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3669 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3670 tmpO = NULL; 3671 } 3672 for (t = 0; t < tmpSize; ++t) { 3673 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3674 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3675 const PetscInt cp = tmp[ip]; 3676 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3677 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3678 PetscInt c; 3679 3680 /* Check for duplicate */ 3681 for (c = 0; c < closureSize; c += 2) { 3682 if (closure[c] == cp) break; 3683 } 3684 if (c == closureSize) { 3685 closure[closureSize++] = cp; 3686 closure[closureSize++] = co; 3687 fifo[fifoSize++] = cp; 3688 fifo[fifoSize++] = co; 3689 fifo[fifoSize++] = ct; 3690 } 3691 } 3692 } 3693 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3694 if (numPoints) *numPoints = closureSize / 2; 3695 if (points) *points = closure; 3696 PetscFunctionReturn(0); 3697 } 3698 3699 /*@C 3700 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3701 3702 Not collective 3703 3704 Input Parameters: 3705 + dm - The DMPlex 3706 . p - The mesh point 3707 - useCone - PETSC_TRUE for the closure, otherwise return the star 3708 3709 Input/Output Parameter: 3710 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3711 if NULL on input, internal storage will be returned, otherwise the provided array is used 3712 3713 Output Parameter: 3714 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3715 3716 Note: 3717 If using internal storage (points is NULL on input), each call overwrites the last output. 3718 3719 Fortran Note: 3720 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3721 3722 Level: beginner 3723 3724 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3725 @*/ 3726 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3727 { 3728 PetscFunctionBeginHot; 3729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3730 if (numPoints) PetscValidIntPointer(numPoints, 4); 3731 if (points) PetscValidPointer(points, 5); 3732 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3733 PetscFunctionReturn(0); 3734 } 3735 3736 /*@C 3737 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3738 3739 Not collective 3740 3741 Input Parameters: 3742 + dm - The DMPlex 3743 . p - The mesh point 3744 . useCone - PETSC_TRUE for the closure, otherwise return the star 3745 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3746 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3747 3748 Note: 3749 If not using internal storage (points is not NULL on input), this call is unnecessary 3750 3751 Level: beginner 3752 3753 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3754 @*/ 3755 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3756 { 3757 PetscFunctionBeginHot; 3758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3759 if (numPoints) *numPoints = 0; 3760 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3761 PetscFunctionReturn(0); 3762 } 3763 3764 /*@ 3765 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3766 3767 Not collective 3768 3769 Input Parameter: 3770 . mesh - The DMPlex 3771 3772 Output Parameters: 3773 + maxConeSize - The maximum number of in-edges 3774 - maxSupportSize - The maximum number of out-edges 3775 3776 Level: beginner 3777 3778 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3779 @*/ 3780 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3781 { 3782 DM_Plex *mesh = (DM_Plex *)dm->data; 3783 3784 PetscFunctionBegin; 3785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3786 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3787 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3788 PetscFunctionReturn(0); 3789 } 3790 3791 PetscErrorCode DMSetUp_Plex(DM dm) 3792 { 3793 DM_Plex *mesh = (DM_Plex *)dm->data; 3794 PetscInt size, maxSupportSize; 3795 3796 PetscFunctionBegin; 3797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3798 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3799 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3800 PetscCall(PetscMalloc1(size, &mesh->cones)); 3801 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3802 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3803 if (maxSupportSize) { 3804 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3805 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3806 PetscCall(PetscMalloc1(size, &mesh->supports)); 3807 } 3808 PetscFunctionReturn(0); 3809 } 3810 3811 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3812 { 3813 PetscFunctionBegin; 3814 if (subdm) PetscCall(DMClone(dm, subdm)); 3815 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3816 if (subdm) (*subdm)->useNatural = dm->useNatural; 3817 if (dm->useNatural && dm->sfMigration) { 3818 PetscSF sfNatural; 3819 3820 (*subdm)->sfMigration = dm->sfMigration; 3821 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3822 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3823 (*subdm)->sfNatural = sfNatural; 3824 } 3825 PetscFunctionReturn(0); 3826 } 3827 3828 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3829 { 3830 PetscInt i = 0; 3831 3832 PetscFunctionBegin; 3833 PetscCall(DMClone(dms[0], superdm)); 3834 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3835 (*superdm)->useNatural = PETSC_FALSE; 3836 for (i = 0; i < len; i++) { 3837 if (dms[i]->useNatural && dms[i]->sfMigration) { 3838 PetscSF sfNatural; 3839 3840 (*superdm)->sfMigration = dms[i]->sfMigration; 3841 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3842 (*superdm)->useNatural = PETSC_TRUE; 3843 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3844 (*superdm)->sfNatural = sfNatural; 3845 break; 3846 } 3847 } 3848 PetscFunctionReturn(0); 3849 } 3850 3851 /*@ 3852 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3853 3854 Not collective 3855 3856 Input Parameter: 3857 . mesh - The DMPlex 3858 3859 Output Parameter: 3860 3861 Note: 3862 This should be called after all calls to DMPlexSetCone() 3863 3864 Level: beginner 3865 3866 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3867 @*/ 3868 PetscErrorCode DMPlexSymmetrize(DM dm) 3869 { 3870 DM_Plex *mesh = (DM_Plex *)dm->data; 3871 PetscInt *offsets; 3872 PetscInt supportSize; 3873 PetscInt pStart, pEnd, p; 3874 3875 PetscFunctionBegin; 3876 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3877 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3878 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3879 /* Calculate support sizes */ 3880 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3881 for (p = pStart; p < pEnd; ++p) { 3882 PetscInt dof, off, c; 3883 3884 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3885 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3886 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3887 } 3888 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3889 /* Calculate supports */ 3890 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3891 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3892 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3893 for (p = pStart; p < pEnd; ++p) { 3894 PetscInt dof, off, c; 3895 3896 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3897 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3898 for (c = off; c < off + dof; ++c) { 3899 const PetscInt q = mesh->cones[c]; 3900 PetscInt offS; 3901 3902 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3903 3904 mesh->supports[offS + offsets[q]] = p; 3905 ++offsets[q]; 3906 } 3907 } 3908 PetscCall(PetscFree(offsets)); 3909 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3910 PetscFunctionReturn(0); 3911 } 3912 3913 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3914 { 3915 IS stratumIS; 3916 3917 PetscFunctionBegin; 3918 if (pStart >= pEnd) PetscFunctionReturn(0); 3919 if (PetscDefined(USE_DEBUG)) { 3920 PetscInt qStart, qEnd, numLevels, level; 3921 PetscBool overlap = PETSC_FALSE; 3922 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3923 for (level = 0; level < numLevels; level++) { 3924 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3925 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 3926 overlap = PETSC_TRUE; 3927 break; 3928 } 3929 } 3930 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); 3931 } 3932 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 3933 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3934 PetscCall(ISDestroy(&stratumIS)); 3935 PetscFunctionReturn(0); 3936 } 3937 3938 /*@ 3939 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3940 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3941 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3942 the DAG. 3943 3944 Collective on dm 3945 3946 Input Parameter: 3947 . mesh - The DMPlex 3948 3949 Output Parameter: 3950 3951 Notes: 3952 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3953 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3954 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3955 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3956 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3957 3958 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3959 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3960 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 3961 to interpolate only that one (e0), so that 3962 $ cone(c0) = {e0, v2} 3963 $ cone(e0) = {v0, v1} 3964 If DMPlexStratify() is run on this mesh, it will give depths 3965 $ depth 0 = {v0, v1, v2} 3966 $ depth 1 = {e0, c0} 3967 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3968 3969 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3970 3971 Level: beginner 3972 3973 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3974 @*/ 3975 PetscErrorCode DMPlexStratify(DM dm) 3976 { 3977 DM_Plex *mesh = (DM_Plex *)dm->data; 3978 DMLabel label; 3979 PetscInt pStart, pEnd, p; 3980 PetscInt numRoots = 0, numLeaves = 0; 3981 3982 PetscFunctionBegin; 3983 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3984 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 3985 3986 /* Create depth label */ 3987 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3988 PetscCall(DMCreateLabel(dm, "depth")); 3989 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3990 3991 { 3992 /* Initialize roots and count leaves */ 3993 PetscInt sMin = PETSC_MAX_INT; 3994 PetscInt sMax = PETSC_MIN_INT; 3995 PetscInt coneSize, supportSize; 3996 3997 for (p = pStart; p < pEnd; ++p) { 3998 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3999 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4000 if (!coneSize && supportSize) { 4001 sMin = PetscMin(p, sMin); 4002 sMax = PetscMax(p, sMax); 4003 ++numRoots; 4004 } else if (!supportSize && coneSize) { 4005 ++numLeaves; 4006 } else if (!supportSize && !coneSize) { 4007 /* Isolated points */ 4008 sMin = PetscMin(p, sMin); 4009 sMax = PetscMax(p, sMax); 4010 } 4011 } 4012 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 4013 } 4014 4015 if (numRoots + numLeaves == (pEnd - pStart)) { 4016 PetscInt sMin = PETSC_MAX_INT; 4017 PetscInt sMax = PETSC_MIN_INT; 4018 PetscInt coneSize, supportSize; 4019 4020 for (p = pStart; p < pEnd; ++p) { 4021 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4022 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 4023 if (!supportSize && coneSize) { 4024 sMin = PetscMin(p, sMin); 4025 sMax = PetscMax(p, sMax); 4026 } 4027 } 4028 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 4029 } else { 4030 PetscInt level = 0; 4031 PetscInt qStart, qEnd, q; 4032 4033 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4034 while (qEnd > qStart) { 4035 PetscInt sMin = PETSC_MAX_INT; 4036 PetscInt sMax = PETSC_MIN_INT; 4037 4038 for (q = qStart; q < qEnd; ++q) { 4039 const PetscInt *support; 4040 PetscInt supportSize, s; 4041 4042 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 4043 PetscCall(DMPlexGetSupport(dm, q, &support)); 4044 for (s = 0; s < supportSize; ++s) { 4045 sMin = PetscMin(support[s], sMin); 4046 sMax = PetscMax(support[s], sMax); 4047 } 4048 } 4049 PetscCall(DMLabelGetNumValues(label, &level)); 4050 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 4051 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 4052 } 4053 } 4054 { /* just in case there is an empty process */ 4055 PetscInt numValues, maxValues = 0, v; 4056 4057 PetscCall(DMLabelGetNumValues(label, &numValues)); 4058 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 4059 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 4060 } 4061 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 4062 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 4063 PetscFunctionReturn(0); 4064 } 4065 4066 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4067 { 4068 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4069 PetscInt dim, depth, pheight, coneSize; 4070 4071 PetscFunctionBeginHot; 4072 PetscCall(DMGetDimension(dm, &dim)); 4073 PetscCall(DMPlexGetDepth(dm, &depth)); 4074 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4075 pheight = depth - pdepth; 4076 if (depth <= 1) { 4077 switch (pdepth) { 4078 case 0: 4079 ct = DM_POLYTOPE_POINT; 4080 break; 4081 case 1: 4082 switch (coneSize) { 4083 case 2: 4084 ct = DM_POLYTOPE_SEGMENT; 4085 break; 4086 case 3: 4087 ct = DM_POLYTOPE_TRIANGLE; 4088 break; 4089 case 4: 4090 switch (dim) { 4091 case 2: 4092 ct = DM_POLYTOPE_QUADRILATERAL; 4093 break; 4094 case 3: 4095 ct = DM_POLYTOPE_TETRAHEDRON; 4096 break; 4097 default: 4098 break; 4099 } 4100 break; 4101 case 5: 4102 ct = DM_POLYTOPE_PYRAMID; 4103 break; 4104 case 6: 4105 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4106 break; 4107 case 8: 4108 ct = DM_POLYTOPE_HEXAHEDRON; 4109 break; 4110 default: 4111 break; 4112 } 4113 } 4114 } else { 4115 if (pdepth == 0) { 4116 ct = DM_POLYTOPE_POINT; 4117 } else if (pheight == 0) { 4118 switch (dim) { 4119 case 1: 4120 switch (coneSize) { 4121 case 2: 4122 ct = DM_POLYTOPE_SEGMENT; 4123 break; 4124 default: 4125 break; 4126 } 4127 break; 4128 case 2: 4129 switch (coneSize) { 4130 case 3: 4131 ct = DM_POLYTOPE_TRIANGLE; 4132 break; 4133 case 4: 4134 ct = DM_POLYTOPE_QUADRILATERAL; 4135 break; 4136 default: 4137 break; 4138 } 4139 break; 4140 case 3: 4141 switch (coneSize) { 4142 case 4: 4143 ct = DM_POLYTOPE_TETRAHEDRON; 4144 break; 4145 case 5: { 4146 const PetscInt *cone; 4147 PetscInt faceConeSize; 4148 4149 PetscCall(DMPlexGetCone(dm, p, &cone)); 4150 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4151 switch (faceConeSize) { 4152 case 3: 4153 ct = DM_POLYTOPE_TRI_PRISM_TENSOR; 4154 break; 4155 case 4: 4156 ct = DM_POLYTOPE_PYRAMID; 4157 break; 4158 } 4159 } break; 4160 case 6: 4161 ct = DM_POLYTOPE_HEXAHEDRON; 4162 break; 4163 default: 4164 break; 4165 } 4166 break; 4167 default: 4168 break; 4169 } 4170 } else if (pheight > 0) { 4171 switch (coneSize) { 4172 case 2: 4173 ct = DM_POLYTOPE_SEGMENT; 4174 break; 4175 case 3: 4176 ct = DM_POLYTOPE_TRIANGLE; 4177 break; 4178 case 4: 4179 ct = DM_POLYTOPE_QUADRILATERAL; 4180 break; 4181 default: 4182 break; 4183 } 4184 } 4185 } 4186 *pt = ct; 4187 PetscFunctionReturn(0); 4188 } 4189 4190 /*@ 4191 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4192 4193 Collective on dm 4194 4195 Input Parameter: 4196 . mesh - The DMPlex 4197 4198 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4199 4200 Level: developer 4201 4202 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4203 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4204 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4205 4206 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4207 @*/ 4208 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4209 { 4210 DM_Plex *mesh; 4211 DMLabel ctLabel; 4212 PetscInt pStart, pEnd, p; 4213 4214 PetscFunctionBegin; 4215 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4216 mesh = (DM_Plex *)dm->data; 4217 PetscCall(DMCreateLabel(dm, "celltype")); 4218 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4219 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4220 for (p = pStart; p < pEnd; ++p) { 4221 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4222 PetscInt pdepth; 4223 4224 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4225 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4226 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4227 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4228 } 4229 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4230 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4231 PetscFunctionReturn(0); 4232 } 4233 4234 /*@C 4235 DMPlexGetJoin - Get an array for the join of the set of points 4236 4237 Not Collective 4238 4239 Input Parameters: 4240 + dm - The DMPlex object 4241 . numPoints - The number of input points for the join 4242 - points - The input points 4243 4244 Output Parameters: 4245 + numCoveredPoints - The number of points in the join 4246 - coveredPoints - The points in the join 4247 4248 Level: intermediate 4249 4250 Note: Currently, this is restricted to a single level join 4251 4252 Fortran Notes: 4253 Since it returns an array, this routine is only available in Fortran 90, and you must 4254 include petsc.h90 in your code. 4255 4256 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4257 4258 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4259 @*/ 4260 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4261 { 4262 DM_Plex *mesh = (DM_Plex *)dm->data; 4263 PetscInt *join[2]; 4264 PetscInt joinSize, i = 0; 4265 PetscInt dof, off, p, c, m; 4266 PetscInt maxSupportSize; 4267 4268 PetscFunctionBegin; 4269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4270 PetscValidIntPointer(points, 3); 4271 PetscValidIntPointer(numCoveredPoints, 4); 4272 PetscValidPointer(coveredPoints, 5); 4273 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4274 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4275 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4276 /* Copy in support of first point */ 4277 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4278 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4279 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4280 /* Check each successive support */ 4281 for (p = 1; p < numPoints; ++p) { 4282 PetscInt newJoinSize = 0; 4283 4284 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4285 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4286 for (c = 0; c < dof; ++c) { 4287 const PetscInt point = mesh->supports[off + c]; 4288 4289 for (m = 0; m < joinSize; ++m) { 4290 if (point == join[i][m]) { 4291 join[1 - i][newJoinSize++] = point; 4292 break; 4293 } 4294 } 4295 } 4296 joinSize = newJoinSize; 4297 i = 1 - i; 4298 } 4299 *numCoveredPoints = joinSize; 4300 *coveredPoints = join[i]; 4301 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4302 PetscFunctionReturn(0); 4303 } 4304 4305 /*@C 4306 DMPlexRestoreJoin - Restore an array for the join of the set of points 4307 4308 Not Collective 4309 4310 Input Parameters: 4311 + dm - The DMPlex object 4312 . numPoints - The number of input points for the join 4313 - points - The input points 4314 4315 Output Parameters: 4316 + numCoveredPoints - The number of points in the join 4317 - coveredPoints - The points in the join 4318 4319 Fortran Notes: 4320 Since it returns an array, this routine is only available in Fortran 90, and you must 4321 include petsc.h90 in your code. 4322 4323 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4324 4325 Level: intermediate 4326 4327 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4328 @*/ 4329 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4330 { 4331 PetscFunctionBegin; 4332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4333 if (points) PetscValidIntPointer(points, 3); 4334 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4335 PetscValidPointer(coveredPoints, 5); 4336 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4337 if (numCoveredPoints) *numCoveredPoints = 0; 4338 PetscFunctionReturn(0); 4339 } 4340 4341 /*@C 4342 DMPlexGetFullJoin - Get an array for the join of the set of points 4343 4344 Not Collective 4345 4346 Input Parameters: 4347 + dm - The DMPlex object 4348 . numPoints - The number of input points for the join 4349 - points - The input points 4350 4351 Output Parameters: 4352 + numCoveredPoints - The number of points in the join 4353 - coveredPoints - The points in the join 4354 4355 Fortran Notes: 4356 Since it returns an array, this routine is only available in Fortran 90, and you must 4357 include petsc.h90 in your code. 4358 4359 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4360 4361 Level: intermediate 4362 4363 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4364 @*/ 4365 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4366 { 4367 PetscInt *offsets, **closures; 4368 PetscInt *join[2]; 4369 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4370 PetscInt p, d, c, m, ms; 4371 4372 PetscFunctionBegin; 4373 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4374 PetscValidIntPointer(points, 3); 4375 PetscValidIntPointer(numCoveredPoints, 4); 4376 PetscValidPointer(coveredPoints, 5); 4377 4378 PetscCall(DMPlexGetDepth(dm, &depth)); 4379 PetscCall(PetscCalloc1(numPoints, &closures)); 4380 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4381 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4382 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4383 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4384 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4385 4386 for (p = 0; p < numPoints; ++p) { 4387 PetscInt closureSize; 4388 4389 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4390 4391 offsets[p * (depth + 2) + 0] = 0; 4392 for (d = 0; d < depth + 1; ++d) { 4393 PetscInt pStart, pEnd, i; 4394 4395 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4396 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4397 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4398 offsets[p * (depth + 2) + d + 1] = i; 4399 break; 4400 } 4401 } 4402 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4403 } 4404 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); 4405 } 4406 for (d = 0; d < depth + 1; ++d) { 4407 PetscInt dof; 4408 4409 /* Copy in support of first point */ 4410 dof = offsets[d + 1] - offsets[d]; 4411 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4412 /* Check each successive cone */ 4413 for (p = 1; p < numPoints && joinSize; ++p) { 4414 PetscInt newJoinSize = 0; 4415 4416 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4417 for (c = 0; c < dof; ++c) { 4418 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4419 4420 for (m = 0; m < joinSize; ++m) { 4421 if (point == join[i][m]) { 4422 join[1 - i][newJoinSize++] = point; 4423 break; 4424 } 4425 } 4426 } 4427 joinSize = newJoinSize; 4428 i = 1 - i; 4429 } 4430 if (joinSize) break; 4431 } 4432 *numCoveredPoints = joinSize; 4433 *coveredPoints = join[i]; 4434 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4435 PetscCall(PetscFree(closures)); 4436 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4437 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4438 PetscFunctionReturn(0); 4439 } 4440 4441 /*@C 4442 DMPlexGetMeet - Get an array for the meet of the set of points 4443 4444 Not Collective 4445 4446 Input Parameters: 4447 + dm - The DMPlex object 4448 . numPoints - The number of input points for the meet 4449 - points - The input points 4450 4451 Output Parameters: 4452 + numCoveredPoints - The number of points in the meet 4453 - coveredPoints - The points in the meet 4454 4455 Level: intermediate 4456 4457 Note: Currently, this is restricted to a single level meet 4458 4459 Fortran Notes: 4460 Since it returns an array, this routine is only available in Fortran 90, and you must 4461 include petsc.h90 in your code. 4462 4463 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4464 4465 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4466 @*/ 4467 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4468 { 4469 DM_Plex *mesh = (DM_Plex *)dm->data; 4470 PetscInt *meet[2]; 4471 PetscInt meetSize, i = 0; 4472 PetscInt dof, off, p, c, m; 4473 PetscInt maxConeSize; 4474 4475 PetscFunctionBegin; 4476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4477 PetscValidIntPointer(points, 3); 4478 PetscValidIntPointer(numCoveringPoints, 4); 4479 PetscValidPointer(coveringPoints, 5); 4480 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4481 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4482 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4483 /* Copy in cone of first point */ 4484 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4485 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4486 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4487 /* Check each successive cone */ 4488 for (p = 1; p < numPoints; ++p) { 4489 PetscInt newMeetSize = 0; 4490 4491 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4492 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4493 for (c = 0; c < dof; ++c) { 4494 const PetscInt point = mesh->cones[off + c]; 4495 4496 for (m = 0; m < meetSize; ++m) { 4497 if (point == meet[i][m]) { 4498 meet[1 - i][newMeetSize++] = point; 4499 break; 4500 } 4501 } 4502 } 4503 meetSize = newMeetSize; 4504 i = 1 - i; 4505 } 4506 *numCoveringPoints = meetSize; 4507 *coveringPoints = meet[i]; 4508 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4509 PetscFunctionReturn(0); 4510 } 4511 4512 /*@C 4513 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4514 4515 Not Collective 4516 4517 Input Parameters: 4518 + dm - The DMPlex object 4519 . numPoints - The number of input points for the meet 4520 - points - The input points 4521 4522 Output Parameters: 4523 + numCoveredPoints - The number of points in the meet 4524 - coveredPoints - The points in the meet 4525 4526 Level: intermediate 4527 4528 Fortran Notes: 4529 Since it returns an array, this routine is only available in Fortran 90, and you must 4530 include petsc.h90 in your code. 4531 4532 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4533 4534 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4535 @*/ 4536 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4537 { 4538 PetscFunctionBegin; 4539 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4540 if (points) PetscValidIntPointer(points, 3); 4541 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4542 PetscValidPointer(coveredPoints, 5); 4543 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4544 if (numCoveredPoints) *numCoveredPoints = 0; 4545 PetscFunctionReturn(0); 4546 } 4547 4548 /*@C 4549 DMPlexGetFullMeet - Get an array for the meet of the set of points 4550 4551 Not Collective 4552 4553 Input Parameters: 4554 + dm - The DMPlex object 4555 . numPoints - The number of input points for the meet 4556 - points - The input points 4557 4558 Output Parameters: 4559 + numCoveredPoints - The number of points in the meet 4560 - coveredPoints - The points in the meet 4561 4562 Level: intermediate 4563 4564 Fortran Notes: 4565 Since it returns an array, this routine is only available in Fortran 90, and you must 4566 include petsc.h90 in your code. 4567 4568 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4569 4570 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4571 @*/ 4572 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4573 { 4574 PetscInt *offsets, **closures; 4575 PetscInt *meet[2]; 4576 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4577 PetscInt p, h, c, m, mc; 4578 4579 PetscFunctionBegin; 4580 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4581 PetscValidIntPointer(points, 3); 4582 PetscValidIntPointer(numCoveredPoints, 4); 4583 PetscValidPointer(coveredPoints, 5); 4584 4585 PetscCall(DMPlexGetDepth(dm, &height)); 4586 PetscCall(PetscMalloc1(numPoints, &closures)); 4587 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4588 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4589 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4590 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4591 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4592 4593 for (p = 0; p < numPoints; ++p) { 4594 PetscInt closureSize; 4595 4596 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4597 4598 offsets[p * (height + 2) + 0] = 0; 4599 for (h = 0; h < height + 1; ++h) { 4600 PetscInt pStart, pEnd, i; 4601 4602 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4603 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4604 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4605 offsets[p * (height + 2) + h + 1] = i; 4606 break; 4607 } 4608 } 4609 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4610 } 4611 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); 4612 } 4613 for (h = 0; h < height + 1; ++h) { 4614 PetscInt dof; 4615 4616 /* Copy in cone of first point */ 4617 dof = offsets[h + 1] - offsets[h]; 4618 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4619 /* Check each successive cone */ 4620 for (p = 1; p < numPoints && meetSize; ++p) { 4621 PetscInt newMeetSize = 0; 4622 4623 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4624 for (c = 0; c < dof; ++c) { 4625 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4626 4627 for (m = 0; m < meetSize; ++m) { 4628 if (point == meet[i][m]) { 4629 meet[1 - i][newMeetSize++] = point; 4630 break; 4631 } 4632 } 4633 } 4634 meetSize = newMeetSize; 4635 i = 1 - i; 4636 } 4637 if (meetSize) break; 4638 } 4639 *numCoveredPoints = meetSize; 4640 *coveredPoints = meet[i]; 4641 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4642 PetscCall(PetscFree(closures)); 4643 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4644 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4645 PetscFunctionReturn(0); 4646 } 4647 4648 /*@C 4649 DMPlexEqual - Determine if two DMs have the same topology 4650 4651 Not Collective 4652 4653 Input Parameters: 4654 + dmA - A DMPlex object 4655 - dmB - A DMPlex object 4656 4657 Output Parameters: 4658 . equal - PETSC_TRUE if the topologies are identical 4659 4660 Level: intermediate 4661 4662 Notes: 4663 We are not solving graph isomorphism, so we do not permutation. 4664 4665 .seealso: `DMPlexGetCone()` 4666 @*/ 4667 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4668 { 4669 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4670 4671 PetscFunctionBegin; 4672 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4673 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4674 PetscValidBoolPointer(equal, 3); 4675 4676 *equal = PETSC_FALSE; 4677 PetscCall(DMPlexGetDepth(dmA, &depth)); 4678 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4679 if (depth != depthB) PetscFunctionReturn(0); 4680 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4681 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4682 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4683 for (p = pStart; p < pEnd; ++p) { 4684 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4685 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4686 4687 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4688 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4689 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4690 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4691 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4692 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4693 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4694 for (c = 0; c < coneSize; ++c) { 4695 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4696 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4697 } 4698 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4699 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4700 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4701 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4702 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4703 for (s = 0; s < supportSize; ++s) { 4704 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4705 } 4706 } 4707 *equal = PETSC_TRUE; 4708 PetscFunctionReturn(0); 4709 } 4710 4711 /*@C 4712 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4713 4714 Not Collective 4715 4716 Input Parameters: 4717 + dm - The DMPlex 4718 . cellDim - The cell dimension 4719 - numCorners - The number of vertices on a cell 4720 4721 Output Parameters: 4722 . numFaceVertices - The number of vertices on a face 4723 4724 Level: developer 4725 4726 Notes: 4727 Of course this can only work for a restricted set of symmetric shapes 4728 4729 .seealso: `DMPlexGetCone()` 4730 @*/ 4731 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4732 { 4733 MPI_Comm comm; 4734 4735 PetscFunctionBegin; 4736 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4737 PetscValidIntPointer(numFaceVertices, 4); 4738 switch (cellDim) { 4739 case 0: 4740 *numFaceVertices = 0; 4741 break; 4742 case 1: 4743 *numFaceVertices = 1; 4744 break; 4745 case 2: 4746 switch (numCorners) { 4747 case 3: /* triangle */ 4748 *numFaceVertices = 2; /* Edge has 2 vertices */ 4749 break; 4750 case 4: /* quadrilateral */ 4751 *numFaceVertices = 2; /* Edge has 2 vertices */ 4752 break; 4753 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4754 *numFaceVertices = 3; /* Edge has 3 vertices */ 4755 break; 4756 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4757 *numFaceVertices = 3; /* Edge has 3 vertices */ 4758 break; 4759 default: 4760 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4761 } 4762 break; 4763 case 3: 4764 switch (numCorners) { 4765 case 4: /* tetradehdron */ 4766 *numFaceVertices = 3; /* Face has 3 vertices */ 4767 break; 4768 case 6: /* tet cohesive cells */ 4769 *numFaceVertices = 4; /* Face has 4 vertices */ 4770 break; 4771 case 8: /* hexahedron */ 4772 *numFaceVertices = 4; /* Face has 4 vertices */ 4773 break; 4774 case 9: /* tet cohesive Lagrange cells */ 4775 *numFaceVertices = 6; /* Face has 6 vertices */ 4776 break; 4777 case 10: /* quadratic tetrahedron */ 4778 *numFaceVertices = 6; /* Face has 6 vertices */ 4779 break; 4780 case 12: /* hex cohesive Lagrange cells */ 4781 *numFaceVertices = 6; /* Face has 6 vertices */ 4782 break; 4783 case 18: /* quadratic tet cohesive Lagrange cells */ 4784 *numFaceVertices = 6; /* Face has 6 vertices */ 4785 break; 4786 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4787 *numFaceVertices = 9; /* Face has 9 vertices */ 4788 break; 4789 default: 4790 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4791 } 4792 break; 4793 default: 4794 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4795 } 4796 PetscFunctionReturn(0); 4797 } 4798 4799 /*@ 4800 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4801 4802 Not Collective 4803 4804 Input Parameter: 4805 . dm - The DMPlex object 4806 4807 Output Parameter: 4808 . depthLabel - The DMLabel recording point depth 4809 4810 Level: developer 4811 4812 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4813 @*/ 4814 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4815 { 4816 PetscFunctionBegin; 4817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4818 PetscValidPointer(depthLabel, 2); 4819 *depthLabel = dm->depthLabel; 4820 PetscFunctionReturn(0); 4821 } 4822 4823 /*@ 4824 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4825 4826 Not Collective 4827 4828 Input Parameter: 4829 . dm - The DMPlex object 4830 4831 Output Parameter: 4832 . depth - The number of strata (breadth first levels) in the DAG 4833 4834 Level: developer 4835 4836 Notes: 4837 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4838 The point depth is described more in detail in DMPlexGetDepthStratum(). 4839 An empty mesh gives -1. 4840 4841 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4842 @*/ 4843 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4844 { 4845 DMLabel label; 4846 PetscInt d = 0; 4847 4848 PetscFunctionBegin; 4849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4850 PetscValidIntPointer(depth, 2); 4851 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4852 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4853 *depth = d - 1; 4854 PetscFunctionReturn(0); 4855 } 4856 4857 /*@ 4858 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4859 4860 Not Collective 4861 4862 Input Parameters: 4863 + dm - The DMPlex object 4864 - depth - The requested depth 4865 4866 Output Parameters: 4867 + start - The first point at this depth 4868 - end - One beyond the last point at this depth 4869 4870 Notes: 4871 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4872 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4873 higher dimension, e.g., "edges". 4874 4875 Level: developer 4876 4877 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4878 @*/ 4879 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4880 { 4881 DMLabel label; 4882 PetscInt pStart, pEnd; 4883 4884 PetscFunctionBegin; 4885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4886 if (start) { 4887 PetscValidIntPointer(start, 3); 4888 *start = 0; 4889 } 4890 if (end) { 4891 PetscValidIntPointer(end, 4); 4892 *end = 0; 4893 } 4894 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4895 if (pStart == pEnd) PetscFunctionReturn(0); 4896 if (depth < 0) { 4897 if (start) *start = pStart; 4898 if (end) *end = pEnd; 4899 PetscFunctionReturn(0); 4900 } 4901 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4902 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4903 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4904 PetscFunctionReturn(0); 4905 } 4906 4907 /*@ 4908 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4909 4910 Not Collective 4911 4912 Input Parameters: 4913 + dm - The DMPlex object 4914 - height - The requested height 4915 4916 Output Parameters: 4917 + start - The first point at this height 4918 - end - One beyond the last point at this height 4919 4920 Notes: 4921 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4922 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4923 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4924 4925 Level: developer 4926 4927 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4928 @*/ 4929 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4930 { 4931 DMLabel label; 4932 PetscInt depth, pStart, pEnd; 4933 4934 PetscFunctionBegin; 4935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4936 if (start) { 4937 PetscValidIntPointer(start, 3); 4938 *start = 0; 4939 } 4940 if (end) { 4941 PetscValidIntPointer(end, 4); 4942 *end = 0; 4943 } 4944 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4945 if (pStart == pEnd) PetscFunctionReturn(0); 4946 if (height < 0) { 4947 if (start) *start = pStart; 4948 if (end) *end = pEnd; 4949 PetscFunctionReturn(0); 4950 } 4951 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4952 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4953 PetscCall(DMLabelGetNumValues(label, &depth)); 4954 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 4955 PetscFunctionReturn(0); 4956 } 4957 4958 /*@ 4959 DMPlexGetPointDepth - Get the depth of a given point 4960 4961 Not Collective 4962 4963 Input Parameters: 4964 + dm - The DMPlex object 4965 - point - The point 4966 4967 Output Parameter: 4968 . depth - The depth of the point 4969 4970 Level: intermediate 4971 4972 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4973 @*/ 4974 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4975 { 4976 PetscFunctionBegin; 4977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4978 PetscValidIntPointer(depth, 3); 4979 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4980 PetscFunctionReturn(0); 4981 } 4982 4983 /*@ 4984 DMPlexGetPointHeight - Get the height of a given point 4985 4986 Not Collective 4987 4988 Input Parameters: 4989 + dm - The DMPlex object 4990 - point - The point 4991 4992 Output Parameter: 4993 . height - The height of the point 4994 4995 Level: intermediate 4996 4997 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4998 @*/ 4999 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 5000 { 5001 PetscInt n, pDepth; 5002 5003 PetscFunctionBegin; 5004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5005 PetscValidIntPointer(height, 3); 5006 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 5007 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 5008 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 5009 PetscFunctionReturn(0); 5010 } 5011 5012 /*@ 5013 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 5014 5015 Not Collective 5016 5017 Input Parameter: 5018 . dm - The DMPlex object 5019 5020 Output Parameter: 5021 . celltypeLabel - The DMLabel recording cell polytope type 5022 5023 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 5024 DMCreateLabel(dm, "celltype") beforehand. 5025 5026 Level: developer 5027 5028 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 5029 @*/ 5030 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 5031 { 5032 PetscFunctionBegin; 5033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5034 PetscValidPointer(celltypeLabel, 2); 5035 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 5036 *celltypeLabel = dm->celltypeLabel; 5037 PetscFunctionReturn(0); 5038 } 5039 5040 /*@ 5041 DMPlexGetCellType - Get the polytope type of a given cell 5042 5043 Not Collective 5044 5045 Input Parameters: 5046 + dm - The DMPlex object 5047 - cell - The cell 5048 5049 Output Parameter: 5050 . celltype - The polytope type of the cell 5051 5052 Level: intermediate 5053 5054 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 5055 @*/ 5056 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 5057 { 5058 DMLabel label; 5059 PetscInt ct; 5060 5061 PetscFunctionBegin; 5062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5063 PetscValidPointer(celltype, 3); 5064 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5065 PetscCall(DMLabelGetValue(label, cell, &ct)); 5066 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 5067 *celltype = (DMPolytopeType)ct; 5068 PetscFunctionReturn(0); 5069 } 5070 5071 /*@ 5072 DMPlexSetCellType - Set the polytope type of a given cell 5073 5074 Not Collective 5075 5076 Input Parameters: 5077 + dm - The DMPlex object 5078 . cell - The cell 5079 - celltype - The polytope type of the cell 5080 5081 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 5082 is executed. This function will override the computed type. However, if automatic classification will not succeed 5083 and a user wants to manually specify all types, the classification must be disabled by calling 5084 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 5085 5086 Level: advanced 5087 5088 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 5089 @*/ 5090 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 5091 { 5092 DMLabel label; 5093 5094 PetscFunctionBegin; 5095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5096 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 5097 PetscCall(DMLabelSetValue(label, cell, celltype)); 5098 PetscFunctionReturn(0); 5099 } 5100 5101 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5102 { 5103 PetscSection section, s; 5104 Mat m; 5105 PetscInt maxHeight; 5106 5107 PetscFunctionBegin; 5108 PetscCall(DMClone(dm, cdm)); 5109 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5110 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5111 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5112 PetscCall(DMSetLocalSection(*cdm, section)); 5113 PetscCall(PetscSectionDestroy(§ion)); 5114 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5115 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5116 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5117 PetscCall(PetscSectionDestroy(&s)); 5118 PetscCall(MatDestroy(&m)); 5119 5120 PetscCall(DMSetNumFields(*cdm, 1)); 5121 PetscCall(DMCreateDS(*cdm)); 5122 PetscFunctionReturn(0); 5123 } 5124 5125 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5126 { 5127 Vec coordsLocal, cellCoordsLocal; 5128 DM coordsDM, cellCoordsDM; 5129 5130 PetscFunctionBegin; 5131 *field = NULL; 5132 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 5133 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 5134 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 5135 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 5136 if (coordsLocal && coordsDM) { 5137 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 5138 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5139 } 5140 PetscFunctionReturn(0); 5141 } 5142 5143 /*@C 5144 DMPlexGetConeSection - Return a section which describes the layout of cone data 5145 5146 Not Collective 5147 5148 Input Parameters: 5149 . dm - The DMPlex object 5150 5151 Output Parameter: 5152 . section - The PetscSection object 5153 5154 Level: developer 5155 5156 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5157 @*/ 5158 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5159 { 5160 DM_Plex *mesh = (DM_Plex *)dm->data; 5161 5162 PetscFunctionBegin; 5163 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5164 if (section) *section = mesh->coneSection; 5165 PetscFunctionReturn(0); 5166 } 5167 5168 /*@C 5169 DMPlexGetSupportSection - Return a section which describes the layout of support data 5170 5171 Not Collective 5172 5173 Input Parameters: 5174 . dm - The DMPlex object 5175 5176 Output Parameter: 5177 . section - The PetscSection object 5178 5179 Level: developer 5180 5181 .seealso: `DMPlexGetConeSection()` 5182 @*/ 5183 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5184 { 5185 DM_Plex *mesh = (DM_Plex *)dm->data; 5186 5187 PetscFunctionBegin; 5188 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5189 if (section) *section = mesh->supportSection; 5190 PetscFunctionReturn(0); 5191 } 5192 5193 /*@C 5194 DMPlexGetCones - Return cone data 5195 5196 Not Collective 5197 5198 Input Parameters: 5199 . dm - The DMPlex object 5200 5201 Output Parameter: 5202 . cones - The cone for each point 5203 5204 Level: developer 5205 5206 .seealso: `DMPlexGetConeSection()` 5207 @*/ 5208 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5209 { 5210 DM_Plex *mesh = (DM_Plex *)dm->data; 5211 5212 PetscFunctionBegin; 5213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5214 if (cones) *cones = mesh->cones; 5215 PetscFunctionReturn(0); 5216 } 5217 5218 /*@C 5219 DMPlexGetConeOrientations - Return cone orientation data 5220 5221 Not Collective 5222 5223 Input Parameters: 5224 . dm - The DMPlex object 5225 5226 Output Parameter: 5227 . coneOrientations - The array of cone orientations for all points 5228 5229 Level: developer 5230 5231 Notes: 5232 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5233 5234 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5235 5236 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5237 @*/ 5238 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5239 { 5240 DM_Plex *mesh = (DM_Plex *)dm->data; 5241 5242 PetscFunctionBegin; 5243 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5244 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5245 PetscFunctionReturn(0); 5246 } 5247 5248 /******************************** FEM Support **********************************/ 5249 5250 /* 5251 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5252 representing a line in the section. 5253 */ 5254 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) 5255 { 5256 PetscFunctionBeginHot; 5257 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5258 if (line < 0) { 5259 *k = 0; 5260 *Nc = 0; 5261 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5262 *k = 1; 5263 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5264 /* An order k SEM disc has k-1 dofs on an edge */ 5265 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5266 *k = *k / *Nc + 1; 5267 } 5268 PetscFunctionReturn(0); 5269 } 5270 5271 /*@ 5272 5273 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5274 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5275 section provided (or the section of the DM). 5276 5277 Input Parameters: 5278 + dm - The DM 5279 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5280 - section - The PetscSection to reorder, or NULL for the default section 5281 5282 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5283 degree of the basis. 5284 5285 Example: 5286 A typical interpolated single-quad mesh might order points as 5287 .vb 5288 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5289 5290 v4 -- e6 -- v3 5291 | | 5292 e7 c0 e8 5293 | | 5294 v1 -- e5 -- v2 5295 .ve 5296 5297 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5298 dofs in the order of points, e.g., 5299 .vb 5300 c0 -> [0,1,2,3] 5301 v1 -> [4] 5302 ... 5303 e5 -> [8, 9] 5304 .ve 5305 5306 which corresponds to the dofs 5307 .vb 5308 6 10 11 7 5309 13 2 3 15 5310 12 0 1 14 5311 4 8 9 5 5312 .ve 5313 5314 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5315 .vb 5316 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5317 .ve 5318 5319 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5320 .vb 5321 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5322 .ve 5323 5324 Level: developer 5325 5326 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5327 @*/ 5328 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5329 { 5330 DMLabel label; 5331 PetscInt dim, depth = -1, eStart = -1, Nf; 5332 PetscBool vertexchart; 5333 5334 PetscFunctionBegin; 5335 PetscCall(DMGetDimension(dm, &dim)); 5336 if (dim < 1) PetscFunctionReturn(0); 5337 if (point < 0) { 5338 PetscInt sStart, sEnd; 5339 5340 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5341 point = sEnd - sStart ? sStart : point; 5342 } 5343 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5344 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5345 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5346 if (depth == 1) { 5347 eStart = point; 5348 } else if (depth == dim) { 5349 const PetscInt *cone; 5350 5351 PetscCall(DMPlexGetCone(dm, point, &cone)); 5352 if (dim == 2) eStart = cone[0]; 5353 else if (dim == 3) { 5354 const PetscInt *cone2; 5355 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5356 eStart = cone2[0]; 5357 } 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); 5358 } 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); 5359 { /* Determine whether the chart covers all points or just vertices. */ 5360 PetscInt pStart, pEnd, cStart, cEnd; 5361 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5362 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5363 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5364 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5365 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5366 } 5367 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5368 for (PetscInt d = 1; d <= dim; d++) { 5369 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5370 PetscInt *perm; 5371 5372 for (f = 0; f < Nf; ++f) { 5373 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5374 size += PetscPowInt(k + 1, d) * Nc; 5375 } 5376 PetscCall(PetscMalloc1(size, &perm)); 5377 for (f = 0; f < Nf; ++f) { 5378 switch (d) { 5379 case 1: 5380 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5381 /* 5382 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5383 We want [ vtx0; edge of length k-1; vtx1 ] 5384 */ 5385 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5386 for (i = 0; i < k - 1; i++) 5387 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5388 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5389 foffset = offset; 5390 break; 5391 case 2: 5392 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5393 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5394 /* The SEM order is 5395 5396 v_lb, {e_b}, v_rb, 5397 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5398 v_lt, reverse {e_t}, v_rt 5399 */ 5400 { 5401 const PetscInt of = 0; 5402 const PetscInt oeb = of + PetscSqr(k - 1); 5403 const PetscInt oer = oeb + (k - 1); 5404 const PetscInt oet = oer + (k - 1); 5405 const PetscInt oel = oet + (k - 1); 5406 const PetscInt ovlb = oel + (k - 1); 5407 const PetscInt ovrb = ovlb + 1; 5408 const PetscInt ovrt = ovrb + 1; 5409 const PetscInt ovlt = ovrt + 1; 5410 PetscInt o; 5411 5412 /* bottom */ 5413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5414 for (o = oeb; o < oer; ++o) 5415 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5416 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5417 /* middle */ 5418 for (i = 0; i < k - 1; ++i) { 5419 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5420 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5421 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5422 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5423 } 5424 /* top */ 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5426 for (o = oel - 1; o >= oet; --o) 5427 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5428 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5429 foffset = offset; 5430 } 5431 break; 5432 case 3: 5433 /* The original hex closure is 5434 5435 {c, 5436 f_b, f_t, f_f, f_b, f_r, f_l, 5437 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5438 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5439 */ 5440 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5441 /* The SEM order is 5442 Bottom Slice 5443 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5444 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5445 v_blb, {e_bb}, v_brb, 5446 5447 Middle Slice (j) 5448 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5449 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5450 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5451 5452 Top Slice 5453 v_tlf, {e_tf}, v_trf, 5454 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5455 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5456 */ 5457 { 5458 const PetscInt oc = 0; 5459 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5460 const PetscInt oft = ofb + PetscSqr(k - 1); 5461 const PetscInt off = oft + PetscSqr(k - 1); 5462 const PetscInt ofk = off + PetscSqr(k - 1); 5463 const PetscInt ofr = ofk + PetscSqr(k - 1); 5464 const PetscInt ofl = ofr + PetscSqr(k - 1); 5465 const PetscInt oebl = ofl + PetscSqr(k - 1); 5466 const PetscInt oebb = oebl + (k - 1); 5467 const PetscInt oebr = oebb + (k - 1); 5468 const PetscInt oebf = oebr + (k - 1); 5469 const PetscInt oetf = oebf + (k - 1); 5470 const PetscInt oetr = oetf + (k - 1); 5471 const PetscInt oetb = oetr + (k - 1); 5472 const PetscInt oetl = oetb + (k - 1); 5473 const PetscInt oerf = oetl + (k - 1); 5474 const PetscInt oelf = oerf + (k - 1); 5475 const PetscInt oelb = oelf + (k - 1); 5476 const PetscInt oerb = oelb + (k - 1); 5477 const PetscInt ovblf = oerb + (k - 1); 5478 const PetscInt ovblb = ovblf + 1; 5479 const PetscInt ovbrb = ovblb + 1; 5480 const PetscInt ovbrf = ovbrb + 1; 5481 const PetscInt ovtlf = ovbrf + 1; 5482 const PetscInt ovtrf = ovtlf + 1; 5483 const PetscInt ovtrb = ovtrf + 1; 5484 const PetscInt ovtlb = ovtrb + 1; 5485 PetscInt o, n; 5486 5487 /* Bottom Slice */ 5488 /* bottom */ 5489 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5490 for (o = oetf - 1; o >= oebf; --o) 5491 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5492 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5493 /* middle */ 5494 for (i = 0; i < k - 1; ++i) { 5495 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5496 for (n = 0; n < k - 1; ++n) { 5497 o = ofb + n * (k - 1) + i; 5498 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5499 } 5500 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5501 } 5502 /* top */ 5503 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5504 for (o = oebb; o < oebr; ++o) 5505 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5506 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5507 5508 /* Middle Slice */ 5509 for (j = 0; j < k - 1; ++j) { 5510 /* bottom */ 5511 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5512 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++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] = (oerf + j) * Nc + c + foffset; 5515 /* middle */ 5516 for (i = 0; i < k - 1; ++i) { 5517 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5518 for (n = 0; n < k - 1; ++n) 5519 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5520 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5521 } 5522 /* top */ 5523 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5524 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --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] = (oerb + (k - 2) - j) * Nc + c + foffset; 5527 } 5528 5529 /* Top Slice */ 5530 /* bottom */ 5531 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5532 for (o = oetf; o < oetr; ++o) 5533 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5534 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5535 /* middle */ 5536 for (i = 0; i < k - 1; ++i) { 5537 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5538 for (n = 0; n < k - 1; ++n) 5539 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5540 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5541 } 5542 /* top */ 5543 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5544 for (o = oetl - 1; o >= oetb; --o) 5545 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5546 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5547 5548 foffset = offset; 5549 } 5550 break; 5551 default: 5552 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5553 } 5554 } 5555 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5556 /* Check permutation */ 5557 { 5558 PetscInt *check; 5559 5560 PetscCall(PetscMalloc1(size, &check)); 5561 for (i = 0; i < size; ++i) { 5562 check[i] = -1; 5563 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5564 } 5565 for (i = 0; i < size; ++i) check[perm[i]] = i; 5566 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5567 PetscCall(PetscFree(check)); 5568 } 5569 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5570 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5571 PetscInt *loc_perm; 5572 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5573 for (PetscInt i = 0; i < size; i++) { 5574 loc_perm[i] = perm[i]; 5575 loc_perm[size + i] = size + perm[i]; 5576 } 5577 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5578 } 5579 } 5580 PetscFunctionReturn(0); 5581 } 5582 5583 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5584 { 5585 PetscDS prob; 5586 PetscInt depth, Nf, h; 5587 DMLabel label; 5588 5589 PetscFunctionBeginHot; 5590 PetscCall(DMGetDS(dm, &prob)); 5591 Nf = prob->Nf; 5592 label = dm->depthLabel; 5593 *dspace = NULL; 5594 if (field < Nf) { 5595 PetscObject disc = prob->disc[field]; 5596 5597 if (disc->classid == PETSCFE_CLASSID) { 5598 PetscDualSpace dsp; 5599 5600 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5601 PetscCall(DMLabelGetNumValues(label, &depth)); 5602 PetscCall(DMLabelGetValue(label, point, &h)); 5603 h = depth - 1 - h; 5604 if (h) { 5605 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5606 } else { 5607 *dspace = dsp; 5608 } 5609 } 5610 } 5611 PetscFunctionReturn(0); 5612 } 5613 5614 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5615 { 5616 PetscScalar *array; 5617 const PetscScalar *vArray; 5618 const PetscInt *cone, *coneO; 5619 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5620 5621 PetscFunctionBeginHot; 5622 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5623 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5624 PetscCall(DMPlexGetCone(dm, point, &cone)); 5625 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5626 if (!values || !*values) { 5627 if ((point >= pStart) && (point < pEnd)) { 5628 PetscInt dof; 5629 5630 PetscCall(PetscSectionGetDof(section, point, &dof)); 5631 size += dof; 5632 } 5633 for (p = 0; p < numPoints; ++p) { 5634 const PetscInt cp = cone[p]; 5635 PetscInt dof; 5636 5637 if ((cp < pStart) || (cp >= pEnd)) continue; 5638 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5639 size += dof; 5640 } 5641 if (!values) { 5642 if (csize) *csize = size; 5643 PetscFunctionReturn(0); 5644 } 5645 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5646 } else { 5647 array = *values; 5648 } 5649 size = 0; 5650 PetscCall(VecGetArrayRead(v, &vArray)); 5651 if ((point >= pStart) && (point < pEnd)) { 5652 PetscInt dof, off, d; 5653 const PetscScalar *varr; 5654 5655 PetscCall(PetscSectionGetDof(section, point, &dof)); 5656 PetscCall(PetscSectionGetOffset(section, point, &off)); 5657 varr = &vArray[off]; 5658 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5659 size += dof; 5660 } 5661 for (p = 0; p < numPoints; ++p) { 5662 const PetscInt cp = cone[p]; 5663 PetscInt o = coneO[p]; 5664 PetscInt dof, off, d; 5665 const PetscScalar *varr; 5666 5667 if ((cp < pStart) || (cp >= pEnd)) continue; 5668 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5669 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5670 varr = &vArray[off]; 5671 if (o >= 0) { 5672 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5673 } else { 5674 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5675 } 5676 size += dof; 5677 } 5678 PetscCall(VecRestoreArrayRead(v, &vArray)); 5679 if (!*values) { 5680 if (csize) *csize = size; 5681 *values = array; 5682 } else { 5683 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5684 *csize = size; 5685 } 5686 PetscFunctionReturn(0); 5687 } 5688 5689 /* Compress out points not in the section */ 5690 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5691 { 5692 const PetscInt np = *numPoints; 5693 PetscInt pStart, pEnd, p, q; 5694 5695 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5696 for (p = 0, q = 0; p < np; ++p) { 5697 const PetscInt r = points[p * 2]; 5698 if ((r >= pStart) && (r < pEnd)) { 5699 points[q * 2] = r; 5700 points[q * 2 + 1] = points[p * 2 + 1]; 5701 ++q; 5702 } 5703 } 5704 *numPoints = q; 5705 return 0; 5706 } 5707 5708 /* Compressed closure does not apply closure permutation */ 5709 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5710 { 5711 const PetscInt *cla = NULL; 5712 PetscInt np, *pts = NULL; 5713 5714 PetscFunctionBeginHot; 5715 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5716 if (*clPoints) { 5717 PetscInt dof, off; 5718 5719 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5720 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5721 PetscCall(ISGetIndices(*clPoints, &cla)); 5722 np = dof / 2; 5723 pts = (PetscInt *)&cla[off]; 5724 } else { 5725 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5726 PetscCall(CompressPoints_Private(section, &np, pts)); 5727 } 5728 *numPoints = np; 5729 *points = pts; 5730 *clp = cla; 5731 PetscFunctionReturn(0); 5732 } 5733 5734 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5735 { 5736 PetscFunctionBeginHot; 5737 if (!*clPoints) { 5738 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5739 } else { 5740 PetscCall(ISRestoreIndices(*clPoints, clp)); 5741 } 5742 *numPoints = 0; 5743 *points = NULL; 5744 *clSec = NULL; 5745 *clPoints = NULL; 5746 *clp = NULL; 5747 PetscFunctionReturn(0); 5748 } 5749 5750 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5751 { 5752 PetscInt offset = 0, p; 5753 const PetscInt **perms = NULL; 5754 const PetscScalar **flips = NULL; 5755 5756 PetscFunctionBeginHot; 5757 *size = 0; 5758 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5759 for (p = 0; p < numPoints; p++) { 5760 const PetscInt point = points[2 * p]; 5761 const PetscInt *perm = perms ? perms[p] : NULL; 5762 const PetscScalar *flip = flips ? flips[p] : NULL; 5763 PetscInt dof, off, d; 5764 const PetscScalar *varr; 5765 5766 PetscCall(PetscSectionGetDof(section, point, &dof)); 5767 PetscCall(PetscSectionGetOffset(section, point, &off)); 5768 varr = &vArray[off]; 5769 if (clperm) { 5770 if (perm) { 5771 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5772 } else { 5773 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5774 } 5775 if (flip) { 5776 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5777 } 5778 } else { 5779 if (perm) { 5780 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5781 } else { 5782 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5783 } 5784 if (flip) { 5785 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5786 } 5787 } 5788 offset += dof; 5789 } 5790 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5791 *size = offset; 5792 PetscFunctionReturn(0); 5793 } 5794 5795 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[]) 5796 { 5797 PetscInt offset = 0, f; 5798 5799 PetscFunctionBeginHot; 5800 *size = 0; 5801 for (f = 0; f < numFields; ++f) { 5802 PetscInt p; 5803 const PetscInt **perms = NULL; 5804 const PetscScalar **flips = NULL; 5805 5806 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5807 for (p = 0; p < numPoints; p++) { 5808 const PetscInt point = points[2 * p]; 5809 PetscInt fdof, foff, b; 5810 const PetscScalar *varr; 5811 const PetscInt *perm = perms ? perms[p] : NULL; 5812 const PetscScalar *flip = flips ? flips[p] : NULL; 5813 5814 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5815 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5816 varr = &vArray[foff]; 5817 if (clperm) { 5818 if (perm) { 5819 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5820 } else { 5821 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5822 } 5823 if (flip) { 5824 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5825 } 5826 } else { 5827 if (perm) { 5828 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5829 } else { 5830 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5831 } 5832 if (flip) { 5833 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5834 } 5835 } 5836 offset += fdof; 5837 } 5838 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5839 } 5840 *size = offset; 5841 PetscFunctionReturn(0); 5842 } 5843 5844 /*@C 5845 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5846 5847 Not collective 5848 5849 Input Parameters: 5850 + dm - The DM 5851 . section - The section describing the layout in v, or NULL to use the default section 5852 . v - The local vector 5853 - point - The point in the DM 5854 5855 Input/Output Parameters: 5856 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5857 - values - An array to use for the values, or NULL to have it allocated automatically; 5858 if the user provided NULL, it is a borrowed array and should not be freed 5859 5860 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5861 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5862 $ assembly function, and a user may already have allocated storage for this operation. 5863 $ 5864 $ A typical use could be 5865 $ 5866 $ values = NULL; 5867 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5868 $ for (cl = 0; cl < clSize; ++cl) { 5869 $ <Compute on closure> 5870 $ } 5871 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5872 $ 5873 $ or 5874 $ 5875 $ PetscMalloc1(clMaxSize, &values); 5876 $ for (p = pStart; p < pEnd; ++p) { 5877 $ clSize = clMaxSize; 5878 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5879 $ for (cl = 0; cl < clSize; ++cl) { 5880 $ <Compute on closure> 5881 $ } 5882 $ } 5883 $ PetscFree(values); 5884 5885 Fortran Notes: 5886 Since it returns an array, this routine is only available in Fortran 90, and you must 5887 include petsc.h90 in your code. 5888 5889 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5890 5891 Level: intermediate 5892 5893 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5894 @*/ 5895 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5896 { 5897 PetscSection clSection; 5898 IS clPoints; 5899 PetscInt *points = NULL; 5900 const PetscInt *clp, *perm; 5901 PetscInt depth, numFields, numPoints, asize; 5902 5903 PetscFunctionBeginHot; 5904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5905 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5906 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5907 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5908 PetscCall(DMPlexGetDepth(dm, &depth)); 5909 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5910 if (depth == 1 && numFields < 2) { 5911 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5912 PetscFunctionReturn(0); 5913 } 5914 /* Get points */ 5915 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5916 /* Get sizes */ 5917 asize = 0; 5918 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5919 PetscInt dof; 5920 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5921 asize += dof; 5922 } 5923 if (values) { 5924 const PetscScalar *vArray; 5925 PetscInt size; 5926 5927 if (*values) { 5928 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); 5929 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5930 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5931 PetscCall(VecGetArrayRead(v, &vArray)); 5932 /* Get values */ 5933 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5934 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5935 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5936 /* Cleanup array */ 5937 PetscCall(VecRestoreArrayRead(v, &vArray)); 5938 } 5939 if (csize) *csize = asize; 5940 /* Cleanup points */ 5941 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5942 PetscFunctionReturn(0); 5943 } 5944 5945 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5946 { 5947 DMLabel depthLabel; 5948 PetscSection clSection; 5949 IS clPoints; 5950 PetscScalar *array; 5951 const PetscScalar *vArray; 5952 PetscInt *points = NULL; 5953 const PetscInt *clp, *perm = NULL; 5954 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5955 5956 PetscFunctionBeginHot; 5957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5958 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5959 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5960 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5961 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5962 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5963 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5964 if (mdepth == 1 && numFields < 2) { 5965 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5966 PetscFunctionReturn(0); 5967 } 5968 /* Get points */ 5969 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5970 for (clsize = 0, p = 0; p < Np; p++) { 5971 PetscInt dof; 5972 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 5973 clsize += dof; 5974 } 5975 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 5976 /* Filter points */ 5977 for (p = 0; p < numPoints * 2; p += 2) { 5978 PetscInt dep; 5979 5980 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5981 if (dep != depth) continue; 5982 points[Np * 2 + 0] = points[p]; 5983 points[Np * 2 + 1] = points[p + 1]; 5984 ++Np; 5985 } 5986 /* Get array */ 5987 if (!values || !*values) { 5988 PetscInt asize = 0, dof; 5989 5990 for (p = 0; p < Np * 2; p += 2) { 5991 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5992 asize += dof; 5993 } 5994 if (!values) { 5995 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5996 if (csize) *csize = asize; 5997 PetscFunctionReturn(0); 5998 } 5999 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 6000 } else { 6001 array = *values; 6002 } 6003 PetscCall(VecGetArrayRead(v, &vArray)); 6004 /* Get values */ 6005 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 6006 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 6007 /* Cleanup points */ 6008 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6009 /* Cleanup array */ 6010 PetscCall(VecRestoreArrayRead(v, &vArray)); 6011 if (!*values) { 6012 if (csize) *csize = size; 6013 *values = array; 6014 } else { 6015 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 6016 *csize = size; 6017 } 6018 PetscFunctionReturn(0); 6019 } 6020 6021 /*@C 6022 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 6023 6024 Not collective 6025 6026 Input Parameters: 6027 + dm - The DM 6028 . section - The section describing the layout in v, or NULL to use the default section 6029 . v - The local vector 6030 . point - The point in the DM 6031 . csize - The number of values in the closure, or NULL 6032 - values - The array of values, which is a borrowed array and should not be freed 6033 6034 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 6035 6036 Fortran Notes: 6037 Since it returns an array, this routine is only available in Fortran 90, and you must 6038 include petsc.h90 in your code. 6039 6040 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 6041 6042 Level: intermediate 6043 6044 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 6045 @*/ 6046 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 6047 { 6048 PetscInt size = 0; 6049 6050 PetscFunctionBegin; 6051 /* Should work without recalculating size */ 6052 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 6053 *values = NULL; 6054 PetscFunctionReturn(0); 6055 } 6056 6057 static inline void add(PetscScalar *x, PetscScalar y) 6058 { 6059 *x += y; 6060 } 6061 static inline void insert(PetscScalar *x, PetscScalar y) 6062 { 6063 *x = y; 6064 } 6065 6066 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[]) 6067 { 6068 PetscInt cdof; /* The number of constraints on this point */ 6069 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6070 PetscScalar *a; 6071 PetscInt off, cind = 0, k; 6072 6073 PetscFunctionBegin; 6074 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6075 PetscCall(PetscSectionGetOffset(section, point, &off)); 6076 a = &array[off]; 6077 if (!cdof || setBC) { 6078 if (clperm) { 6079 if (perm) { 6080 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6081 } else { 6082 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6083 } 6084 } else { 6085 if (perm) { 6086 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6087 } else { 6088 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6089 } 6090 } 6091 } else { 6092 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6093 if (clperm) { 6094 if (perm) { 6095 for (k = 0; k < dof; ++k) { 6096 if ((cind < cdof) && (k == cdofs[cind])) { 6097 ++cind; 6098 continue; 6099 } 6100 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6101 } 6102 } else { 6103 for (k = 0; k < dof; ++k) { 6104 if ((cind < cdof) && (k == cdofs[cind])) { 6105 ++cind; 6106 continue; 6107 } 6108 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6109 } 6110 } 6111 } else { 6112 if (perm) { 6113 for (k = 0; k < dof; ++k) { 6114 if ((cind < cdof) && (k == cdofs[cind])) { 6115 ++cind; 6116 continue; 6117 } 6118 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6119 } 6120 } else { 6121 for (k = 0; k < dof; ++k) { 6122 if ((cind < cdof) && (k == cdofs[cind])) { 6123 ++cind; 6124 continue; 6125 } 6126 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6127 } 6128 } 6129 } 6130 } 6131 PetscFunctionReturn(0); 6132 } 6133 6134 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[]) 6135 { 6136 PetscInt cdof; /* The number of constraints on this point */ 6137 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6138 PetscScalar *a; 6139 PetscInt off, cind = 0, k; 6140 6141 PetscFunctionBegin; 6142 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6143 PetscCall(PetscSectionGetOffset(section, point, &off)); 6144 a = &array[off]; 6145 if (cdof) { 6146 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6147 if (clperm) { 6148 if (perm) { 6149 for (k = 0; k < dof; ++k) { 6150 if ((cind < cdof) && (k == cdofs[cind])) { 6151 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6152 cind++; 6153 } 6154 } 6155 } else { 6156 for (k = 0; k < dof; ++k) { 6157 if ((cind < cdof) && (k == cdofs[cind])) { 6158 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 6159 cind++; 6160 } 6161 } 6162 } 6163 } else { 6164 if (perm) { 6165 for (k = 0; k < dof; ++k) { 6166 if ((cind < cdof) && (k == cdofs[cind])) { 6167 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 6168 cind++; 6169 } 6170 } 6171 } else { 6172 for (k = 0; k < dof; ++k) { 6173 if ((cind < cdof) && (k == cdofs[cind])) { 6174 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 6175 cind++; 6176 } 6177 } 6178 } 6179 } 6180 } 6181 PetscFunctionReturn(0); 6182 } 6183 6184 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[]) 6185 { 6186 PetscScalar *a; 6187 PetscInt fdof, foff, fcdof, foffset = *offset; 6188 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6189 PetscInt cind = 0, b; 6190 6191 PetscFunctionBegin; 6192 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6193 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6194 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6195 a = &array[foff]; 6196 if (!fcdof || setBC) { 6197 if (clperm) { 6198 if (perm) { 6199 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6200 } else { 6201 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6202 } 6203 } else { 6204 if (perm) { 6205 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6206 } else { 6207 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6208 } 6209 } 6210 } else { 6211 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6212 if (clperm) { 6213 if (perm) { 6214 for (b = 0; b < fdof; b++) { 6215 if ((cind < fcdof) && (b == fcdofs[cind])) { 6216 ++cind; 6217 continue; 6218 } 6219 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6220 } 6221 } else { 6222 for (b = 0; b < fdof; b++) { 6223 if ((cind < fcdof) && (b == fcdofs[cind])) { 6224 ++cind; 6225 continue; 6226 } 6227 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6228 } 6229 } 6230 } else { 6231 if (perm) { 6232 for (b = 0; b < fdof; b++) { 6233 if ((cind < fcdof) && (b == fcdofs[cind])) { 6234 ++cind; 6235 continue; 6236 } 6237 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6238 } 6239 } else { 6240 for (b = 0; b < fdof; b++) { 6241 if ((cind < fcdof) && (b == fcdofs[cind])) { 6242 ++cind; 6243 continue; 6244 } 6245 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6246 } 6247 } 6248 } 6249 } 6250 *offset += fdof; 6251 PetscFunctionReturn(0); 6252 } 6253 6254 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[]) 6255 { 6256 PetscScalar *a; 6257 PetscInt fdof, foff, fcdof, foffset = *offset; 6258 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6259 PetscInt Nc, cind = 0, ncind = 0, b; 6260 PetscBool ncSet, fcSet; 6261 6262 PetscFunctionBegin; 6263 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6264 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6265 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6266 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6267 a = &array[foff]; 6268 if (fcdof) { 6269 /* We just override fcdof and fcdofs with Ncc and comps */ 6270 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6271 if (clperm) { 6272 if (perm) { 6273 if (comps) { 6274 for (b = 0; b < fdof; b++) { 6275 ncSet = fcSet = PETSC_FALSE; 6276 if (b % Nc == comps[ncind]) { 6277 ncind = (ncind + 1) % Ncc; 6278 ncSet = PETSC_TRUE; 6279 } 6280 if ((cind < fcdof) && (b == fcdofs[cind])) { 6281 ++cind; 6282 fcSet = PETSC_TRUE; 6283 } 6284 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6285 } 6286 } else { 6287 for (b = 0; b < fdof; b++) { 6288 if ((cind < fcdof) && (b == fcdofs[cind])) { 6289 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6290 ++cind; 6291 } 6292 } 6293 } 6294 } else { 6295 if (comps) { 6296 for (b = 0; b < fdof; b++) { 6297 ncSet = fcSet = PETSC_FALSE; 6298 if (b % Nc == comps[ncind]) { 6299 ncind = (ncind + 1) % Ncc; 6300 ncSet = PETSC_TRUE; 6301 } 6302 if ((cind < fcdof) && (b == fcdofs[cind])) { 6303 ++cind; 6304 fcSet = PETSC_TRUE; 6305 } 6306 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6307 } 6308 } else { 6309 for (b = 0; b < fdof; b++) { 6310 if ((cind < fcdof) && (b == fcdofs[cind])) { 6311 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6312 ++cind; 6313 } 6314 } 6315 } 6316 } 6317 } else { 6318 if (perm) { 6319 if (comps) { 6320 for (b = 0; b < fdof; b++) { 6321 ncSet = fcSet = PETSC_FALSE; 6322 if (b % Nc == comps[ncind]) { 6323 ncind = (ncind + 1) % Ncc; 6324 ncSet = PETSC_TRUE; 6325 } 6326 if ((cind < fcdof) && (b == fcdofs[cind])) { 6327 ++cind; 6328 fcSet = PETSC_TRUE; 6329 } 6330 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6331 } 6332 } else { 6333 for (b = 0; b < fdof; b++) { 6334 if ((cind < fcdof) && (b == fcdofs[cind])) { 6335 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6336 ++cind; 6337 } 6338 } 6339 } 6340 } else { 6341 if (comps) { 6342 for (b = 0; b < fdof; b++) { 6343 ncSet = fcSet = PETSC_FALSE; 6344 if (b % Nc == comps[ncind]) { 6345 ncind = (ncind + 1) % Ncc; 6346 ncSet = PETSC_TRUE; 6347 } 6348 if ((cind < fcdof) && (b == fcdofs[cind])) { 6349 ++cind; 6350 fcSet = PETSC_TRUE; 6351 } 6352 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6353 } 6354 } else { 6355 for (b = 0; b < fdof; b++) { 6356 if ((cind < fcdof) && (b == fcdofs[cind])) { 6357 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6358 ++cind; 6359 } 6360 } 6361 } 6362 } 6363 } 6364 } 6365 *offset += fdof; 6366 PetscFunctionReturn(0); 6367 } 6368 6369 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6370 { 6371 PetscScalar *array; 6372 const PetscInt *cone, *coneO; 6373 PetscInt pStart, pEnd, p, numPoints, off, dof; 6374 6375 PetscFunctionBeginHot; 6376 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6377 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6378 PetscCall(DMPlexGetCone(dm, point, &cone)); 6379 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6380 PetscCall(VecGetArray(v, &array)); 6381 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6382 const PetscInt cp = !p ? point : cone[p - 1]; 6383 const PetscInt o = !p ? 0 : coneO[p - 1]; 6384 6385 if ((cp < pStart) || (cp >= pEnd)) { 6386 dof = 0; 6387 continue; 6388 } 6389 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6390 /* ADD_VALUES */ 6391 { 6392 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6393 PetscScalar *a; 6394 PetscInt cdof, coff, cind = 0, k; 6395 6396 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6397 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6398 a = &array[coff]; 6399 if (!cdof) { 6400 if (o >= 0) { 6401 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6402 } else { 6403 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6404 } 6405 } else { 6406 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6407 if (o >= 0) { 6408 for (k = 0; k < dof; ++k) { 6409 if ((cind < cdof) && (k == cdofs[cind])) { 6410 ++cind; 6411 continue; 6412 } 6413 a[k] += values[off + k]; 6414 } 6415 } else { 6416 for (k = 0; k < dof; ++k) { 6417 if ((cind < cdof) && (k == cdofs[cind])) { 6418 ++cind; 6419 continue; 6420 } 6421 a[k] += values[off + dof - k - 1]; 6422 } 6423 } 6424 } 6425 } 6426 } 6427 PetscCall(VecRestoreArray(v, &array)); 6428 PetscFunctionReturn(0); 6429 } 6430 6431 /*@C 6432 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6433 6434 Not collective 6435 6436 Input Parameters: 6437 + dm - The DM 6438 . section - The section describing the layout in v, or NULL to use the default section 6439 . v - The local vector 6440 . point - The point in the DM 6441 . values - The array of values 6442 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6443 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6444 6445 Fortran Notes: 6446 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6447 6448 Level: intermediate 6449 6450 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6451 @*/ 6452 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6453 { 6454 PetscSection clSection; 6455 IS clPoints; 6456 PetscScalar *array; 6457 PetscInt *points = NULL; 6458 const PetscInt *clp, *clperm = NULL; 6459 PetscInt depth, numFields, numPoints, p, clsize; 6460 6461 PetscFunctionBeginHot; 6462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6463 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6464 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6465 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6466 PetscCall(DMPlexGetDepth(dm, &depth)); 6467 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6468 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6469 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6470 PetscFunctionReturn(0); 6471 } 6472 /* Get points */ 6473 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6474 for (clsize = 0, p = 0; p < numPoints; p++) { 6475 PetscInt dof; 6476 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6477 clsize += dof; 6478 } 6479 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6480 /* Get array */ 6481 PetscCall(VecGetArray(v, &array)); 6482 /* Get values */ 6483 if (numFields > 0) { 6484 PetscInt offset = 0, f; 6485 for (f = 0; f < numFields; ++f) { 6486 const PetscInt **perms = NULL; 6487 const PetscScalar **flips = NULL; 6488 6489 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6490 switch (mode) { 6491 case INSERT_VALUES: 6492 for (p = 0; p < numPoints; p++) { 6493 const PetscInt point = points[2 * p]; 6494 const PetscInt *perm = perms ? perms[p] : NULL; 6495 const PetscScalar *flip = flips ? flips[p] : NULL; 6496 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6497 } 6498 break; 6499 case INSERT_ALL_VALUES: 6500 for (p = 0; p < numPoints; p++) { 6501 const PetscInt point = points[2 * p]; 6502 const PetscInt *perm = perms ? perms[p] : NULL; 6503 const PetscScalar *flip = flips ? flips[p] : NULL; 6504 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6505 } 6506 break; 6507 case INSERT_BC_VALUES: 6508 for (p = 0; p < numPoints; p++) { 6509 const PetscInt point = points[2 * p]; 6510 const PetscInt *perm = perms ? perms[p] : NULL; 6511 const PetscScalar *flip = flips ? flips[p] : NULL; 6512 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6513 } 6514 break; 6515 case ADD_VALUES: 6516 for (p = 0; p < numPoints; p++) { 6517 const PetscInt point = points[2 * p]; 6518 const PetscInt *perm = perms ? perms[p] : NULL; 6519 const PetscScalar *flip = flips ? flips[p] : NULL; 6520 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6521 } 6522 break; 6523 case ADD_ALL_VALUES: 6524 for (p = 0; p < numPoints; p++) { 6525 const PetscInt point = points[2 * p]; 6526 const PetscInt *perm = perms ? perms[p] : NULL; 6527 const PetscScalar *flip = flips ? flips[p] : NULL; 6528 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6529 } 6530 break; 6531 case ADD_BC_VALUES: 6532 for (p = 0; p < numPoints; p++) { 6533 const PetscInt point = points[2 * p]; 6534 const PetscInt *perm = perms ? perms[p] : NULL; 6535 const PetscScalar *flip = flips ? flips[p] : NULL; 6536 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6537 } 6538 break; 6539 default: 6540 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6541 } 6542 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6543 } 6544 } else { 6545 PetscInt dof, off; 6546 const PetscInt **perms = NULL; 6547 const PetscScalar **flips = NULL; 6548 6549 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6550 switch (mode) { 6551 case INSERT_VALUES: 6552 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6553 const PetscInt point = points[2 * p]; 6554 const PetscInt *perm = perms ? perms[p] : NULL; 6555 const PetscScalar *flip = flips ? flips[p] : NULL; 6556 PetscCall(PetscSectionGetDof(section, point, &dof)); 6557 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6558 } 6559 break; 6560 case INSERT_ALL_VALUES: 6561 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6562 const PetscInt point = points[2 * p]; 6563 const PetscInt *perm = perms ? perms[p] : NULL; 6564 const PetscScalar *flip = flips ? flips[p] : NULL; 6565 PetscCall(PetscSectionGetDof(section, point, &dof)); 6566 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6567 } 6568 break; 6569 case INSERT_BC_VALUES: 6570 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6571 const PetscInt point = points[2 * p]; 6572 const PetscInt *perm = perms ? perms[p] : NULL; 6573 const PetscScalar *flip = flips ? flips[p] : NULL; 6574 PetscCall(PetscSectionGetDof(section, point, &dof)); 6575 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6576 } 6577 break; 6578 case ADD_VALUES: 6579 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6580 const PetscInt point = points[2 * p]; 6581 const PetscInt *perm = perms ? perms[p] : NULL; 6582 const PetscScalar *flip = flips ? flips[p] : NULL; 6583 PetscCall(PetscSectionGetDof(section, point, &dof)); 6584 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6585 } 6586 break; 6587 case ADD_ALL_VALUES: 6588 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6589 const PetscInt point = points[2 * p]; 6590 const PetscInt *perm = perms ? perms[p] : NULL; 6591 const PetscScalar *flip = flips ? flips[p] : NULL; 6592 PetscCall(PetscSectionGetDof(section, point, &dof)); 6593 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6594 } 6595 break; 6596 case ADD_BC_VALUES: 6597 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6598 const PetscInt point = points[2 * p]; 6599 const PetscInt *perm = perms ? perms[p] : NULL; 6600 const PetscScalar *flip = flips ? flips[p] : NULL; 6601 PetscCall(PetscSectionGetDof(section, point, &dof)); 6602 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6603 } 6604 break; 6605 default: 6606 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6607 } 6608 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6609 } 6610 /* Cleanup points */ 6611 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6612 /* Cleanup array */ 6613 PetscCall(VecRestoreArray(v, &array)); 6614 PetscFunctionReturn(0); 6615 } 6616 6617 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6618 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) 6619 { 6620 PetscFunctionBegin; 6621 *contains = PETSC_TRUE; 6622 if (label) { 6623 PetscInt fdof; 6624 6625 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6626 if (!*contains) { 6627 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6628 *offset += fdof; 6629 PetscFunctionReturn(0); 6630 } 6631 } 6632 PetscFunctionReturn(0); 6633 } 6634 6635 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6636 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) 6637 { 6638 PetscSection clSection; 6639 IS clPoints; 6640 PetscScalar *array; 6641 PetscInt *points = NULL; 6642 const PetscInt *clp; 6643 PetscInt numFields, numPoints, p; 6644 PetscInt offset = 0, f; 6645 6646 PetscFunctionBeginHot; 6647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6648 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6649 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6650 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6651 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6652 /* Get points */ 6653 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6654 /* Get array */ 6655 PetscCall(VecGetArray(v, &array)); 6656 /* Get values */ 6657 for (f = 0; f < numFields; ++f) { 6658 const PetscInt **perms = NULL; 6659 const PetscScalar **flips = NULL; 6660 PetscBool contains; 6661 6662 if (!fieldActive[f]) { 6663 for (p = 0; p < numPoints * 2; p += 2) { 6664 PetscInt fdof; 6665 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6666 offset += fdof; 6667 } 6668 continue; 6669 } 6670 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6671 switch (mode) { 6672 case INSERT_VALUES: 6673 for (p = 0; p < numPoints; p++) { 6674 const PetscInt point = points[2 * p]; 6675 const PetscInt *perm = perms ? perms[p] : NULL; 6676 const PetscScalar *flip = flips ? flips[p] : NULL; 6677 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6678 if (!contains) continue; 6679 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6680 } 6681 break; 6682 case INSERT_ALL_VALUES: 6683 for (p = 0; p < numPoints; p++) { 6684 const PetscInt point = points[2 * p]; 6685 const PetscInt *perm = perms ? perms[p] : NULL; 6686 const PetscScalar *flip = flips ? flips[p] : NULL; 6687 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6688 if (!contains) continue; 6689 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6690 } 6691 break; 6692 case INSERT_BC_VALUES: 6693 for (p = 0; p < numPoints; p++) { 6694 const PetscInt point = points[2 * p]; 6695 const PetscInt *perm = perms ? perms[p] : NULL; 6696 const PetscScalar *flip = flips ? flips[p] : NULL; 6697 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6698 if (!contains) continue; 6699 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6700 } 6701 break; 6702 case ADD_VALUES: 6703 for (p = 0; p < numPoints; p++) { 6704 const PetscInt point = points[2 * p]; 6705 const PetscInt *perm = perms ? perms[p] : NULL; 6706 const PetscScalar *flip = flips ? flips[p] : NULL; 6707 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6708 if (!contains) continue; 6709 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6710 } 6711 break; 6712 case ADD_ALL_VALUES: 6713 for (p = 0; p < numPoints; p++) { 6714 const PetscInt point = points[2 * p]; 6715 const PetscInt *perm = perms ? perms[p] : NULL; 6716 const PetscScalar *flip = flips ? flips[p] : NULL; 6717 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6718 if (!contains) continue; 6719 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6720 } 6721 break; 6722 default: 6723 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6724 } 6725 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6726 } 6727 /* Cleanup points */ 6728 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6729 /* Cleanup array */ 6730 PetscCall(VecRestoreArray(v, &array)); 6731 PetscFunctionReturn(0); 6732 } 6733 6734 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6735 { 6736 PetscMPIInt rank; 6737 PetscInt i, j; 6738 6739 PetscFunctionBegin; 6740 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6741 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6742 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6743 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6744 numCIndices = numCIndices ? numCIndices : numRIndices; 6745 if (!values) PetscFunctionReturn(0); 6746 for (i = 0; i < numRIndices; i++) { 6747 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6748 for (j = 0; j < numCIndices; j++) { 6749 #if defined(PETSC_USE_COMPLEX) 6750 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6751 #else 6752 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6753 #endif 6754 } 6755 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6756 } 6757 PetscFunctionReturn(0); 6758 } 6759 6760 /* 6761 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6762 6763 Input Parameters: 6764 + section - The section for this data layout 6765 . islocal - Is the section (and thus indices being requested) local or global? 6766 . point - The point contributing dofs with these indices 6767 . off - The global offset of this point 6768 . loff - The local offset of each field 6769 . setBC - The flag determining whether to include indices of boundary values 6770 . perm - A permutation of the dofs on this point, or NULL 6771 - indperm - A permutation of the entire indices array, or NULL 6772 6773 Output Parameter: 6774 . indices - Indices for dofs on this point 6775 6776 Level: developer 6777 6778 Note: The indices could be local or global, depending on the value of 'off'. 6779 */ 6780 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6781 { 6782 PetscInt dof; /* The number of unknowns on this point */ 6783 PetscInt cdof; /* The number of constraints on this point */ 6784 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6785 PetscInt cind = 0, k; 6786 6787 PetscFunctionBegin; 6788 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6789 PetscCall(PetscSectionGetDof(section, point, &dof)); 6790 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6791 if (!cdof || setBC) { 6792 for (k = 0; k < dof; ++k) { 6793 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6794 const PetscInt ind = indperm ? indperm[preind] : preind; 6795 6796 indices[ind] = off + k; 6797 } 6798 } else { 6799 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6800 for (k = 0; k < dof; ++k) { 6801 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6802 const PetscInt ind = indperm ? indperm[preind] : preind; 6803 6804 if ((cind < cdof) && (k == cdofs[cind])) { 6805 /* Insert check for returning constrained indices */ 6806 indices[ind] = -(off + k + 1); 6807 ++cind; 6808 } else { 6809 indices[ind] = off + k - (islocal ? 0 : cind); 6810 } 6811 } 6812 } 6813 *loff += dof; 6814 PetscFunctionReturn(0); 6815 } 6816 6817 /* 6818 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6819 6820 Input Parameters: 6821 + section - a section (global or local) 6822 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6823 . point - point within section 6824 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6825 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6826 . setBC - identify constrained (boundary condition) points via involution. 6827 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6828 . permsoff - offset 6829 - indperm - index permutation 6830 6831 Output Parameter: 6832 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6833 . indices - array to hold indices (as defined by section) of each dof associated with point 6834 6835 Notes: 6836 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6837 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6838 in the local vector. 6839 6840 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6841 significant). It is invalid to call with a global section and setBC=true. 6842 6843 Developer Note: 6844 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6845 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6846 offset could be obtained from the section instead of passing it explicitly as we do now. 6847 6848 Example: 6849 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6850 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6851 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6852 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. 6853 6854 Level: developer 6855 */ 6856 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[]) 6857 { 6858 PetscInt numFields, foff, f; 6859 6860 PetscFunctionBegin; 6861 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6862 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6863 for (f = 0, foff = 0; f < numFields; ++f) { 6864 PetscInt fdof, cfdof; 6865 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6866 PetscInt cind = 0, b; 6867 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6868 6869 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6870 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6871 if (!cfdof || setBC) { 6872 for (b = 0; b < fdof; ++b) { 6873 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6874 const PetscInt ind = indperm ? indperm[preind] : preind; 6875 6876 indices[ind] = off + foff + b; 6877 } 6878 } else { 6879 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6880 for (b = 0; b < fdof; ++b) { 6881 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6882 const PetscInt ind = indperm ? indperm[preind] : preind; 6883 6884 if ((cind < cfdof) && (b == fcdofs[cind])) { 6885 indices[ind] = -(off + foff + b + 1); 6886 ++cind; 6887 } else { 6888 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6889 } 6890 } 6891 } 6892 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6893 foffs[f] += fdof; 6894 } 6895 PetscFunctionReturn(0); 6896 } 6897 6898 /* 6899 This version believes the globalSection offsets for each field, rather than just the point offset 6900 6901 . foffs - The offset into 'indices' for each field, since it is segregated by field 6902 6903 Notes: 6904 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6905 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6906 */ 6907 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6908 { 6909 PetscInt numFields, foff, f; 6910 6911 PetscFunctionBegin; 6912 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6913 for (f = 0; f < numFields; ++f) { 6914 PetscInt fdof, cfdof; 6915 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6916 PetscInt cind = 0, b; 6917 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6918 6919 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6920 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6921 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6922 if (!cfdof) { 6923 for (b = 0; b < fdof; ++b) { 6924 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6925 const PetscInt ind = indperm ? indperm[preind] : preind; 6926 6927 indices[ind] = foff + b; 6928 } 6929 } else { 6930 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6931 for (b = 0; b < fdof; ++b) { 6932 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6933 const PetscInt ind = indperm ? indperm[preind] : preind; 6934 6935 if ((cind < cfdof) && (b == fcdofs[cind])) { 6936 indices[ind] = -(foff + b + 1); 6937 ++cind; 6938 } else { 6939 indices[ind] = foff + b - cind; 6940 } 6941 } 6942 } 6943 foffs[f] += fdof; 6944 } 6945 PetscFunctionReturn(0); 6946 } 6947 6948 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) 6949 { 6950 Mat cMat; 6951 PetscSection aSec, cSec; 6952 IS aIS; 6953 PetscInt aStart = -1, aEnd = -1; 6954 const PetscInt *anchors; 6955 PetscInt numFields, f, p, q, newP = 0; 6956 PetscInt newNumPoints = 0, newNumIndices = 0; 6957 PetscInt *newPoints, *indices, *newIndices; 6958 PetscInt maxAnchor, maxDof; 6959 PetscInt newOffsets[32]; 6960 PetscInt *pointMatOffsets[32]; 6961 PetscInt *newPointOffsets[32]; 6962 PetscScalar *pointMat[32]; 6963 PetscScalar *newValues = NULL, *tmpValues; 6964 PetscBool anyConstrained = PETSC_FALSE; 6965 6966 PetscFunctionBegin; 6967 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6968 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6969 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6970 6971 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6972 /* if there are point-to-point constraints */ 6973 if (aSec) { 6974 PetscCall(PetscArrayzero(newOffsets, 32)); 6975 PetscCall(ISGetIndices(aIS, &anchors)); 6976 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6977 /* figure out how many points are going to be in the new element matrix 6978 * (we allow double counting, because it's all just going to be summed 6979 * into the global matrix anyway) */ 6980 for (p = 0; p < 2 * numPoints; p += 2) { 6981 PetscInt b = points[p]; 6982 PetscInt bDof = 0, bSecDof; 6983 6984 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6985 if (!bSecDof) continue; 6986 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6987 if (bDof) { 6988 /* this point is constrained */ 6989 /* it is going to be replaced by its anchors */ 6990 PetscInt bOff, q; 6991 6992 anyConstrained = PETSC_TRUE; 6993 newNumPoints += bDof; 6994 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6995 for (q = 0; q < bDof; q++) { 6996 PetscInt a = anchors[bOff + q]; 6997 PetscInt aDof; 6998 6999 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7000 newNumIndices += aDof; 7001 for (f = 0; f < numFields; ++f) { 7002 PetscInt fDof; 7003 7004 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 7005 newOffsets[f + 1] += fDof; 7006 } 7007 } 7008 } else { 7009 /* this point is not constrained */ 7010 newNumPoints++; 7011 newNumIndices += bSecDof; 7012 for (f = 0; f < numFields; ++f) { 7013 PetscInt fDof; 7014 7015 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7016 newOffsets[f + 1] += fDof; 7017 } 7018 } 7019 } 7020 } 7021 if (!anyConstrained) { 7022 if (outNumPoints) *outNumPoints = 0; 7023 if (outNumIndices) *outNumIndices = 0; 7024 if (outPoints) *outPoints = NULL; 7025 if (outValues) *outValues = NULL; 7026 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7027 PetscFunctionReturn(0); 7028 } 7029 7030 if (outNumPoints) *outNumPoints = newNumPoints; 7031 if (outNumIndices) *outNumIndices = newNumIndices; 7032 7033 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 7034 7035 if (!outPoints && !outValues) { 7036 if (offsets) { 7037 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7038 } 7039 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 7040 PetscFunctionReturn(0); 7041 } 7042 7043 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 7044 7045 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 7046 7047 /* workspaces */ 7048 if (numFields) { 7049 for (f = 0; f < numFields; f++) { 7050 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7051 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7052 } 7053 } else { 7054 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7055 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 7056 } 7057 7058 /* get workspaces for the point-to-point matrices */ 7059 if (numFields) { 7060 PetscInt totalOffset, totalMatOffset; 7061 7062 for (p = 0; p < numPoints; p++) { 7063 PetscInt b = points[2 * p]; 7064 PetscInt bDof = 0, bSecDof; 7065 7066 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7067 if (!bSecDof) { 7068 for (f = 0; f < numFields; f++) { 7069 newPointOffsets[f][p + 1] = 0; 7070 pointMatOffsets[f][p + 1] = 0; 7071 } 7072 continue; 7073 } 7074 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7075 if (bDof) { 7076 for (f = 0; f < numFields; f++) { 7077 PetscInt fDof, q, bOff, allFDof = 0; 7078 7079 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7080 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7081 for (q = 0; q < bDof; q++) { 7082 PetscInt a = anchors[bOff + q]; 7083 PetscInt aFDof; 7084 7085 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 7086 allFDof += aFDof; 7087 } 7088 newPointOffsets[f][p + 1] = allFDof; 7089 pointMatOffsets[f][p + 1] = fDof * allFDof; 7090 } 7091 } else { 7092 for (f = 0; f < numFields; f++) { 7093 PetscInt fDof; 7094 7095 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 7096 newPointOffsets[f][p + 1] = fDof; 7097 pointMatOffsets[f][p + 1] = 0; 7098 } 7099 } 7100 } 7101 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 7102 newPointOffsets[f][0] = totalOffset; 7103 pointMatOffsets[f][0] = totalMatOffset; 7104 for (p = 0; p < numPoints; p++) { 7105 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 7106 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 7107 } 7108 totalOffset = newPointOffsets[f][numPoints]; 7109 totalMatOffset = pointMatOffsets[f][numPoints]; 7110 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7111 } 7112 } else { 7113 for (p = 0; p < numPoints; p++) { 7114 PetscInt b = points[2 * p]; 7115 PetscInt bDof = 0, bSecDof; 7116 7117 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7118 if (!bSecDof) { 7119 newPointOffsets[0][p + 1] = 0; 7120 pointMatOffsets[0][p + 1] = 0; 7121 continue; 7122 } 7123 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7124 if (bDof) { 7125 PetscInt bOff, q, allDof = 0; 7126 7127 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7128 for (q = 0; q < bDof; q++) { 7129 PetscInt a = anchors[bOff + q], aDof; 7130 7131 PetscCall(PetscSectionGetDof(section, a, &aDof)); 7132 allDof += aDof; 7133 } 7134 newPointOffsets[0][p + 1] = allDof; 7135 pointMatOffsets[0][p + 1] = bSecDof * allDof; 7136 } else { 7137 newPointOffsets[0][p + 1] = bSecDof; 7138 pointMatOffsets[0][p + 1] = 0; 7139 } 7140 } 7141 newPointOffsets[0][0] = 0; 7142 pointMatOffsets[0][0] = 0; 7143 for (p = 0; p < numPoints; p++) { 7144 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 7145 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 7146 } 7147 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7148 } 7149 7150 /* output arrays */ 7151 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7152 7153 /* get the point-to-point matrices; construct newPoints */ 7154 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 7155 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 7156 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 7157 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7158 if (numFields) { 7159 for (p = 0, newP = 0; p < numPoints; p++) { 7160 PetscInt b = points[2 * p]; 7161 PetscInt o = points[2 * p + 1]; 7162 PetscInt bDof = 0, bSecDof; 7163 7164 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7165 if (!bSecDof) continue; 7166 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7167 if (bDof) { 7168 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 7169 7170 fStart[0] = 0; 7171 fEnd[0] = 0; 7172 for (f = 0; f < numFields; f++) { 7173 PetscInt fDof; 7174 7175 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 7176 fStart[f + 1] = fStart[f] + fDof; 7177 fEnd[f + 1] = fStart[f + 1]; 7178 } 7179 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7180 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 7181 7182 fAnchorStart[0] = 0; 7183 fAnchorEnd[0] = 0; 7184 for (f = 0; f < numFields; f++) { 7185 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 7186 7187 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 7188 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 7189 } 7190 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7191 for (q = 0; q < bDof; q++) { 7192 PetscInt a = anchors[bOff + q], aOff; 7193 7194 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7195 newPoints[2 * (newP + q)] = a; 7196 newPoints[2 * (newP + q) + 1] = 0; 7197 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7198 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7199 } 7200 newP += bDof; 7201 7202 if (outValues) { 7203 /* get the point-to-point submatrix */ 7204 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])); 7205 } 7206 } else { 7207 newPoints[2 * newP] = b; 7208 newPoints[2 * newP + 1] = o; 7209 newP++; 7210 } 7211 } 7212 } else { 7213 for (p = 0; p < numPoints; p++) { 7214 PetscInt b = points[2 * p]; 7215 PetscInt o = points[2 * p + 1]; 7216 PetscInt bDof = 0, bSecDof; 7217 7218 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7219 if (!bSecDof) continue; 7220 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7221 if (bDof) { 7222 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7223 7224 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7225 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7226 7227 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7228 for (q = 0; q < bDof; q++) { 7229 PetscInt a = anchors[bOff + q], aOff; 7230 7231 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7232 7233 newPoints[2 * (newP + q)] = a; 7234 newPoints[2 * (newP + q) + 1] = 0; 7235 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7236 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7237 } 7238 newP += bDof; 7239 7240 /* get the point-to-point submatrix */ 7241 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7242 } else { 7243 newPoints[2 * newP] = b; 7244 newPoints[2 * newP + 1] = o; 7245 newP++; 7246 } 7247 } 7248 } 7249 7250 if (outValues) { 7251 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7252 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7253 /* multiply constraints on the right */ 7254 if (numFields) { 7255 for (f = 0; f < numFields; f++) { 7256 PetscInt oldOff = offsets[f]; 7257 7258 for (p = 0; p < numPoints; p++) { 7259 PetscInt cStart = newPointOffsets[f][p]; 7260 PetscInt b = points[2 * p]; 7261 PetscInt c, r, k; 7262 PetscInt dof; 7263 7264 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7265 if (!dof) continue; 7266 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7267 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7268 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7269 7270 for (r = 0; r < numIndices; r++) { 7271 for (c = 0; c < nCols; c++) { 7272 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7273 } 7274 } 7275 } else { 7276 /* copy this column as is */ 7277 for (r = 0; r < numIndices; r++) { 7278 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7279 } 7280 } 7281 oldOff += dof; 7282 } 7283 } 7284 } else { 7285 PetscInt oldOff = 0; 7286 for (p = 0; p < numPoints; p++) { 7287 PetscInt cStart = newPointOffsets[0][p]; 7288 PetscInt b = points[2 * p]; 7289 PetscInt c, r, k; 7290 PetscInt dof; 7291 7292 PetscCall(PetscSectionGetDof(section, b, &dof)); 7293 if (!dof) continue; 7294 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7295 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7296 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7297 7298 for (r = 0; r < numIndices; r++) { 7299 for (c = 0; c < nCols; c++) { 7300 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7301 } 7302 } 7303 } else { 7304 /* copy this column as is */ 7305 for (r = 0; r < numIndices; r++) { 7306 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7307 } 7308 } 7309 oldOff += dof; 7310 } 7311 } 7312 7313 if (multiplyLeft) { 7314 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7315 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7316 /* multiply constraints transpose on the left */ 7317 if (numFields) { 7318 for (f = 0; f < numFields; f++) { 7319 PetscInt oldOff = offsets[f]; 7320 7321 for (p = 0; p < numPoints; p++) { 7322 PetscInt rStart = newPointOffsets[f][p]; 7323 PetscInt b = points[2 * p]; 7324 PetscInt c, r, k; 7325 PetscInt dof; 7326 7327 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7328 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7329 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7330 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7331 7332 for (r = 0; r < nRows; r++) { 7333 for (c = 0; c < newNumIndices; c++) { 7334 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7335 } 7336 } 7337 } else { 7338 /* copy this row as is */ 7339 for (r = 0; r < dof; r++) { 7340 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7341 } 7342 } 7343 oldOff += dof; 7344 } 7345 } 7346 } else { 7347 PetscInt oldOff = 0; 7348 7349 for (p = 0; p < numPoints; p++) { 7350 PetscInt rStart = newPointOffsets[0][p]; 7351 PetscInt b = points[2 * p]; 7352 PetscInt c, r, k; 7353 PetscInt dof; 7354 7355 PetscCall(PetscSectionGetDof(section, b, &dof)); 7356 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7357 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7358 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7359 7360 for (r = 0; r < nRows; r++) { 7361 for (c = 0; c < newNumIndices; c++) { 7362 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7363 } 7364 } 7365 } else { 7366 /* copy this row as is */ 7367 for (r = 0; r < dof; r++) { 7368 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7369 } 7370 } 7371 oldOff += dof; 7372 } 7373 } 7374 7375 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7376 } else { 7377 newValues = tmpValues; 7378 } 7379 } 7380 7381 /* clean up */ 7382 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7383 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7384 7385 if (numFields) { 7386 for (f = 0; f < numFields; f++) { 7387 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7388 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7389 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7390 } 7391 } else { 7392 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7393 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7394 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7395 } 7396 PetscCall(ISRestoreIndices(aIS, &anchors)); 7397 7398 /* output */ 7399 if (outPoints) { 7400 *outPoints = newPoints; 7401 } else { 7402 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7403 } 7404 if (outValues) *outValues = newValues; 7405 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7406 PetscFunctionReturn(0); 7407 } 7408 7409 /*@C 7410 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7411 7412 Not collective 7413 7414 Input Parameters: 7415 + dm - The DM 7416 . section - The PetscSection describing the points (a local section) 7417 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7418 . point - The point defining the closure 7419 - useClPerm - Use the closure point permutation if available 7420 7421 Output Parameters: 7422 + numIndices - The number of dof indices in the closure of point with the input sections 7423 . indices - The dof indices 7424 . outOffsets - Array to write the field offsets into, or NULL 7425 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7426 7427 Notes: 7428 Must call DMPlexRestoreClosureIndices() to free allocated memory 7429 7430 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7431 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7432 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7433 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7434 indices (with the above semantics) are implied. 7435 7436 Level: advanced 7437 7438 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7439 @*/ 7440 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7441 { 7442 /* Closure ordering */ 7443 PetscSection clSection; 7444 IS clPoints; 7445 const PetscInt *clp; 7446 PetscInt *points; 7447 const PetscInt *clperm = NULL; 7448 /* Dof permutation and sign flips */ 7449 const PetscInt **perms[32] = {NULL}; 7450 const PetscScalar **flips[32] = {NULL}; 7451 PetscScalar *valCopy = NULL; 7452 /* Hanging node constraints */ 7453 PetscInt *pointsC = NULL; 7454 PetscScalar *valuesC = NULL; 7455 PetscInt NclC, NiC; 7456 7457 PetscInt *idx; 7458 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7459 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7460 7461 PetscFunctionBeginHot; 7462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7463 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7464 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7465 if (numIndices) PetscValidIntPointer(numIndices, 6); 7466 if (indices) PetscValidPointer(indices, 7); 7467 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7468 if (values) PetscValidPointer(values, 9); 7469 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7470 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7471 PetscCall(PetscArrayzero(offsets, 32)); 7472 /* 1) Get points in closure */ 7473 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7474 if (useClPerm) { 7475 PetscInt depth, clsize; 7476 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7477 for (clsize = 0, p = 0; p < Ncl; p++) { 7478 PetscInt dof; 7479 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7480 clsize += dof; 7481 } 7482 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7483 } 7484 /* 2) Get number of indices on these points and field offsets from section */ 7485 for (p = 0; p < Ncl * 2; p += 2) { 7486 PetscInt dof, fdof; 7487 7488 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7489 for (f = 0; f < Nf; ++f) { 7490 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7491 offsets[f + 1] += fdof; 7492 } 7493 Ni += dof; 7494 } 7495 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7496 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7497 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7498 for (f = 0; f < PetscMax(1, Nf); ++f) { 7499 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7500 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7501 /* may need to apply sign changes to the element matrix */ 7502 if (values && flips[f]) { 7503 PetscInt foffset = offsets[f]; 7504 7505 for (p = 0; p < Ncl; ++p) { 7506 PetscInt pnt = points[2 * p], fdof; 7507 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7508 7509 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7510 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7511 if (flip) { 7512 PetscInt i, j, k; 7513 7514 if (!valCopy) { 7515 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7516 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7517 *values = valCopy; 7518 } 7519 for (i = 0; i < fdof; ++i) { 7520 PetscScalar fval = flip[i]; 7521 7522 for (k = 0; k < Ni; ++k) { 7523 valCopy[Ni * (foffset + i) + k] *= fval; 7524 valCopy[Ni * k + (foffset + i)] *= fval; 7525 } 7526 } 7527 } 7528 foffset += fdof; 7529 } 7530 } 7531 } 7532 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7533 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7534 if (NclC) { 7535 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7536 for (f = 0; f < PetscMax(1, Nf); ++f) { 7537 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7538 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7539 } 7540 for (f = 0; f < PetscMax(1, Nf); ++f) { 7541 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7542 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7543 } 7544 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7545 Ncl = NclC; 7546 Ni = NiC; 7547 points = pointsC; 7548 if (values) *values = valuesC; 7549 } 7550 /* 5) Calculate indices */ 7551 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7552 if (Nf) { 7553 PetscInt idxOff; 7554 PetscBool useFieldOffsets; 7555 7556 if (outOffsets) { 7557 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7558 } 7559 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7560 if (useFieldOffsets) { 7561 for (p = 0; p < Ncl; ++p) { 7562 const PetscInt pnt = points[p * 2]; 7563 7564 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7565 } 7566 } else { 7567 for (p = 0; p < Ncl; ++p) { 7568 const PetscInt pnt = points[p * 2]; 7569 7570 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7571 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7572 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7573 * global section. */ 7574 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7575 } 7576 } 7577 } else { 7578 PetscInt off = 0, idxOff; 7579 7580 for (p = 0; p < Ncl; ++p) { 7581 const PetscInt pnt = points[p * 2]; 7582 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7583 7584 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7585 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7586 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7587 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7588 } 7589 } 7590 /* 6) Cleanup */ 7591 for (f = 0; f < PetscMax(1, Nf); ++f) { 7592 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7593 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7594 } 7595 if (NclC) { 7596 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7597 } else { 7598 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7599 } 7600 7601 if (numIndices) *numIndices = Ni; 7602 if (indices) *indices = idx; 7603 PetscFunctionReturn(0); 7604 } 7605 7606 /*@C 7607 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7608 7609 Not collective 7610 7611 Input Parameters: 7612 + dm - The DM 7613 . section - The PetscSection describing the points (a local section) 7614 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7615 . point - The point defining the closure 7616 - useClPerm - Use the closure point permutation if available 7617 7618 Output Parameters: 7619 + numIndices - The number of dof indices in the closure of point with the input sections 7620 . indices - The dof indices 7621 . outOffsets - Array to write the field offsets into, or NULL 7622 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7623 7624 Notes: 7625 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7626 7627 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7628 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7629 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7630 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7631 indices (with the above semantics) are implied. 7632 7633 Level: advanced 7634 7635 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7636 @*/ 7637 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7638 { 7639 PetscFunctionBegin; 7640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7641 PetscValidPointer(indices, 7); 7642 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7643 PetscFunctionReturn(0); 7644 } 7645 7646 /*@C 7647 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7648 7649 Not collective 7650 7651 Input Parameters: 7652 + dm - The DM 7653 . section - The section describing the layout in v, or NULL to use the default section 7654 . globalSection - The section describing the layout in v, or NULL to use the default global section 7655 . A - The matrix 7656 . point - The point in the DM 7657 . values - The array of values 7658 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7659 7660 Fortran Notes: 7661 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7662 7663 Level: intermediate 7664 7665 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7666 @*/ 7667 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7668 { 7669 DM_Plex *mesh = (DM_Plex *)dm->data; 7670 PetscInt *indices; 7671 PetscInt numIndices; 7672 const PetscScalar *valuesOrig = values; 7673 PetscErrorCode ierr; 7674 7675 PetscFunctionBegin; 7676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7677 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7678 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7679 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7680 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7681 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7682 7683 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7684 7685 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7686 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7687 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7688 if (ierr) { 7689 PetscMPIInt rank; 7690 7691 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7692 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7693 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7694 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7695 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7696 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7697 } 7698 if (mesh->printFEM > 1) { 7699 PetscInt i; 7700 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7701 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7702 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7703 } 7704 7705 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7706 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7707 PetscFunctionReturn(0); 7708 } 7709 7710 /*@C 7711 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7712 7713 Not collective 7714 7715 Input Parameters: 7716 + dmRow - The DM for the row fields 7717 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7718 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7719 . dmCol - The DM for the column fields 7720 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7721 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7722 . A - The matrix 7723 . point - The point in the DMs 7724 . values - The array of values 7725 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7726 7727 Level: intermediate 7728 7729 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7730 @*/ 7731 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7732 { 7733 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7734 PetscInt *indicesRow, *indicesCol; 7735 PetscInt numIndicesRow, numIndicesCol; 7736 const PetscScalar *valuesOrig = values; 7737 PetscErrorCode ierr; 7738 7739 PetscFunctionBegin; 7740 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7741 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7742 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7743 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7744 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7745 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7746 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7747 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7748 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7749 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7750 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7751 7752 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7753 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7754 7755 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7756 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7757 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7758 if (ierr) { 7759 PetscMPIInt rank; 7760 7761 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7762 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7763 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7764 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7765 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7766 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7767 } 7768 7769 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7770 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7771 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7772 PetscFunctionReturn(0); 7773 } 7774 7775 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7776 { 7777 DM_Plex *mesh = (DM_Plex *)dmf->data; 7778 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7779 PetscInt *cpoints = NULL; 7780 PetscInt *findices, *cindices; 7781 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7782 PetscInt foffsets[32], coffsets[32]; 7783 DMPolytopeType ct; 7784 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7785 PetscErrorCode ierr; 7786 7787 PetscFunctionBegin; 7788 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7789 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7790 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7791 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7792 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7793 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7794 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7795 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7796 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7797 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7798 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7799 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7800 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7801 PetscCall(PetscArrayzero(foffsets, 32)); 7802 PetscCall(PetscArrayzero(coffsets, 32)); 7803 /* Column indices */ 7804 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7805 maxFPoints = numCPoints; 7806 /* Compress out points not in the section */ 7807 /* TODO: Squeeze out points with 0 dof as well */ 7808 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7809 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7810 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7811 cpoints[q * 2] = cpoints[p]; 7812 cpoints[q * 2 + 1] = cpoints[p + 1]; 7813 ++q; 7814 } 7815 } 7816 numCPoints = q; 7817 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7818 PetscInt fdof; 7819 7820 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7821 if (!dof) continue; 7822 for (f = 0; f < numFields; ++f) { 7823 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7824 coffsets[f + 1] += fdof; 7825 } 7826 numCIndices += dof; 7827 } 7828 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7829 /* Row indices */ 7830 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7831 { 7832 DMPlexTransform tr; 7833 DMPolytopeType *rct; 7834 PetscInt *rsize, *rcone, *rornt, Nt; 7835 7836 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7837 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7838 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7839 numSubcells = rsize[Nt - 1]; 7840 PetscCall(DMPlexTransformDestroy(&tr)); 7841 } 7842 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7843 for (r = 0, q = 0; r < numSubcells; ++r) { 7844 /* TODO Map from coarse to fine cells */ 7845 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7846 /* Compress out points not in the section */ 7847 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7848 for (p = 0; p < numFPoints * 2; p += 2) { 7849 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7850 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7851 if (!dof) continue; 7852 for (s = 0; s < q; ++s) 7853 if (fpoints[p] == ftotpoints[s * 2]) break; 7854 if (s < q) continue; 7855 ftotpoints[q * 2] = fpoints[p]; 7856 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7857 ++q; 7858 } 7859 } 7860 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7861 } 7862 numFPoints = q; 7863 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7864 PetscInt fdof; 7865 7866 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7867 if (!dof) continue; 7868 for (f = 0; f < numFields; ++f) { 7869 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7870 foffsets[f + 1] += fdof; 7871 } 7872 numFIndices += dof; 7873 } 7874 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7875 7876 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7877 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7878 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7879 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7880 if (numFields) { 7881 const PetscInt **permsF[32] = {NULL}; 7882 const PetscInt **permsC[32] = {NULL}; 7883 7884 for (f = 0; f < numFields; f++) { 7885 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7886 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7887 } 7888 for (p = 0; p < numFPoints; p++) { 7889 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7890 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7891 } 7892 for (p = 0; p < numCPoints; p++) { 7893 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7894 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7895 } 7896 for (f = 0; f < numFields; f++) { 7897 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7898 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7899 } 7900 } else { 7901 const PetscInt **permsF = NULL; 7902 const PetscInt **permsC = NULL; 7903 7904 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7905 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7906 for (p = 0, off = 0; p < numFPoints; p++) { 7907 const PetscInt *perm = permsF ? permsF[p] : NULL; 7908 7909 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7910 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7911 } 7912 for (p = 0, off = 0; p < numCPoints; p++) { 7913 const PetscInt *perm = permsC ? permsC[p] : NULL; 7914 7915 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7916 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7917 } 7918 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7919 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7920 } 7921 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7922 /* TODO: flips */ 7923 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7924 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7925 if (ierr) { 7926 PetscMPIInt rank; 7927 7928 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7929 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7930 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7931 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7932 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7933 } 7934 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7935 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7936 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7937 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7938 PetscFunctionReturn(0); 7939 } 7940 7941 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7942 { 7943 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7944 PetscInt *cpoints = NULL; 7945 PetscInt foffsets[32], coffsets[32]; 7946 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7947 DMPolytopeType ct; 7948 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7949 7950 PetscFunctionBegin; 7951 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7952 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7953 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7954 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7955 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7956 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7957 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7958 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7959 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7960 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7961 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7962 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7963 PetscCall(PetscArrayzero(foffsets, 32)); 7964 PetscCall(PetscArrayzero(coffsets, 32)); 7965 /* Column indices */ 7966 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7967 maxFPoints = numCPoints; 7968 /* Compress out points not in the section */ 7969 /* TODO: Squeeze out points with 0 dof as well */ 7970 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7971 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7972 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7973 cpoints[q * 2] = cpoints[p]; 7974 cpoints[q * 2 + 1] = cpoints[p + 1]; 7975 ++q; 7976 } 7977 } 7978 numCPoints = q; 7979 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7980 PetscInt fdof; 7981 7982 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7983 if (!dof) continue; 7984 for (f = 0; f < numFields; ++f) { 7985 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7986 coffsets[f + 1] += fdof; 7987 } 7988 numCIndices += dof; 7989 } 7990 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7991 /* Row indices */ 7992 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7993 { 7994 DMPlexTransform tr; 7995 DMPolytopeType *rct; 7996 PetscInt *rsize, *rcone, *rornt, Nt; 7997 7998 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7999 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 8000 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 8001 numSubcells = rsize[Nt - 1]; 8002 PetscCall(DMPlexTransformDestroy(&tr)); 8003 } 8004 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 8005 for (r = 0, q = 0; r < numSubcells; ++r) { 8006 /* TODO Map from coarse to fine cells */ 8007 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 8008 /* Compress out points not in the section */ 8009 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 8010 for (p = 0; p < numFPoints * 2; p += 2) { 8011 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 8012 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 8013 if (!dof) continue; 8014 for (s = 0; s < q; ++s) 8015 if (fpoints[p] == ftotpoints[s * 2]) break; 8016 if (s < q) continue; 8017 ftotpoints[q * 2] = fpoints[p]; 8018 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 8019 ++q; 8020 } 8021 } 8022 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 8023 } 8024 numFPoints = q; 8025 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 8026 PetscInt fdof; 8027 8028 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 8029 if (!dof) continue; 8030 for (f = 0; f < numFields; ++f) { 8031 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 8032 foffsets[f + 1] += fdof; 8033 } 8034 numFIndices += dof; 8035 } 8036 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 8037 8038 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 8039 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 8040 if (numFields) { 8041 const PetscInt **permsF[32] = {NULL}; 8042 const PetscInt **permsC[32] = {NULL}; 8043 8044 for (f = 0; f < numFields; f++) { 8045 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8046 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8047 } 8048 for (p = 0; p < numFPoints; p++) { 8049 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8050 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 8051 } 8052 for (p = 0; p < numCPoints; p++) { 8053 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8054 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 8055 } 8056 for (f = 0; f < numFields; f++) { 8057 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 8058 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 8059 } 8060 } else { 8061 const PetscInt **permsF = NULL; 8062 const PetscInt **permsC = NULL; 8063 8064 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8065 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8066 for (p = 0, off = 0; p < numFPoints; p++) { 8067 const PetscInt *perm = permsF ? permsF[p] : NULL; 8068 8069 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 8070 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 8071 } 8072 for (p = 0, off = 0; p < numCPoints; p++) { 8073 const PetscInt *perm = permsC ? permsC[p] : NULL; 8074 8075 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 8076 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 8077 } 8078 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 8079 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 8080 } 8081 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 8082 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 8083 PetscFunctionReturn(0); 8084 } 8085 8086 /*@C 8087 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 8088 8089 Input Parameter: 8090 . dm - The DMPlex object 8091 8092 Output Parameter: 8093 . cellHeight - The height of a cell 8094 8095 Level: developer 8096 8097 .seealso `DMPlexSetVTKCellHeight()` 8098 @*/ 8099 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 8100 { 8101 DM_Plex *mesh = (DM_Plex *)dm->data; 8102 8103 PetscFunctionBegin; 8104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8105 PetscValidIntPointer(cellHeight, 2); 8106 *cellHeight = mesh->vtkCellHeight; 8107 PetscFunctionReturn(0); 8108 } 8109 8110 /*@C 8111 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 8112 8113 Input Parameters: 8114 + dm - The DMPlex object 8115 - cellHeight - The height of a cell 8116 8117 Level: developer 8118 8119 .seealso `DMPlexGetVTKCellHeight()` 8120 @*/ 8121 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 8122 { 8123 DM_Plex *mesh = (DM_Plex *)dm->data; 8124 8125 PetscFunctionBegin; 8126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8127 mesh->vtkCellHeight = cellHeight; 8128 PetscFunctionReturn(0); 8129 } 8130 8131 /*@ 8132 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 8133 8134 Input Parameter: 8135 . dm - The DMPlex object 8136 8137 Output Parameters: 8138 + gcStart - The first ghost cell, or NULL 8139 - gcEnd - The upper bound on ghost cells, or NULL 8140 8141 Level: advanced 8142 8143 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 8144 @*/ 8145 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 8146 { 8147 DMLabel ctLabel; 8148 8149 PetscFunctionBegin; 8150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8151 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 8152 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 8153 // Reset label for fast lookup 8154 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 8155 PetscFunctionReturn(0); 8156 } 8157 8158 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8159 { 8160 PetscSection section, globalSection; 8161 PetscInt *numbers, p; 8162 8163 PetscFunctionBegin; 8164 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 8165 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8166 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8167 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 8168 PetscCall(PetscSectionSetUp(section)); 8169 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8170 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8171 for (p = pStart; p < pEnd; ++p) { 8172 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 8173 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 8174 else numbers[p - pStart] += shift; 8175 } 8176 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8177 if (globalSize) { 8178 PetscLayout layout; 8179 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 8180 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8181 PetscCall(PetscLayoutDestroy(&layout)); 8182 } 8183 PetscCall(PetscSectionDestroy(§ion)); 8184 PetscCall(PetscSectionDestroy(&globalSection)); 8185 PetscFunctionReturn(0); 8186 } 8187 8188 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8189 { 8190 PetscInt cellHeight, cStart, cEnd; 8191 8192 PetscFunctionBegin; 8193 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8194 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8195 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8196 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8197 PetscFunctionReturn(0); 8198 } 8199 8200 /*@ 8201 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8202 8203 Input Parameter: 8204 . dm - The DMPlex object 8205 8206 Output Parameter: 8207 . globalCellNumbers - Global cell numbers for all cells on this process 8208 8209 Level: developer 8210 8211 .seealso `DMPlexGetVertexNumbering()` 8212 @*/ 8213 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8214 { 8215 DM_Plex *mesh = (DM_Plex *)dm->data; 8216 8217 PetscFunctionBegin; 8218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8219 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8220 *globalCellNumbers = mesh->globalCellNumbers; 8221 PetscFunctionReturn(0); 8222 } 8223 8224 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8225 { 8226 PetscInt vStart, vEnd; 8227 8228 PetscFunctionBegin; 8229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8230 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8231 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8232 PetscFunctionReturn(0); 8233 } 8234 8235 /*@ 8236 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8237 8238 Input Parameter: 8239 . dm - The DMPlex object 8240 8241 Output Parameter: 8242 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8243 8244 Level: developer 8245 8246 .seealso `DMPlexGetCellNumbering()` 8247 @*/ 8248 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8249 { 8250 DM_Plex *mesh = (DM_Plex *)dm->data; 8251 8252 PetscFunctionBegin; 8253 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8254 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8255 *globalVertexNumbers = mesh->globalVertexNumbers; 8256 PetscFunctionReturn(0); 8257 } 8258 8259 /*@ 8260 DMPlexCreatePointNumbering - Create a global numbering for all points. 8261 8262 Collective on dm 8263 8264 Input Parameter: 8265 . dm - The DMPlex object 8266 8267 Output Parameter: 8268 . globalPointNumbers - Global numbers for all points on this process 8269 8270 Notes: 8271 8272 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8273 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8274 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8275 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8276 8277 The partitioned mesh is 8278 ``` 8279 (2)--0--(3)--1--(4) (1)--0--(2) 8280 ``` 8281 and its global numbering is 8282 ``` 8283 (3)--0--(4)--1--(5)--2--(6) 8284 ``` 8285 Then the global numbering is provided as 8286 ``` 8287 [0] Number of indices in set 5 8288 [0] 0 0 8289 [0] 1 1 8290 [0] 2 3 8291 [0] 3 4 8292 [0] 4 -6 8293 [1] Number of indices in set 3 8294 [1] 0 2 8295 [1] 1 5 8296 [1] 2 6 8297 ``` 8298 8299 Level: developer 8300 8301 .seealso `DMPlexGetCellNumbering()` 8302 @*/ 8303 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8304 { 8305 IS nums[4]; 8306 PetscInt depths[4], gdepths[4], starts[4]; 8307 PetscInt depth, d, shift = 0; 8308 PetscBool empty = PETSC_FALSE; 8309 8310 PetscFunctionBegin; 8311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8312 PetscCall(DMPlexGetDepth(dm, &depth)); 8313 // For unstratified meshes use dim instead of depth 8314 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8315 // If any stratum is empty, we must mark all empty 8316 for (d = 0; d <= depth; ++d) { 8317 PetscInt end; 8318 8319 depths[d] = depth - d; 8320 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8321 if (!(starts[d] - end)) empty = PETSC_TRUE; 8322 } 8323 if (empty) 8324 for (d = 0; d <= depth; ++d) { 8325 depths[d] = -1; 8326 starts[d] = -1; 8327 } 8328 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8329 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8330 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]); 8331 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8332 for (d = 0; d <= depth; ++d) { 8333 PetscInt pStart, pEnd, gsize; 8334 8335 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8336 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8337 shift += gsize; 8338 } 8339 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8340 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8341 PetscFunctionReturn(0); 8342 } 8343 8344 /*@ 8345 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8346 8347 Input Parameter: 8348 . dm - The DMPlex object 8349 8350 Output Parameter: 8351 . ranks - The rank field 8352 8353 Options Database Keys: 8354 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8355 8356 Level: intermediate 8357 8358 .seealso: `DMView()` 8359 @*/ 8360 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8361 { 8362 DM rdm; 8363 PetscFE fe; 8364 PetscScalar *r; 8365 PetscMPIInt rank; 8366 DMPolytopeType ct; 8367 PetscInt dim, cStart, cEnd, c; 8368 PetscBool simplex; 8369 8370 PetscFunctionBeginUser; 8371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8372 PetscValidPointer(ranks, 2); 8373 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8374 PetscCall(DMClone(dm, &rdm)); 8375 PetscCall(DMGetDimension(rdm, &dim)); 8376 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8377 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8378 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8379 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8380 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8381 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8382 PetscCall(PetscFEDestroy(&fe)); 8383 PetscCall(DMCreateDS(rdm)); 8384 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8385 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8386 PetscCall(VecGetArray(*ranks, &r)); 8387 for (c = cStart; c < cEnd; ++c) { 8388 PetscScalar *lr; 8389 8390 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8391 if (lr) *lr = rank; 8392 } 8393 PetscCall(VecRestoreArray(*ranks, &r)); 8394 PetscCall(DMDestroy(&rdm)); 8395 PetscFunctionReturn(0); 8396 } 8397 8398 /*@ 8399 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8400 8401 Input Parameters: 8402 + dm - The DMPlex 8403 - label - The DMLabel 8404 8405 Output Parameter: 8406 . val - The label value field 8407 8408 Options Database Keys: 8409 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8410 8411 Level: intermediate 8412 8413 .seealso: `DMView()` 8414 @*/ 8415 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8416 { 8417 DM rdm; 8418 PetscFE fe; 8419 PetscScalar *v; 8420 PetscInt dim, cStart, cEnd, c; 8421 8422 PetscFunctionBeginUser; 8423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8424 PetscValidPointer(label, 2); 8425 PetscValidPointer(val, 3); 8426 PetscCall(DMClone(dm, &rdm)); 8427 PetscCall(DMGetDimension(rdm, &dim)); 8428 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8429 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8430 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8431 PetscCall(PetscFEDestroy(&fe)); 8432 PetscCall(DMCreateDS(rdm)); 8433 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8434 PetscCall(DMCreateGlobalVector(rdm, val)); 8435 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8436 PetscCall(VecGetArray(*val, &v)); 8437 for (c = cStart; c < cEnd; ++c) { 8438 PetscScalar *lv; 8439 PetscInt cval; 8440 8441 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8442 PetscCall(DMLabelGetValue(label, c, &cval)); 8443 *lv = cval; 8444 } 8445 PetscCall(VecRestoreArray(*val, &v)); 8446 PetscCall(DMDestroy(&rdm)); 8447 PetscFunctionReturn(0); 8448 } 8449 8450 /*@ 8451 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8452 8453 Input Parameter: 8454 . dm - The DMPlex object 8455 8456 Notes: 8457 This is a useful diagnostic when creating meshes programmatically. 8458 8459 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8460 8461 Level: developer 8462 8463 .seealso: `DMCreate()`, `DMSetFromOptions()` 8464 @*/ 8465 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8466 { 8467 PetscSection coneSection, supportSection; 8468 const PetscInt *cone, *support; 8469 PetscInt coneSize, c, supportSize, s; 8470 PetscInt pStart, pEnd, p, pp, csize, ssize; 8471 PetscBool storagecheck = PETSC_TRUE; 8472 8473 PetscFunctionBegin; 8474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8475 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8476 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8477 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8478 /* Check that point p is found in the support of its cone points, and vice versa */ 8479 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8480 for (p = pStart; p < pEnd; ++p) { 8481 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8482 PetscCall(DMPlexGetCone(dm, p, &cone)); 8483 for (c = 0; c < coneSize; ++c) { 8484 PetscBool dup = PETSC_FALSE; 8485 PetscInt d; 8486 for (d = c - 1; d >= 0; --d) { 8487 if (cone[c] == cone[d]) { 8488 dup = PETSC_TRUE; 8489 break; 8490 } 8491 } 8492 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8493 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8494 for (s = 0; s < supportSize; ++s) { 8495 if (support[s] == p) break; 8496 } 8497 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8498 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8499 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8500 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8501 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8502 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8503 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8504 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]); 8505 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8506 } 8507 } 8508 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8509 if (p != pp) { 8510 storagecheck = PETSC_FALSE; 8511 continue; 8512 } 8513 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8514 PetscCall(DMPlexGetSupport(dm, p, &support)); 8515 for (s = 0; s < supportSize; ++s) { 8516 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8517 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8518 for (c = 0; c < coneSize; ++c) { 8519 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8520 if (cone[c] != pp) { 8521 c = 0; 8522 break; 8523 } 8524 if (cone[c] == p) break; 8525 } 8526 if (c >= coneSize) { 8527 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8528 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8529 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8530 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8531 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8532 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8533 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8534 } 8535 } 8536 } 8537 if (storagecheck) { 8538 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8539 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8540 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8541 } 8542 PetscFunctionReturn(0); 8543 } 8544 8545 /* 8546 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. 8547 */ 8548 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8549 { 8550 DMPolytopeType cct; 8551 PetscInt ptpoints[4]; 8552 const PetscInt *cone, *ccone, *ptcone; 8553 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8554 8555 PetscFunctionBegin; 8556 *unsplit = 0; 8557 switch (ct) { 8558 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8559 ptpoints[npt++] = c; 8560 break; 8561 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8562 PetscCall(DMPlexGetCone(dm, c, &cone)); 8563 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8564 for (cp = 0; cp < coneSize; ++cp) { 8565 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8566 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8567 } 8568 break; 8569 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8570 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8571 PetscCall(DMPlexGetCone(dm, c, &cone)); 8572 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8573 for (cp = 0; cp < coneSize; ++cp) { 8574 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8575 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8576 for (ccp = 0; ccp < cconeSize; ++ccp) { 8577 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8578 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8579 PetscInt p; 8580 for (p = 0; p < npt; ++p) 8581 if (ptpoints[p] == ccone[ccp]) break; 8582 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8583 } 8584 } 8585 } 8586 break; 8587 default: 8588 break; 8589 } 8590 for (pt = 0; pt < npt; ++pt) { 8591 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8592 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8593 } 8594 PetscFunctionReturn(0); 8595 } 8596 8597 /*@ 8598 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8599 8600 Input Parameters: 8601 + dm - The DMPlex object 8602 - cellHeight - Normally 0 8603 8604 Notes: 8605 This is a useful diagnostic when creating meshes programmatically. 8606 Currently applicable only to homogeneous simplex or tensor meshes. 8607 8608 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8609 8610 Level: developer 8611 8612 .seealso: `DMCreate()`, `DMSetFromOptions()` 8613 @*/ 8614 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8615 { 8616 DMPlexInterpolatedFlag interp; 8617 DMPolytopeType ct; 8618 PetscInt vStart, vEnd, cStart, cEnd, c; 8619 8620 PetscFunctionBegin; 8621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8622 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8623 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8624 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8625 for (c = cStart; c < cEnd; ++c) { 8626 PetscInt *closure = NULL; 8627 PetscInt coneSize, closureSize, cl, Nv = 0; 8628 8629 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8630 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8631 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8632 if (interp == DMPLEX_INTERPOLATED_FULL) { 8633 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8634 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)); 8635 } 8636 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8637 for (cl = 0; cl < closureSize * 2; cl += 2) { 8638 const PetscInt p = closure[cl]; 8639 if ((p >= vStart) && (p < vEnd)) ++Nv; 8640 } 8641 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8642 /* Special Case: Tensor faces with identified vertices */ 8643 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8644 PetscInt unsplit; 8645 8646 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8647 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8648 } 8649 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)); 8650 } 8651 PetscFunctionReturn(0); 8652 } 8653 8654 /*@ 8655 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8656 8657 Collective 8658 8659 Input Parameters: 8660 + dm - The DMPlex object 8661 - cellHeight - Normally 0 8662 8663 Notes: 8664 This is a useful diagnostic when creating meshes programmatically. 8665 This routine is only relevant for meshes that are fully interpolated across all ranks. 8666 It will error out if a partially interpolated mesh is given on some rank. 8667 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8668 8669 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8670 8671 Level: developer 8672 8673 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8674 @*/ 8675 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8676 { 8677 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8678 DMPlexInterpolatedFlag interpEnum; 8679 8680 PetscFunctionBegin; 8681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8682 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8683 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8684 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8685 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8686 PetscFunctionReturn(0); 8687 } 8688 8689 PetscCall(DMGetDimension(dm, &dim)); 8690 PetscCall(DMPlexGetDepth(dm, &depth)); 8691 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8692 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8693 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8694 for (c = cStart; c < cEnd; ++c) { 8695 const PetscInt *cone, *ornt, *faceSizes, *faces; 8696 const DMPolytopeType *faceTypes; 8697 DMPolytopeType ct; 8698 PetscInt numFaces, coneSize, f; 8699 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8700 8701 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8702 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8703 if (unsplit) continue; 8704 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8705 PetscCall(DMPlexGetCone(dm, c, &cone)); 8706 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8707 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8708 for (cl = 0; cl < closureSize * 2; cl += 2) { 8709 const PetscInt p = closure[cl]; 8710 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8711 } 8712 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8713 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); 8714 for (f = 0; f < numFaces; ++f) { 8715 DMPolytopeType fct; 8716 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8717 8718 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8719 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8720 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8721 const PetscInt p = fclosure[cl]; 8722 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8723 } 8724 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]); 8725 for (v = 0; v < fnumCorners; ++v) { 8726 if (fclosure[v] != faces[fOff + v]) { 8727 PetscInt v1; 8728 8729 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8730 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8731 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8732 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8733 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8734 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]); 8735 } 8736 } 8737 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8738 fOff += faceSizes[f]; 8739 } 8740 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8741 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8742 } 8743 } 8744 PetscFunctionReturn(0); 8745 } 8746 8747 /*@ 8748 DMPlexCheckGeometry - Check the geometry of mesh cells 8749 8750 Input Parameter: 8751 . dm - The DMPlex object 8752 8753 Notes: 8754 This is a useful diagnostic when creating meshes programmatically. 8755 8756 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8757 8758 Level: developer 8759 8760 .seealso: `DMCreate()`, `DMSetFromOptions()` 8761 @*/ 8762 PetscErrorCode DMPlexCheckGeometry(DM dm) 8763 { 8764 Vec coordinates; 8765 PetscReal detJ, J[9], refVol = 1.0; 8766 PetscReal vol; 8767 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8768 8769 PetscFunctionBegin; 8770 PetscCall(DMGetDimension(dm, &dim)); 8771 PetscCall(DMGetCoordinateDim(dm, &dE)); 8772 if (dim != dE) PetscFunctionReturn(0); 8773 PetscCall(DMPlexGetDepth(dm, &depth)); 8774 for (d = 0; d < dim; ++d) refVol *= 2.0; 8775 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8776 /* Make sure local coordinates are created, because that step is collective */ 8777 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8778 for (c = cStart; c < cEnd; ++c) { 8779 DMPolytopeType ct; 8780 PetscInt unsplit; 8781 PetscBool ignoreZeroVol = PETSC_FALSE; 8782 8783 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8784 switch (ct) { 8785 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8786 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8787 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8788 ignoreZeroVol = PETSC_TRUE; 8789 break; 8790 default: 8791 break; 8792 } 8793 switch (ct) { 8794 case DM_POLYTOPE_TRI_PRISM: 8795 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8796 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8797 case DM_POLYTOPE_PYRAMID: 8798 continue; 8799 default: 8800 break; 8801 } 8802 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8803 if (unsplit) continue; 8804 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8805 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); 8806 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8807 /* This should work with periodicity since DG coordinates should be used */ 8808 if (depth > 1) { 8809 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8810 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); 8811 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8812 } 8813 } 8814 PetscFunctionReturn(0); 8815 } 8816 8817 /*@ 8818 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8819 8820 Collective 8821 8822 Input Parameters: 8823 + dm - The DMPlex object 8824 . pointSF - The Point SF, or NULL for Point SF attached to DM 8825 - allowExtraRoots - Flag to allow extra points not present in the DM 8826 8827 Notes: 8828 This is mainly intended for debugging/testing purposes. 8829 8830 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8831 8832 Extra roots can come from priodic cuts, where additional points appear on the boundary 8833 8834 Level: developer 8835 8836 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8837 @*/ 8838 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) 8839 { 8840 PetscInt l, nleaves, nroots, overlap; 8841 const PetscInt *locals; 8842 const PetscSFNode *remotes; 8843 PetscBool distributed; 8844 MPI_Comm comm; 8845 PetscMPIInt rank; 8846 8847 PetscFunctionBegin; 8848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8849 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8850 else pointSF = dm->sf; 8851 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8852 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8853 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8854 { 8855 PetscMPIInt mpiFlag; 8856 8857 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8858 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8859 } 8860 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8861 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8862 if (!distributed) { 8863 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); 8864 PetscFunctionReturn(0); 8865 } 8866 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); 8867 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8868 8869 /* Check SF graph is compatible with DMPlex chart */ 8870 { 8871 PetscInt pStart, pEnd, maxLeaf; 8872 8873 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8874 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8875 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8876 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8877 } 8878 8879 /* Check Point SF has no local points referenced */ 8880 for (l = 0; l < nleaves; l++) { 8881 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); 8882 } 8883 8884 /* Check there are no cells in interface */ 8885 if (!overlap) { 8886 PetscInt cellHeight, cStart, cEnd; 8887 8888 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8889 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8890 for (l = 0; l < nleaves; ++l) { 8891 const PetscInt point = locals ? locals[l] : l; 8892 8893 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8894 } 8895 } 8896 8897 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8898 { 8899 const PetscInt *rootdegree; 8900 8901 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8902 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8903 for (l = 0; l < nleaves; ++l) { 8904 const PetscInt point = locals ? locals[l] : l; 8905 const PetscInt *cone; 8906 PetscInt coneSize, c, idx; 8907 8908 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8909 PetscCall(DMPlexGetCone(dm, point, &cone)); 8910 for (c = 0; c < coneSize; ++c) { 8911 if (!rootdegree[cone[c]]) { 8912 if (locals) { 8913 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8914 } else { 8915 idx = (cone[c] < nleaves) ? cone[c] : -1; 8916 } 8917 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8918 } 8919 } 8920 } 8921 } 8922 PetscFunctionReturn(0); 8923 } 8924 8925 /*@ 8926 DMPlexCheck - Perform various checks of Plex sanity 8927 8928 Input Parameter: 8929 . dm - The DMPlex object 8930 8931 Notes: 8932 This is a useful diagnostic when creating meshes programmatically. 8933 8934 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8935 8936 Currently does not include DMPlexCheckCellShape(). 8937 8938 Level: developer 8939 8940 .seealso: DMCreate(), DMSetFromOptions() 8941 @*/ 8942 PetscErrorCode DMPlexCheck(DM dm) 8943 { 8944 PetscInt cellHeight; 8945 8946 PetscFunctionBegin; 8947 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8948 PetscCall(DMPlexCheckSymmetry(dm)); 8949 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8950 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8951 PetscCall(DMPlexCheckGeometry(dm)); 8952 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 8953 PetscCall(DMPlexCheckInterfaceCones(dm)); 8954 PetscFunctionReturn(0); 8955 } 8956 8957 typedef struct cell_stats { 8958 PetscReal min, max, sum, squaresum; 8959 PetscInt count; 8960 } cell_stats_t; 8961 8962 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) 8963 { 8964 PetscInt i, N = *len; 8965 8966 for (i = 0; i < N; i++) { 8967 cell_stats_t *A = (cell_stats_t *)a; 8968 cell_stats_t *B = (cell_stats_t *)b; 8969 8970 B->min = PetscMin(A->min, B->min); 8971 B->max = PetscMax(A->max, B->max); 8972 B->sum += A->sum; 8973 B->squaresum += A->squaresum; 8974 B->count += A->count; 8975 } 8976 } 8977 8978 /*@ 8979 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8980 8981 Collective on dm 8982 8983 Input Parameters: 8984 + dm - The DMPlex object 8985 . output - If true, statistics will be displayed on stdout 8986 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8987 8988 Notes: 8989 This is mainly intended for debugging/testing purposes. 8990 8991 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8992 8993 Level: developer 8994 8995 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8996 @*/ 8997 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8998 { 8999 DM dmCoarse; 9000 cell_stats_t stats, globalStats; 9001 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 9002 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 9003 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 9004 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 9005 PetscMPIInt rank, size; 9006 9007 PetscFunctionBegin; 9008 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9009 stats.min = PETSC_MAX_REAL; 9010 stats.max = PETSC_MIN_REAL; 9011 stats.sum = stats.squaresum = 0.; 9012 stats.count = 0; 9013 9014 PetscCallMPI(MPI_Comm_size(comm, &size)); 9015 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9016 PetscCall(DMGetCoordinateDim(dm, &cdim)); 9017 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 9018 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 9019 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 9020 for (c = cStart; c < cEnd; c++) { 9021 PetscInt i; 9022 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 9023 9024 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 9025 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 9026 for (i = 0; i < PetscSqr(cdim); ++i) { 9027 frobJ += J[i] * J[i]; 9028 frobInvJ += invJ[i] * invJ[i]; 9029 } 9030 cond2 = frobJ * frobInvJ; 9031 cond = PetscSqrtReal(cond2); 9032 9033 stats.min = PetscMin(stats.min, cond); 9034 stats.max = PetscMax(stats.max, cond); 9035 stats.sum += cond; 9036 stats.squaresum += cond2; 9037 stats.count++; 9038 if (output && cond > limit) { 9039 PetscSection coordSection; 9040 Vec coordsLocal; 9041 PetscScalar *coords = NULL; 9042 PetscInt Nv, d, clSize, cl, *closure = NULL; 9043 9044 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9045 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 9046 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9047 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 9048 for (i = 0; i < Nv / cdim; ++i) { 9049 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 9050 for (d = 0; d < cdim; ++d) { 9051 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 9052 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 9053 } 9054 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 9055 } 9056 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9057 for (cl = 0; cl < clSize * 2; cl += 2) { 9058 const PetscInt edge = closure[cl]; 9059 9060 if ((edge >= eStart) && (edge < eEnd)) { 9061 PetscReal len; 9062 9063 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 9064 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 9065 } 9066 } 9067 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 9068 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 9069 } 9070 } 9071 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 9072 9073 if (size > 1) { 9074 PetscMPIInt blockLengths[2] = {4, 1}; 9075 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 9076 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 9077 MPI_Op statReduce; 9078 9079 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 9080 PetscCallMPI(MPI_Type_commit(&statType)); 9081 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 9082 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 9083 PetscCallMPI(MPI_Op_free(&statReduce)); 9084 PetscCallMPI(MPI_Type_free(&statType)); 9085 } else { 9086 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 9087 } 9088 if (rank == 0) { 9089 count = globalStats.count; 9090 min = globalStats.min; 9091 max = globalStats.max; 9092 mean = globalStats.sum / globalStats.count; 9093 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 9094 } 9095 9096 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)); 9097 PetscCall(PetscFree2(J, invJ)); 9098 9099 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 9100 if (dmCoarse) { 9101 PetscBool isplex; 9102 9103 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 9104 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 9105 } 9106 PetscFunctionReturn(0); 9107 } 9108 9109 /*@ 9110 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 9111 orthogonal quality below given tolerance. 9112 9113 Collective on dm 9114 9115 Input Parameters: 9116 + dm - The DMPlex object 9117 . fv - Optional PetscFV object for pre-computed cell/face centroid information 9118 - atol - [0, 1] Absolute tolerance for tagging cells. 9119 9120 Output Parameters: 9121 + OrthQual - Vec containing orthogonal quality per cell 9122 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 9123 9124 Options Database Keys: 9125 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 9126 supported. 9127 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 9128 9129 Notes: 9130 Orthogonal quality is given by the following formula: 9131 9132 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 9133 9134 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 9135 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 9136 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 9137 calculating the cosine of the angle between these vectors. 9138 9139 Orthogonal quality ranges from 1 (best) to 0 (worst). 9140 9141 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 9142 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 9143 9144 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 9145 9146 Level: intermediate 9147 9148 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 9149 @*/ 9150 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 9151 { 9152 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 9153 PetscInt *idx; 9154 PetscScalar *oqVals; 9155 const PetscScalar *cellGeomArr, *faceGeomArr; 9156 PetscReal *ci, *fi, *Ai; 9157 MPI_Comm comm; 9158 Vec cellgeom, facegeom; 9159 DM dmFace, dmCell; 9160 IS glob; 9161 ISLocalToGlobalMapping ltog; 9162 PetscViewer vwr; 9163 9164 PetscFunctionBegin; 9165 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9166 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 9167 PetscValidPointer(OrthQual, 4); 9168 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 9169 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 9170 PetscCall(DMGetDimension(dm, &nc)); 9171 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 9172 { 9173 DMPlexInterpolatedFlag interpFlag; 9174 9175 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 9176 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 9177 PetscMPIInt rank; 9178 9179 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9180 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 9181 } 9182 } 9183 if (OrthQualLabel) { 9184 PetscValidPointer(OrthQualLabel, 5); 9185 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 9186 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 9187 } else { 9188 *OrthQualLabel = NULL; 9189 } 9190 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 9191 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 9192 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 9193 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 9194 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 9195 PetscCall(VecCreate(comm, OrthQual)); 9196 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 9197 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 9198 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9199 PetscCall(VecSetUp(*OrthQual)); 9200 PetscCall(ISDestroy(&glob)); 9201 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9202 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9203 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9204 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9205 PetscCall(VecGetDM(cellgeom, &dmCell)); 9206 PetscCall(VecGetDM(facegeom, &dmFace)); 9207 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9208 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 9209 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9210 PetscInt cellarr[2], *adj = NULL; 9211 PetscScalar *cArr, *fArr; 9212 PetscReal minvalc = 1.0, minvalf = 1.0; 9213 PetscFVCellGeom *cg; 9214 9215 idx[cellIter] = cell - cStart; 9216 cellarr[0] = cell; 9217 /* Make indexing into cellGeom easier */ 9218 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9219 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9220 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9221 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9222 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 9223 PetscInt i; 9224 const PetscInt neigh = adj[cellneigh]; 9225 PetscReal normci = 0, normfi = 0, normai = 0; 9226 PetscFVCellGeom *cgneigh; 9227 PetscFVFaceGeom *fg; 9228 9229 /* Don't count ourselves in the neighbor list */ 9230 if (neigh == cell) continue; 9231 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9232 cellarr[1] = neigh; 9233 { 9234 PetscInt numcovpts; 9235 const PetscInt *covpts; 9236 9237 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9238 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9239 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9240 } 9241 9242 /* Compute c_i, f_i and their norms */ 9243 for (i = 0; i < nc; i++) { 9244 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9245 fi[i] = fg->centroid[i] - cg->centroid[i]; 9246 Ai[i] = fg->normal[i]; 9247 normci += PetscPowReal(ci[i], 2); 9248 normfi += PetscPowReal(fi[i], 2); 9249 normai += PetscPowReal(Ai[i], 2); 9250 } 9251 normci = PetscSqrtReal(normci); 9252 normfi = PetscSqrtReal(normfi); 9253 normai = PetscSqrtReal(normai); 9254 9255 /* Normalize and compute for each face-cell-normal pair */ 9256 for (i = 0; i < nc; i++) { 9257 ci[i] = ci[i] / normci; 9258 fi[i] = fi[i] / normfi; 9259 Ai[i] = Ai[i] / normai; 9260 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9261 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9262 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9263 } 9264 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9265 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9266 } 9267 PetscCall(PetscFree(adj)); 9268 PetscCall(PetscFree2(cArr, fArr)); 9269 /* Defer to cell if they're equal */ 9270 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9271 if (OrthQualLabel) { 9272 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9273 } 9274 } 9275 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9276 PetscCall(VecAssemblyBegin(*OrthQual)); 9277 PetscCall(VecAssemblyEnd(*OrthQual)); 9278 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9279 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9280 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9281 if (OrthQualLabel) { 9282 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9283 } 9284 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9285 PetscCall(PetscViewerDestroy(&vwr)); 9286 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9287 PetscFunctionReturn(0); 9288 } 9289 9290 /* this is here instead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9291 * interpolator construction */ 9292 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9293 { 9294 PetscSection section, newSection, gsection; 9295 PetscSF sf; 9296 PetscBool hasConstraints, ghasConstraints; 9297 9298 PetscFunctionBegin; 9299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9300 PetscValidPointer(odm, 2); 9301 PetscCall(DMGetLocalSection(dm, §ion)); 9302 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9303 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9304 if (!ghasConstraints) { 9305 PetscCall(PetscObjectReference((PetscObject)dm)); 9306 *odm = dm; 9307 PetscFunctionReturn(0); 9308 } 9309 PetscCall(DMClone(dm, odm)); 9310 PetscCall(DMCopyFields(dm, *odm)); 9311 PetscCall(DMGetLocalSection(*odm, &newSection)); 9312 PetscCall(DMGetPointSF(*odm, &sf)); 9313 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9314 PetscCall(DMSetGlobalSection(*odm, gsection)); 9315 PetscCall(PetscSectionDestroy(&gsection)); 9316 PetscFunctionReturn(0); 9317 } 9318 9319 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9320 { 9321 DM dmco, dmfo; 9322 Mat interpo; 9323 Vec rscale; 9324 Vec cglobalo, clocal; 9325 Vec fglobal, fglobalo, flocal; 9326 PetscBool regular; 9327 9328 PetscFunctionBegin; 9329 PetscCall(DMGetFullDM(dmc, &dmco)); 9330 PetscCall(DMGetFullDM(dmf, &dmfo)); 9331 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9332 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9333 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9334 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9335 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9336 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9337 PetscCall(VecSet(cglobalo, 0.)); 9338 PetscCall(VecSet(clocal, 0.)); 9339 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9340 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9341 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9342 PetscCall(VecSet(fglobal, 0.)); 9343 PetscCall(VecSet(fglobalo, 0.)); 9344 PetscCall(VecSet(flocal, 0.)); 9345 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9346 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9347 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9348 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9349 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9350 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9351 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9352 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9353 *shift = fglobal; 9354 PetscCall(VecDestroy(&flocal)); 9355 PetscCall(VecDestroy(&fglobalo)); 9356 PetscCall(VecDestroy(&clocal)); 9357 PetscCall(VecDestroy(&cglobalo)); 9358 PetscCall(VecDestroy(&rscale)); 9359 PetscCall(MatDestroy(&interpo)); 9360 PetscCall(DMDestroy(&dmfo)); 9361 PetscCall(DMDestroy(&dmco)); 9362 PetscFunctionReturn(0); 9363 } 9364 9365 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9366 { 9367 PetscObject shifto; 9368 Vec shift; 9369 9370 PetscFunctionBegin; 9371 if (!interp) { 9372 Vec rscale; 9373 9374 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9375 PetscCall(VecDestroy(&rscale)); 9376 } else { 9377 PetscCall(PetscObjectReference((PetscObject)interp)); 9378 } 9379 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9380 if (!shifto) { 9381 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9382 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9383 shifto = (PetscObject)shift; 9384 PetscCall(VecDestroy(&shift)); 9385 } 9386 shift = (Vec)shifto; 9387 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9388 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9389 PetscCall(MatDestroy(&interp)); 9390 PetscFunctionReturn(0); 9391 } 9392 9393 /* Pointwise interpolation 9394 Just code FEM for now 9395 u^f = I u^c 9396 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9397 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9398 I_{ij} = psi^f_i phi^c_j 9399 */ 9400 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9401 { 9402 PetscSection gsc, gsf; 9403 PetscInt m, n; 9404 void *ctx; 9405 DM cdm; 9406 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9407 9408 PetscFunctionBegin; 9409 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9410 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9411 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9412 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9413 9414 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9415 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9416 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9417 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9418 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9419 9420 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9421 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9422 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9423 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9424 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9425 if (scaling) { 9426 /* Use naive scaling */ 9427 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9428 } 9429 PetscFunctionReturn(0); 9430 } 9431 9432 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9433 { 9434 VecScatter ctx; 9435 9436 PetscFunctionBegin; 9437 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9438 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9439 PetscCall(VecScatterDestroy(&ctx)); 9440 PetscFunctionReturn(0); 9441 } 9442 9443 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[]) 9444 { 9445 const PetscInt Nc = uOff[1] - uOff[0]; 9446 PetscInt c; 9447 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9448 } 9449 9450 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9451 { 9452 DM dmc; 9453 PetscDS ds; 9454 Vec ones, locmass; 9455 IS cellIS; 9456 PetscFormKey key; 9457 PetscInt depth; 9458 9459 PetscFunctionBegin; 9460 PetscCall(DMClone(dm, &dmc)); 9461 PetscCall(DMCopyDisc(dm, dmc)); 9462 PetscCall(DMGetDS(dmc, &ds)); 9463 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9464 PetscCall(DMCreateGlobalVector(dmc, mass)); 9465 PetscCall(DMGetLocalVector(dmc, &ones)); 9466 PetscCall(DMGetLocalVector(dmc, &locmass)); 9467 PetscCall(DMPlexGetDepth(dmc, &depth)); 9468 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9469 PetscCall(VecSet(locmass, 0.0)); 9470 PetscCall(VecSet(ones, 1.0)); 9471 key.label = NULL; 9472 key.value = 0; 9473 key.field = 0; 9474 key.part = 0; 9475 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9476 PetscCall(ISDestroy(&cellIS)); 9477 PetscCall(VecSet(*mass, 0.0)); 9478 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9479 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9480 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9481 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9482 PetscCall(DMDestroy(&dmc)); 9483 PetscFunctionReturn(0); 9484 } 9485 9486 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9487 { 9488 PetscSection gsc, gsf; 9489 PetscInt m, n; 9490 void *ctx; 9491 DM cdm; 9492 PetscBool regular; 9493 9494 PetscFunctionBegin; 9495 if (dmFine == dmCoarse) { 9496 DM dmc; 9497 PetscDS ds; 9498 PetscWeakForm wf; 9499 Vec u; 9500 IS cellIS; 9501 PetscFormKey key; 9502 PetscInt depth; 9503 9504 PetscCall(DMClone(dmFine, &dmc)); 9505 PetscCall(DMCopyDisc(dmFine, dmc)); 9506 PetscCall(DMGetDS(dmc, &ds)); 9507 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9508 PetscCall(PetscWeakFormClear(wf)); 9509 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9510 PetscCall(DMCreateMatrix(dmc, mass)); 9511 PetscCall(DMGetLocalVector(dmc, &u)); 9512 PetscCall(DMPlexGetDepth(dmc, &depth)); 9513 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9514 PetscCall(MatZeroEntries(*mass)); 9515 key.label = NULL; 9516 key.value = 0; 9517 key.field = 0; 9518 key.part = 0; 9519 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9520 PetscCall(ISDestroy(&cellIS)); 9521 PetscCall(DMRestoreLocalVector(dmc, &u)); 9522 PetscCall(DMDestroy(&dmc)); 9523 } else { 9524 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9525 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9526 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9527 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9528 9529 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9530 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9531 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9532 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9533 9534 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9535 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9536 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9537 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9538 } 9539 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9540 PetscFunctionReturn(0); 9541 } 9542 9543 /*@ 9544 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9545 9546 Input Parameter: 9547 . dm - The DMPlex object 9548 9549 Output Parameter: 9550 . regular - The flag 9551 9552 Level: intermediate 9553 9554 .seealso: `DMPlexSetRegularRefinement()` 9555 @*/ 9556 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9557 { 9558 PetscFunctionBegin; 9559 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9560 PetscValidBoolPointer(regular, 2); 9561 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9562 PetscFunctionReturn(0); 9563 } 9564 9565 /*@ 9566 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9567 9568 Input Parameters: 9569 + dm - The DMPlex object 9570 - regular - The flag 9571 9572 Level: intermediate 9573 9574 .seealso: `DMPlexGetRegularRefinement()` 9575 @*/ 9576 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9577 { 9578 PetscFunctionBegin; 9579 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9580 ((DM_Plex *)dm->data)->regularRefinement = regular; 9581 PetscFunctionReturn(0); 9582 } 9583 9584 /* anchors */ 9585 /*@ 9586 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9587 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9588 9589 not collective 9590 9591 Input Parameter: 9592 . dm - The DMPlex object 9593 9594 Output Parameters: 9595 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9596 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9597 9598 Level: intermediate 9599 9600 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9601 @*/ 9602 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9603 { 9604 DM_Plex *plex = (DM_Plex *)dm->data; 9605 9606 PetscFunctionBegin; 9607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9608 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9609 if (anchorSection) *anchorSection = plex->anchorSection; 9610 if (anchorIS) *anchorIS = plex->anchorIS; 9611 PetscFunctionReturn(0); 9612 } 9613 9614 /*@ 9615 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9616 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9617 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9618 9619 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9620 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9621 9622 collective on dm 9623 9624 Input Parameters: 9625 + dm - The DMPlex object 9626 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. Must have a local communicator (PETSC_COMM_SELF or derivative). 9627 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9628 9629 The reference counts of anchorSection and anchorIS are incremented. 9630 9631 Level: intermediate 9632 9633 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9634 @*/ 9635 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9636 { 9637 DM_Plex *plex = (DM_Plex *)dm->data; 9638 PetscMPIInt result; 9639 9640 PetscFunctionBegin; 9641 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9642 if (anchorSection) { 9643 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9644 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9645 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9646 } 9647 if (anchorIS) { 9648 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9649 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9650 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9651 } 9652 9653 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9654 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9655 plex->anchorSection = anchorSection; 9656 9657 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9658 PetscCall(ISDestroy(&plex->anchorIS)); 9659 plex->anchorIS = anchorIS; 9660 9661 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9662 PetscInt size, a, pStart, pEnd; 9663 const PetscInt *anchors; 9664 9665 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9666 PetscCall(ISGetLocalSize(anchorIS, &size)); 9667 PetscCall(ISGetIndices(anchorIS, &anchors)); 9668 for (a = 0; a < size; a++) { 9669 PetscInt p; 9670 9671 p = anchors[a]; 9672 if (p >= pStart && p < pEnd) { 9673 PetscInt dof; 9674 9675 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9676 if (dof) { 9677 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9678 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9679 } 9680 } 9681 } 9682 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9683 } 9684 /* reset the generic constraints */ 9685 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9686 PetscFunctionReturn(0); 9687 } 9688 9689 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9690 { 9691 PetscSection anchorSection; 9692 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9693 9694 PetscFunctionBegin; 9695 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9696 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9697 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9698 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9699 if (numFields) { 9700 PetscInt f; 9701 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9702 9703 for (f = 0; f < numFields; f++) { 9704 PetscInt numComp; 9705 9706 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9707 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9708 } 9709 } 9710 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9711 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9712 pStart = PetscMax(pStart, sStart); 9713 pEnd = PetscMin(pEnd, sEnd); 9714 pEnd = PetscMax(pStart, pEnd); 9715 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9716 for (p = pStart; p < pEnd; p++) { 9717 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9718 if (dof) { 9719 PetscCall(PetscSectionGetDof(section, p, &dof)); 9720 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9721 for (f = 0; f < numFields; f++) { 9722 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9723 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9724 } 9725 } 9726 } 9727 PetscCall(PetscSectionSetUp(*cSec)); 9728 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9729 PetscFunctionReturn(0); 9730 } 9731 9732 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9733 { 9734 PetscSection aSec; 9735 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9736 const PetscInt *anchors; 9737 PetscInt numFields, f; 9738 IS aIS; 9739 MatType mtype; 9740 PetscBool iscuda, iskokkos; 9741 9742 PetscFunctionBegin; 9743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9744 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9745 PetscCall(PetscSectionGetStorageSize(section, &n)); 9746 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9747 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9748 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9749 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9750 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9751 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9752 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9753 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9754 else mtype = MATSEQAIJ; 9755 PetscCall(MatSetType(*cMat, mtype)); 9756 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9757 PetscCall(ISGetIndices(aIS, &anchors)); 9758 /* cSec will be a subset of aSec and section */ 9759 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9760 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9761 PetscCall(PetscMalloc1(m + 1, &i)); 9762 i[0] = 0; 9763 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9764 for (p = pStart; p < pEnd; p++) { 9765 PetscInt rDof, rOff, r; 9766 9767 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9768 if (!rDof) continue; 9769 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9770 if (numFields) { 9771 for (f = 0; f < numFields; f++) { 9772 annz = 0; 9773 for (r = 0; r < rDof; r++) { 9774 a = anchors[rOff + r]; 9775 if (a < sStart || a >= sEnd) continue; 9776 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9777 annz += aDof; 9778 } 9779 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9780 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9781 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9782 } 9783 } else { 9784 annz = 0; 9785 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9786 for (q = 0; q < dof; q++) { 9787 a = anchors[rOff + q]; 9788 if (a < sStart || a >= sEnd) continue; 9789 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9790 annz += aDof; 9791 } 9792 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9793 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9794 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9795 } 9796 } 9797 nnz = i[m]; 9798 PetscCall(PetscMalloc1(nnz, &j)); 9799 offset = 0; 9800 for (p = pStart; p < pEnd; p++) { 9801 if (numFields) { 9802 for (f = 0; f < numFields; f++) { 9803 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9804 for (q = 0; q < dof; q++) { 9805 PetscInt rDof, rOff, r; 9806 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9807 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9808 for (r = 0; r < rDof; r++) { 9809 PetscInt s; 9810 9811 a = anchors[rOff + r]; 9812 if (a < sStart || a >= sEnd) continue; 9813 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9814 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9815 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9816 } 9817 } 9818 } 9819 } else { 9820 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9821 for (q = 0; q < dof; q++) { 9822 PetscInt rDof, rOff, r; 9823 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9824 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9825 for (r = 0; r < rDof; r++) { 9826 PetscInt s; 9827 9828 a = anchors[rOff + r]; 9829 if (a < sStart || a >= sEnd) continue; 9830 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9831 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9832 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9833 } 9834 } 9835 } 9836 } 9837 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9838 PetscCall(PetscFree(i)); 9839 PetscCall(PetscFree(j)); 9840 PetscCall(ISRestoreIndices(aIS, &anchors)); 9841 PetscFunctionReturn(0); 9842 } 9843 9844 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9845 { 9846 DM_Plex *plex = (DM_Plex *)dm->data; 9847 PetscSection anchorSection, section, cSec; 9848 Mat cMat; 9849 9850 PetscFunctionBegin; 9851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9852 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9853 if (anchorSection) { 9854 PetscInt Nf; 9855 9856 PetscCall(DMGetLocalSection(dm, §ion)); 9857 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9858 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9859 PetscCall(DMGetNumFields(dm, &Nf)); 9860 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9861 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9862 PetscCall(PetscSectionDestroy(&cSec)); 9863 PetscCall(MatDestroy(&cMat)); 9864 } 9865 PetscFunctionReturn(0); 9866 } 9867 9868 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9869 { 9870 IS subis; 9871 PetscSection section, subsection; 9872 9873 PetscFunctionBegin; 9874 PetscCall(DMGetLocalSection(dm, §ion)); 9875 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9876 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9877 /* Create subdomain */ 9878 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9879 /* Create submodel */ 9880 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9881 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9882 PetscCall(DMSetLocalSection(*subdm, subsection)); 9883 PetscCall(PetscSectionDestroy(&subsection)); 9884 PetscCall(DMCopyDisc(dm, *subdm)); 9885 /* Create map from submodel to global model */ 9886 if (is) { 9887 PetscSection sectionGlobal, subsectionGlobal; 9888 IS spIS; 9889 const PetscInt *spmap; 9890 PetscInt *subIndices; 9891 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9892 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9893 9894 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9895 PetscCall(ISGetIndices(spIS, &spmap)); 9896 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9897 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9898 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9899 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9900 for (p = pStart; p < pEnd; ++p) { 9901 PetscInt gdof, pSubSize = 0; 9902 9903 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9904 if (gdof > 0) { 9905 for (f = 0; f < Nf; ++f) { 9906 PetscInt fdof, fcdof; 9907 9908 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9909 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9910 pSubSize += fdof - fcdof; 9911 } 9912 subSize += pSubSize; 9913 if (pSubSize) { 9914 if (bs < 0) { 9915 bs = pSubSize; 9916 } else if (bs != pSubSize) { 9917 /* Layout does not admit a pointwise block size */ 9918 bs = 1; 9919 } 9920 } 9921 } 9922 } 9923 /* Must have same blocksize on all procs (some might have no points) */ 9924 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9925 bsLocal[1] = bs; 9926 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9927 if (bsMinMax[0] != bsMinMax[1]) { 9928 bs = 1; 9929 } else { 9930 bs = bsMinMax[0]; 9931 } 9932 PetscCall(PetscMalloc1(subSize, &subIndices)); 9933 for (p = pStart; p < pEnd; ++p) { 9934 PetscInt gdof, goff; 9935 9936 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9937 if (gdof > 0) { 9938 const PetscInt point = spmap[p]; 9939 9940 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9941 for (f = 0; f < Nf; ++f) { 9942 PetscInt fdof, fcdof, fc, f2, poff = 0; 9943 9944 /* Can get rid of this loop by storing field information in the global section */ 9945 for (f2 = 0; f2 < f; ++f2) { 9946 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9947 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9948 poff += fdof - fcdof; 9949 } 9950 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9951 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9952 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 9953 } 9954 } 9955 } 9956 PetscCall(ISRestoreIndices(spIS, &spmap)); 9957 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9958 if (bs > 1) { 9959 /* We need to check that the block size does not come from non-contiguous fields */ 9960 PetscInt i, j, set = 1; 9961 for (i = 0; i < subSize; i += bs) { 9962 for (j = 0; j < bs; ++j) { 9963 if (subIndices[i + j] != subIndices[i] + j) { 9964 set = 0; 9965 break; 9966 } 9967 } 9968 } 9969 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9970 } 9971 /* Attach nullspace */ 9972 for (f = 0; f < Nf; ++f) { 9973 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9974 if ((*subdm)->nullspaceConstructors[f]) break; 9975 } 9976 if (f < Nf) { 9977 MatNullSpace nullSpace; 9978 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9979 9980 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9981 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9982 } 9983 } 9984 PetscFunctionReturn(0); 9985 } 9986 9987 /*@ 9988 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9989 9990 Input Parameter: 9991 - dm - The DM 9992 9993 Level: developer 9994 9995 Options Database Keys: 9996 . -dm_plex_monitor_throughput - Activate the monitor 9997 9998 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9999 @*/ 10000 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 10001 { 10002 #if defined(PETSC_USE_LOG) 10003 PetscStageLog stageLog; 10004 PetscLogEvent event; 10005 PetscLogStage stage; 10006 PetscEventPerfInfo eventInfo; 10007 PetscReal cellRate, flopRate; 10008 PetscInt cStart, cEnd, Nf, N; 10009 const char *name; 10010 #endif 10011 10012 PetscFunctionBegin; 10013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 10014 #if defined(PETSC_USE_LOG) 10015 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 10016 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 10017 PetscCall(DMGetNumFields(dm, &Nf)); 10018 PetscCall(PetscLogGetStageLog(&stageLog)); 10019 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 10020 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 10021 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 10022 N = (cEnd - cStart) * Nf * eventInfo.count; 10023 flopRate = eventInfo.flops / eventInfo.time; 10024 cellRate = N / eventInfo.time; 10025 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))); 10026 #else 10027 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 10028 #endif 10029 PetscFunctionReturn(0); 10030 } 10031