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 DMPolytopeType ct; 36 PetscInt cStart, cEnd; 37 38 PetscFunctionBegin; 39 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 40 if (cEnd <= cStart) { 41 *simplex = PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 45 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 46 PetscFunctionReturn(0); 47 } 48 49 /*@ 50 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 51 52 Input Parameters: 53 + dm - The DMPlex object 54 - height - The cell height in the Plex, 0 is the default 55 56 Output Parameters: 57 + cStart - The first "normal" cell 58 - cEnd - The upper bound on "normal"" cells 59 60 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 61 62 Level: developer 63 64 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 65 @*/ 66 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) { 67 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 68 PetscInt cS, cE, c; 69 70 PetscFunctionBegin; 71 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 72 for (c = cS; c < cE; ++c) { 73 DMPolytopeType cct; 74 75 PetscCall(DMPlexGetCellType(dm, c, &cct)); 76 if ((PetscInt)cct < 0) break; 77 switch (cct) { 78 case DM_POLYTOPE_POINT: 79 case DM_POLYTOPE_SEGMENT: 80 case DM_POLYTOPE_TRIANGLE: 81 case DM_POLYTOPE_QUADRILATERAL: 82 case DM_POLYTOPE_TETRAHEDRON: 83 case DM_POLYTOPE_HEXAHEDRON: ct = cct; break; 84 default: break; 85 } 86 if (ct != DM_POLYTOPE_UNKNOWN) break; 87 } 88 if (ct != DM_POLYTOPE_UNKNOWN) { 89 DMLabel ctLabel; 90 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 93 // Reset label for fast lookup 94 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 95 } 96 if (cStart) *cStart = cS; 97 if (cEnd) *cEnd = cE; 98 PetscFunctionReturn(0); 99 } 100 101 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) { 102 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 103 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 104 105 PetscFunctionBegin; 106 *ft = PETSC_VTK_INVALID; 107 PetscCall(DMGetCoordinateDim(dm, &cdim)); 108 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 109 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 110 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 111 if (field >= 0) { 112 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 113 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 114 } else { 115 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 116 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 117 } 118 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 119 if (globalvcdof[0]) { 120 *sStart = vStart; 121 *sEnd = vEnd; 122 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 123 else *ft = PETSC_VTK_POINT_FIELD; 124 } else if (globalvcdof[1]) { 125 *sStart = cStart; 126 *sEnd = cEnd; 127 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 128 else *ft = PETSC_VTK_CELL_FIELD; 129 } else { 130 if (field >= 0) { 131 const char *fieldname; 132 133 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 134 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 135 } else { 136 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 137 } 138 } 139 PetscFunctionReturn(0); 140 } 141 142 /*@ 143 DMPlexVecView1D - Plot many 1D solutions on the same line graph 144 145 Collective on dm 146 147 Input Parameters: 148 + dm - The DMPlex 149 . n - The number of vectors 150 . u - The array of local vectors 151 - viewer - The Draw viewer 152 153 Level: advanced 154 155 .seealso: `VecViewFromOptions()`, `VecView()` 156 @*/ 157 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) { 158 PetscDS ds; 159 PetscDraw draw = NULL; 160 PetscDrawLG lg; 161 Vec coordinates; 162 const PetscScalar *coords, **sol; 163 PetscReal *vals; 164 PetscInt *Nc; 165 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 166 char **names; 167 168 PetscFunctionBegin; 169 PetscCall(DMGetDS(dm, &ds)); 170 PetscCall(PetscDSGetNumFields(ds, &Nf)); 171 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 172 PetscCall(PetscDSGetComponents(ds, &Nc)); 173 174 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 175 if (!draw) PetscFunctionReturn(0); 176 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 177 178 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 179 for (i = 0, l = 0; i < n; ++i) { 180 const char *vname; 181 182 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 183 for (f = 0; f < Nf; ++f) { 184 PetscObject disc; 185 const char *fname; 186 char tmpname[PETSC_MAX_PATH_LEN]; 187 188 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 189 /* TODO Create names for components */ 190 for (c = 0; c < Nc[f]; ++c, ++l) { 191 PetscCall(PetscObjectGetName(disc, &fname)); 192 PetscCall(PetscStrcpy(tmpname, vname)); 193 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 195 PetscCall(PetscStrallocpy(tmpname, &names[l])); 196 } 197 } 198 } 199 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 200 /* Just add P_1 support for now */ 201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 202 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 203 PetscCall(VecGetArrayRead(coordinates, &coords)); 204 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 205 for (v = vStart; v < vEnd; ++v) { 206 PetscScalar *x, *svals; 207 208 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 209 for (i = 0; i < n; ++i) { 210 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 211 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 212 } 213 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 214 } 215 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 216 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 217 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 218 PetscCall(PetscFree3(sol, names, vals)); 219 220 PetscCall(PetscDrawLGDraw(lg)); 221 PetscCall(PetscDrawLGDestroy(&lg)); 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) { 235 DM dm; 236 PetscSection s; 237 PetscDraw draw, popup; 238 DM cdm; 239 PetscSection coordSection; 240 Vec coordinates; 241 const PetscScalar *coords, *array; 242 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 243 PetscReal vbound[2], time; 244 PetscBool flg; 245 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 246 const char *name; 247 char title[PETSC_MAX_PATH_LEN]; 248 249 PetscFunctionBegin; 250 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 251 PetscCall(VecGetDM(v, &dm)); 252 PetscCall(DMGetCoordinateDim(dm, &dim)); 253 PetscCall(DMGetLocalSection(dm, &s)); 254 PetscCall(PetscSectionGetNumFields(s, &Nf)); 255 PetscCall(DMGetCoarsenLevel(dm, &level)); 256 PetscCall(DMGetCoordinateDM(dm, &cdm)); 257 PetscCall(DMGetLocalSection(cdm, &coordSection)); 258 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 259 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 260 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 261 262 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 263 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 264 265 PetscCall(VecGetLocalSize(coordinates, &N)); 266 PetscCall(VecGetArrayRead(coordinates, &coords)); 267 for (c = 0; c < N; c += dim) { 268 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 269 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 271 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 272 } 273 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 274 PetscCall(PetscDrawClear(draw)); 275 276 /* Could implement something like DMDASelectFields() */ 277 for (f = 0; f < Nf; ++f) { 278 DM fdm = dm; 279 Vec fv = v; 280 IS fis; 281 char prefix[PETSC_MAX_PATH_LEN]; 282 const char *fname; 283 284 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 285 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 286 287 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 288 else prefix[0] = '\0'; 289 if (Nf > 1) { 290 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 291 PetscCall(VecGetSubVector(v, fis, &fv)); 292 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 293 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 294 } 295 for (comp = 0; comp < Nc; ++comp, ++w) { 296 PetscInt nmax = 2; 297 298 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 299 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 300 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 301 PetscCall(PetscDrawSetTitle(draw, title)); 302 303 /* TODO Get max and min only for this component */ 304 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 305 if (!flg) { 306 PetscCall(VecMin(fv, NULL, &vbound[0])); 307 PetscCall(VecMax(fv, NULL, &vbound[1])); 308 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 309 } 310 PetscCall(PetscDrawGetPopup(draw, &popup)); 311 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 312 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 313 314 PetscCall(VecGetArrayRead(fv, &array)); 315 for (c = cStart; c < cEnd; ++c) { 316 PetscScalar *coords = NULL, *a = NULL; 317 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 318 319 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 320 if (a) { 321 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 322 color[1] = color[2] = color[3] = color[0]; 323 } else { 324 PetscScalar *vals = NULL; 325 PetscInt numVals, va; 326 327 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 328 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); 329 switch (numVals / Nc) { 330 case 3: /* P1 Triangle */ 331 case 4: /* P1 Quadrangle */ 332 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 333 break; 334 case 6: /* P2 Triangle */ 335 case 8: /* P2 Quadrangle */ 336 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 337 break; 338 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 339 } 340 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 341 } 342 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 343 switch (numCoords) { 344 case 6: 345 case 12: /* Localized triangle */ 346 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])); 347 break; 348 case 8: 349 case 16: /* Localized quadrilateral */ 350 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])); 351 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])); 352 break; 353 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 354 } 355 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 356 } 357 PetscCall(VecRestoreArrayRead(fv, &array)); 358 PetscCall(PetscDrawFlush(draw)); 359 PetscCall(PetscDrawPause(draw)); 360 PetscCall(PetscDrawSave(draw)); 361 } 362 if (Nf > 1) { 363 PetscCall(VecRestoreSubVector(v, fis, &fv)); 364 PetscCall(ISDestroy(&fis)); 365 PetscCall(DMDestroy(&fdm)); 366 } 367 } 368 PetscFunctionReturn(0); 369 } 370 371 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); break; 387 default: SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) { 393 DM dm; 394 Vec locv; 395 const char *name; 396 PetscSection section; 397 PetscInt pStart, pEnd; 398 PetscInt numFields; 399 PetscViewerVTKFieldType ft; 400 401 PetscFunctionBegin; 402 PetscCall(VecGetDM(v, &dm)); 403 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 404 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 405 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 406 PetscCall(VecCopy(v, locv)); 407 PetscCall(DMGetLocalSection(dm, §ion)); 408 PetscCall(PetscSectionGetNumFields(section, &numFields)); 409 if (!numFields) { 410 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 411 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 412 } else { 413 PetscInt f; 414 415 for (f = 0; f < numFields; f++) { 416 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 417 if (ft == PETSC_VTK_INVALID) continue; 418 PetscCall(PetscObjectReference((PetscObject)locv)); 419 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 420 } 421 PetscCall(VecDestroy(&locv)); 422 } 423 PetscFunctionReturn(0); 424 } 425 426 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) { 427 DM dm; 428 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 429 430 PetscFunctionBegin; 431 PetscCall(VecGetDM(v, &dm)); 432 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 433 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 434 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 437 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 438 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 439 PetscInt i, numFields; 440 PetscObject fe; 441 PetscBool fem = PETSC_FALSE; 442 Vec locv = v; 443 const char *name; 444 PetscInt step; 445 PetscReal time; 446 447 PetscCall(DMGetNumFields(dm, &numFields)); 448 for (i = 0; i < numFields; i++) { 449 PetscCall(DMGetField(dm, i, NULL, &fe)); 450 if (fe->classid == PETSCFE_CLASSID) { 451 fem = PETSC_TRUE; 452 break; 453 } 454 } 455 if (fem) { 456 PetscObject isZero; 457 458 PetscCall(DMGetLocalVector(dm, &locv)); 459 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 460 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 461 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 462 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 463 PetscCall(VecCopy(v, locv)); 464 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 465 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 466 } 467 if (isvtk) { 468 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 469 } else if (ishdf5) { 470 #if defined(PETSC_HAVE_HDF5) 471 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 472 #else 473 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 474 #endif 475 } else if (isdraw) { 476 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 477 } else if (isglvis) { 478 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 479 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 480 PetscCall(VecView_GLVis(locv, viewer)); 481 } else if (iscgns) { 482 #if defined(PETSC_HAVE_CGNS) 483 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 484 #else 485 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 486 #endif 487 } 488 if (fem) { 489 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 490 PetscCall(DMRestoreLocalVector(dm, &locv)); 491 } 492 } else { 493 PetscBool isseq; 494 495 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 496 if (isseq) PetscCall(VecView_Seq(v, viewer)); 497 else PetscCall(VecView_MPI(v, viewer)); 498 } 499 PetscFunctionReturn(0); 500 } 501 502 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) { 503 DM dm; 504 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 505 506 PetscFunctionBegin; 507 PetscCall(VecGetDM(v, &dm)); 508 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 509 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 510 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 511 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 512 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 513 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 514 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 515 if (isvtk || isdraw || isglvis || iscgns) { 516 Vec locv; 517 PetscObject isZero; 518 const char *name; 519 520 PetscCall(DMGetLocalVector(dm, &locv)); 521 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 522 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 523 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 524 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 525 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 526 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 527 PetscCall(VecView_Plex_Local(locv, viewer)); 528 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 529 PetscCall(DMRestoreLocalVector(dm, &locv)); 530 } else if (ishdf5) { 531 #if defined(PETSC_HAVE_HDF5) 532 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 533 #else 534 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 535 #endif 536 } else if (isexodusii) { 537 #if defined(PETSC_HAVE_EXODUSII) 538 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 539 #else 540 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 541 #endif 542 } else { 543 PetscBool isseq; 544 545 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 546 if (isseq) PetscCall(VecView_Seq(v, viewer)); 547 else PetscCall(VecView_MPI(v, viewer)); 548 } 549 PetscFunctionReturn(0); 550 } 551 552 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) { 553 DM dm; 554 MPI_Comm comm; 555 PetscViewerFormat format; 556 Vec v; 557 PetscBool isvtk, ishdf5; 558 559 PetscFunctionBegin; 560 PetscCall(VecGetDM(originalv, &dm)); 561 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 562 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 563 PetscCall(PetscViewerGetFormat(viewer, &format)); 564 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 565 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 566 if (format == PETSC_VIEWER_NATIVE) { 567 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 568 /* this need a better fix */ 569 if (dm->useNatural) { 570 if (dm->sfNatural) { 571 const char *vecname; 572 PetscInt n, nroots; 573 574 PetscCall(VecGetLocalSize(originalv, &n)); 575 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 576 if (n == nroots) { 577 PetscCall(DMGetGlobalVector(dm, &v)); 578 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 579 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 580 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 581 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 582 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 583 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 584 } else v = originalv; 585 } else v = originalv; 586 587 if (ishdf5) { 588 #if defined(PETSC_HAVE_HDF5) 589 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 590 #else 591 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 592 #endif 593 } else if (isvtk) { 594 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 595 } else { 596 PetscBool isseq; 597 598 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 599 if (isseq) PetscCall(VecView_Seq(v, viewer)); 600 else PetscCall(VecView_MPI(v, viewer)); 601 } 602 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 603 PetscFunctionReturn(0); 604 } 605 606 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) { 607 DM dm; 608 PetscBool ishdf5; 609 610 PetscFunctionBegin; 611 PetscCall(VecGetDM(v, &dm)); 612 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 613 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 614 if (ishdf5) { 615 DM dmBC; 616 Vec gv; 617 const char *name; 618 619 PetscCall(DMGetOutputDM(dm, &dmBC)); 620 PetscCall(DMGetGlobalVector(dmBC, &gv)); 621 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 622 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 623 PetscCall(VecLoad_Default(gv, viewer)); 624 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 625 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 626 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 627 } else PetscCall(VecLoad_Default(v, viewer)); 628 PetscFunctionReturn(0); 629 } 630 631 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) { 632 DM dm; 633 PetscBool ishdf5, isexodusii; 634 635 PetscFunctionBegin; 636 PetscCall(VecGetDM(v, &dm)); 637 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (ishdf5) { 641 #if defined(PETSC_HAVE_HDF5) 642 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 643 #else 644 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 645 #endif 646 } else if (isexodusii) { 647 #if defined(PETSC_HAVE_EXODUSII) 648 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 649 #else 650 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 651 #endif 652 } else PetscCall(VecLoad_Default(v, viewer)); 653 PetscFunctionReturn(0); 654 } 655 656 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else PetscCall(VecLoad_Default(originalv, viewer)); 687 } 688 PetscFunctionReturn(0); 689 } 690 691 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) { 692 PetscSection coordSection; 693 Vec coordinates; 694 DMLabel depthLabel, celltypeLabel; 695 const char *name[4]; 696 const PetscScalar *a; 697 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 698 699 PetscFunctionBegin; 700 PetscCall(DMGetDimension(dm, &dim)); 701 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 702 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 703 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 704 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 705 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 706 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 707 PetscCall(VecGetArrayRead(coordinates, &a)); 708 name[0] = "vertex"; 709 name[1] = "edge"; 710 name[dim - 1] = "face"; 711 name[dim] = "cell"; 712 for (c = cStart; c < cEnd; ++c) { 713 PetscInt *closure = NULL; 714 PetscInt closureSize, cl, ct; 715 716 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 717 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 718 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 719 PetscCall(PetscViewerASCIIPushTab(viewer)); 720 for (cl = 0; cl < closureSize * 2; cl += 2) { 721 PetscInt point = closure[cl], depth, dof, off, d, p; 722 723 if ((point < pStart) || (point >= pEnd)) continue; 724 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 725 if (!dof) continue; 726 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 727 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 728 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 729 for (p = 0; p < dof / dim; ++p) { 730 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 731 for (d = 0; d < dim; ++d) { 732 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 733 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 734 } 735 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 736 } 737 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 738 } 739 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 740 PetscCall(PetscViewerASCIIPopTab(viewer)); 741 } 742 PetscCall(VecRestoreArrayRead(coordinates, &a)); 743 PetscFunctionReturn(0); 744 } 745 746 typedef enum { 747 CS_CARTESIAN, 748 CS_POLAR, 749 CS_CYLINDRICAL, 750 CS_SPHERICAL 751 } CoordSystem; 752 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 753 754 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) { 755 PetscInt i; 756 757 PetscFunctionBegin; 758 if (dim > 3) { 759 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 760 } else { 761 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 762 763 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 764 switch (cs) { 765 case CS_CARTESIAN: 766 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 767 break; 768 case CS_POLAR: 769 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 770 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 771 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 772 break; 773 case CS_CYLINDRICAL: 774 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 775 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 776 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 777 trcoords[2] = coords[2]; 778 break; 779 case CS_SPHERICAL: 780 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 781 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 782 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 783 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 784 break; 785 } 786 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 787 } 788 PetscFunctionReturn(0); 789 } 790 791 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) { 792 DM_Plex *mesh = (DM_Plex *)dm->data; 793 DM cdm, cdmCell; 794 PetscSection coordSection, coordSectionCell; 795 Vec coordinates, coordinatesCell; 796 PetscViewerFormat format; 797 798 PetscFunctionBegin; 799 PetscCall(DMGetCoordinateDM(dm, &cdm)); 800 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 801 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 802 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 803 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 804 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 805 PetscCall(PetscViewerGetFormat(viewer, &format)); 806 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 807 const char *name; 808 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 809 PetscInt pStart, pEnd, p, numLabels, l; 810 PetscMPIInt rank, size; 811 812 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 813 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 814 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 815 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 816 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 817 PetscCall(DMGetDimension(dm, &dim)); 818 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 819 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 820 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 821 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 822 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 823 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 824 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 825 for (p = pStart; p < pEnd; ++p) { 826 PetscInt dof, off, s; 827 828 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 829 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 830 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 831 } 832 PetscCall(PetscViewerFlush(viewer)); 833 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 834 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 835 for (p = pStart; p < pEnd; ++p) { 836 PetscInt dof, off, c; 837 838 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 839 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 840 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])); 841 } 842 PetscCall(PetscViewerFlush(viewer)); 843 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 844 if (coordSection && coordinates) { 845 CoordSystem cs = CS_CARTESIAN; 846 const PetscScalar *array, *arrayCell = NULL; 847 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 848 PetscMPIInt rank; 849 const char *name; 850 851 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 852 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 853 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 854 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 855 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 856 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 857 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 858 pStart = PetscMin(pvStart, pcStart); 859 pEnd = PetscMax(pvEnd, pcEnd); 860 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 863 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 864 865 PetscCall(VecGetArrayRead(coordinates, &array)); 866 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 867 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 868 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 869 for (p = pStart; p < pEnd; ++p) { 870 PetscInt dof, off; 871 872 if (p >= pvStart && p < pvEnd) { 873 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 874 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 875 if (dof) { 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 877 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 878 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 879 } 880 } 881 if (cdmCell && p >= pcStart && p < pcEnd) { 882 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 883 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 884 if (dof) { 885 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 886 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 887 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 888 } 889 } 890 } 891 PetscCall(PetscViewerFlush(viewer)); 892 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 893 PetscCall(VecRestoreArrayRead(coordinates, &array)); 894 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 895 } 896 PetscCall(DMGetNumLabels(dm, &numLabels)); 897 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 898 for (l = 0; l < numLabels; ++l) { 899 DMLabel label; 900 PetscBool isdepth; 901 const char *name; 902 903 PetscCall(DMGetLabelName(dm, l, &name)); 904 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 905 if (isdepth) continue; 906 PetscCall(DMGetLabel(dm, name, &label)); 907 PetscCall(DMLabelView(label, viewer)); 908 } 909 if (size > 1) { 910 PetscSF sf; 911 912 PetscCall(DMGetPointSF(dm, &sf)); 913 PetscCall(PetscSFView(sf, viewer)); 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 917 const char *name, *color; 918 const char *defcolors[3] = {"gray", "orange", "green"}; 919 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 920 char lname[PETSC_MAX_PATH_LEN]; 921 PetscReal scale = 2.0; 922 PetscReal tikzscale = 1.0; 923 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 924 double tcoords[3]; 925 PetscScalar *coords; 926 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 927 PetscMPIInt rank, size; 928 char **names, **colors, **lcolors; 929 PetscBool flg, lflg; 930 PetscBT wp = NULL; 931 PetscInt pEnd, pStart; 932 933 PetscCall(DMGetDimension(dm, &dim)); 934 PetscCall(DMPlexGetDepth(dm, &depth)); 935 PetscCall(DMGetNumLabels(dm, &numLabels)); 936 numLabels = PetscMax(numLabels, 10); 937 numColors = 10; 938 numLColors = 10; 939 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 940 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 941 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 942 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 943 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 944 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 945 n = 4; 946 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 947 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 948 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 949 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 950 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 951 if (!useLabels) numLabels = 0; 952 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 953 if (!useColors) { 954 numColors = 3; 955 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 956 } 957 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 958 if (!useColors) { 959 numLColors = 4; 960 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 961 } 962 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 963 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 964 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 965 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 966 if (depth < dim) plotEdges = PETSC_FALSE; 967 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 968 969 /* filter points with labelvalue != labeldefaultvalue */ 970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 971 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 972 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 973 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 974 if (lflg) { 975 DMLabel lbl; 976 977 PetscCall(DMGetLabel(dm, lname, &lbl)); 978 if (lbl) { 979 PetscInt val, defval; 980 981 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 982 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 983 for (c = pStart; c < pEnd; c++) { 984 PetscInt *closure = NULL; 985 PetscInt closureSize; 986 987 PetscCall(DMLabelGetValue(lbl, c, &val)); 988 if (val == defval) continue; 989 990 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 992 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 993 } 994 } 995 } 996 997 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 998 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 999 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1001 \\documentclass[tikz]{standalone}\n\n\ 1002 \\usepackage{pgflibraryshapes}\n\ 1003 \\usetikzlibrary{backgrounds}\n\ 1004 \\usetikzlibrary{arrows}\n\ 1005 \\begin{document}\n")); 1006 if (size > 1) { 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1008 for (p = 0; p < size; ++p) { 1009 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1011 } 1012 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1013 } 1014 if (drawHasse) { 1015 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1016 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1018 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1029 } 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1031 1032 /* Plot vertices */ 1033 PetscCall(VecGetArray(coordinates, &coords)); 1034 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1035 for (v = vStart; v < vEnd; ++v) { 1036 PetscInt off, dof, d; 1037 PetscBool isLabeled = PETSC_FALSE; 1038 1039 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1040 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1041 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1042 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1043 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1044 for (d = 0; d < dof; ++d) { 1045 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1046 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1047 } 1048 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1049 if (dim == 3) { 1050 PetscReal tmp = tcoords[1]; 1051 tcoords[1] = tcoords[2]; 1052 tcoords[2] = -tmp; 1053 } 1054 for (d = 0; d < dof; ++d) { 1055 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1056 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1057 } 1058 if (drawHasse) color = colors[0 % numColors]; 1059 else color = colors[rank % numColors]; 1060 for (l = 0; l < numLabels; ++l) { 1061 PetscInt val; 1062 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1063 if (val >= 0) { 1064 color = lcolors[l % numLColors]; 1065 isLabeled = PETSC_TRUE; 1066 break; 1067 } 1068 } 1069 if (drawNumbers[0]) { 1070 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1071 } else if (drawColors[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1073 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1074 } 1075 PetscCall(VecRestoreArray(coordinates, &coords)); 1076 PetscCall(PetscViewerFlush(viewer)); 1077 /* Plot edges */ 1078 if (plotEdges) { 1079 PetscCall(VecGetArray(coordinates, &coords)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1081 for (e = eStart; e < eEnd; ++e) { 1082 const PetscInt *cone; 1083 PetscInt coneSize, offA, offB, dof, d; 1084 1085 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1086 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1087 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1088 PetscCall(DMPlexGetCone(dm, e, &cone)); 1089 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1090 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1091 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1093 for (d = 0; d < dof; ++d) { 1094 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1095 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1096 } 1097 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1098 if (dim == 3) { 1099 PetscReal tmp = tcoords[1]; 1100 tcoords[1] = tcoords[2]; 1101 tcoords[2] = -tmp; 1102 } 1103 for (d = 0; d < dof; ++d) { 1104 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1106 } 1107 if (drawHasse) color = colors[1 % numColors]; 1108 else color = colors[rank % numColors]; 1109 for (l = 0; l < numLabels; ++l) { 1110 PetscInt val; 1111 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1112 if (val >= 0) { 1113 color = lcolors[l % numLColors]; 1114 break; 1115 } 1116 } 1117 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1118 } 1119 PetscCall(VecRestoreArray(coordinates, &coords)); 1120 PetscCall(PetscViewerFlush(viewer)); 1121 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1122 } 1123 /* Plot cells */ 1124 if (dim == 3 || !drawNumbers[1]) { 1125 for (e = eStart; e < eEnd; ++e) { 1126 const PetscInt *cone; 1127 1128 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1129 color = colors[rank % numColors]; 1130 for (l = 0; l < numLabels; ++l) { 1131 PetscInt val; 1132 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1133 if (val >= 0) { 1134 color = lcolors[l % numLColors]; 1135 break; 1136 } 1137 } 1138 PetscCall(DMPlexGetCone(dm, e, &cone)); 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1140 } 1141 } else { 1142 DMPolytopeType ct; 1143 1144 /* Drawing a 2D polygon */ 1145 for (c = cStart; c < cEnd; ++c) { 1146 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1147 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1148 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1149 const PetscInt *cone; 1150 PetscInt coneSize, e; 1151 1152 PetscCall(DMPlexGetCone(dm, c, &cone)); 1153 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1154 for (e = 0; e < coneSize; ++e) { 1155 const PetscInt *econe; 1156 1157 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1158 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)); 1159 } 1160 } else { 1161 PetscInt *closure = NULL; 1162 PetscInt closureSize, Nv = 0, v; 1163 1164 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1165 for (p = 0; p < closureSize * 2; p += 2) { 1166 const PetscInt point = closure[p]; 1167 1168 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1169 } 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1171 for (v = 0; v <= Nv; ++v) { 1172 const PetscInt vertex = closure[v % Nv]; 1173 1174 if (v > 0) { 1175 if (plotEdges) { 1176 const PetscInt *edge; 1177 PetscInt endpoints[2], ne; 1178 1179 endpoints[0] = closure[v - 1]; 1180 endpoints[1] = vertex; 1181 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1182 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1183 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1184 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1185 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1186 } 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1188 } 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1190 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1191 } 1192 } 1193 } 1194 for (c = cStart; c < cEnd; ++c) { 1195 double ccoords[3] = {0.0, 0.0, 0.0}; 1196 PetscBool isLabeled = PETSC_FALSE; 1197 PetscScalar *cellCoords = NULL; 1198 const PetscScalar *array; 1199 PetscInt numCoords, cdim, d; 1200 PetscBool isDG; 1201 1202 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1203 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1204 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1205 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1207 for (p = 0; p < numCoords / cdim; ++p) { 1208 for (d = 0; d < cdim; ++d) { 1209 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1210 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1211 } 1212 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1213 if (cdim == 3) { 1214 PetscReal tmp = tcoords[1]; 1215 tcoords[1] = tcoords[2]; 1216 tcoords[2] = -tmp; 1217 } 1218 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1219 } 1220 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1221 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1222 for (d = 0; d < cdim; ++d) { 1223 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1224 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1225 } 1226 if (drawHasse) color = colors[depth % numColors]; 1227 else color = colors[rank % numColors]; 1228 for (l = 0; l < numLabels; ++l) { 1229 PetscInt val; 1230 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1231 if (val >= 0) { 1232 color = lcolors[l % numLColors]; 1233 isLabeled = PETSC_TRUE; 1234 break; 1235 } 1236 } 1237 if (drawNumbers[dim]) { 1238 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1239 } else if (drawColors[dim]) { 1240 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1241 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1242 } 1243 if (drawHasse) { 1244 color = colors[depth % numColors]; 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1250 1251 color = colors[1 % numColors]; 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1257 1258 color = colors[0 % numColors]; 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1264 1265 for (p = pStart; p < pEnd; ++p) { 1266 const PetscInt *cone; 1267 PetscInt coneSize, cp; 1268 1269 PetscCall(DMPlexGetCone(dm, p, &cone)); 1270 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1271 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1272 } 1273 } 1274 PetscCall(PetscViewerFlush(viewer)); 1275 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1278 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1279 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1280 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1281 PetscCall(PetscFree3(names, colors, lcolors)); 1282 PetscCall(PetscBTDestroy(&wp)); 1283 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1284 Vec cown, acown; 1285 VecScatter sct; 1286 ISLocalToGlobalMapping g2l; 1287 IS gid, acis; 1288 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1289 MPI_Group ggroup, ngroup; 1290 PetscScalar *array, nid; 1291 const PetscInt *idxs; 1292 PetscInt *idxs2, *start, *adjacency, *work; 1293 PetscInt64 lm[3], gm[3]; 1294 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1295 PetscMPIInt d1, d2, rank; 1296 1297 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1298 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1299 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1300 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1301 #endif 1302 if (ncomm != MPI_COMM_NULL) { 1303 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1304 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1305 d1 = 0; 1306 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1307 nid = d2; 1308 PetscCallMPI(MPI_Group_free(&ggroup)); 1309 PetscCallMPI(MPI_Group_free(&ngroup)); 1310 PetscCallMPI(MPI_Comm_free(&ncomm)); 1311 } else nid = 0.0; 1312 1313 /* Get connectivity */ 1314 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1315 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1316 1317 /* filter overlapped local cells */ 1318 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1319 PetscCall(ISGetIndices(gid, &idxs)); 1320 PetscCall(ISGetLocalSize(gid, &cum)); 1321 PetscCall(PetscMalloc1(cum, &idxs2)); 1322 for (c = cStart, cum = 0; c < cEnd; c++) { 1323 if (idxs[c - cStart] < 0) continue; 1324 idxs2[cum++] = idxs[c - cStart]; 1325 } 1326 PetscCall(ISRestoreIndices(gid, &idxs)); 1327 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1328 PetscCall(ISDestroy(&gid)); 1329 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1330 1331 /* support for node-aware cell locality */ 1332 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1333 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1334 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1335 PetscCall(VecGetArray(cown, &array)); 1336 for (c = 0; c < numVertices; c++) array[c] = nid; 1337 PetscCall(VecRestoreArray(cown, &array)); 1338 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1339 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1340 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1341 PetscCall(ISDestroy(&acis)); 1342 PetscCall(VecScatterDestroy(&sct)); 1343 PetscCall(VecDestroy(&cown)); 1344 1345 /* compute edgeCut */ 1346 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1347 PetscCall(PetscMalloc1(cum, &work)); 1348 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1349 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1350 PetscCall(ISDestroy(&gid)); 1351 PetscCall(VecGetArray(acown, &array)); 1352 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1353 PetscInt totl; 1354 1355 totl = start[c + 1] - start[c]; 1356 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1357 for (i = 0; i < totl; i++) { 1358 if (work[i] < 0) { 1359 ect += 1; 1360 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1361 } 1362 } 1363 } 1364 PetscCall(PetscFree(work)); 1365 PetscCall(VecRestoreArray(acown, &array)); 1366 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1367 lm[1] = -numVertices; 1368 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1369 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1370 lm[0] = ect; /* edgeCut */ 1371 lm[1] = ectn; /* node-aware edgeCut */ 1372 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1373 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1374 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1375 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1376 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1377 #else 1378 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1379 #endif 1380 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1381 PetscCall(PetscFree(start)); 1382 PetscCall(PetscFree(adjacency)); 1383 PetscCall(VecDestroy(&acown)); 1384 } else { 1385 const char *name; 1386 PetscInt *sizes, *hybsizes, *ghostsizes; 1387 PetscInt locDepth, depth, cellHeight, dim, d; 1388 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1389 PetscInt numLabels, l, maxSize = 17; 1390 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1391 MPI_Comm comm; 1392 PetscMPIInt size, rank; 1393 1394 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1395 PetscCallMPI(MPI_Comm_size(comm, &size)); 1396 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1397 PetscCall(DMGetDimension(dm, &dim)); 1398 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1399 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1400 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1401 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1402 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1403 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1404 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1405 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1406 gcNum = gcEnd - gcStart; 1407 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1408 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1409 for (d = 0; d <= depth; d++) { 1410 PetscInt Nc[2] = {0, 0}, ict; 1411 1412 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1413 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1414 ict = ct0; 1415 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1416 ct0 = (DMPolytopeType)ict; 1417 for (p = pStart; p < pEnd; ++p) { 1418 DMPolytopeType ct; 1419 1420 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1421 if (ct == ct0) ++Nc[0]; 1422 else ++Nc[1]; 1423 } 1424 if (size < maxSize) { 1425 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1426 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1427 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1429 for (p = 0; p < size; ++p) { 1430 if (rank == 0) { 1431 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1432 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1433 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1434 } 1435 } 1436 } else { 1437 PetscInt locMinMax[2]; 1438 1439 locMinMax[0] = Nc[0] + Nc[1]; 1440 locMinMax[1] = Nc[0] + Nc[1]; 1441 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1442 locMinMax[0] = Nc[1]; 1443 locMinMax[1] = Nc[1]; 1444 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1445 if (d == depth) { 1446 locMinMax[0] = gcNum; 1447 locMinMax[1] = gcNum; 1448 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1449 } 1450 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1451 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1452 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1453 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1454 } 1455 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1456 } 1457 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1458 { 1459 const PetscReal *maxCell; 1460 const PetscReal *L; 1461 PetscBool localized; 1462 1463 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1464 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1465 if (L || localized) { 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1467 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1468 if (L) { 1469 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1470 for (d = 0; d < dim; ++d) { 1471 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1473 } 1474 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1475 } 1476 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1477 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1478 } 1479 } 1480 PetscCall(DMGetNumLabels(dm, &numLabels)); 1481 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1482 for (l = 0; l < numLabels; ++l) { 1483 DMLabel label; 1484 const char *name; 1485 IS valueIS; 1486 const PetscInt *values; 1487 PetscInt numValues, v; 1488 1489 PetscCall(DMGetLabelName(dm, l, &name)); 1490 PetscCall(DMGetLabel(dm, name, &label)); 1491 PetscCall(DMLabelGetNumValues(label, &numValues)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1493 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1494 PetscCall(ISGetIndices(valueIS, &values)); 1495 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1496 for (v = 0; v < numValues; ++v) { 1497 PetscInt size; 1498 1499 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1500 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1502 } 1503 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1504 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1505 PetscCall(ISRestoreIndices(valueIS, &values)); 1506 PetscCall(ISDestroy(&valueIS)); 1507 } 1508 { 1509 char **labelNames; 1510 PetscInt Nl = numLabels; 1511 PetscBool flg; 1512 1513 PetscCall(PetscMalloc1(Nl, &labelNames)); 1514 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1515 for (l = 0; l < Nl; ++l) { 1516 DMLabel label; 1517 1518 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1519 if (flg) { 1520 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1521 PetscCall(DMLabelView(label, viewer)); 1522 } 1523 PetscCall(PetscFree(labelNames[l])); 1524 } 1525 PetscCall(PetscFree(labelNames)); 1526 } 1527 /* If no fields are specified, people do not want to see adjacency */ 1528 if (dm->Nf) { 1529 PetscInt f; 1530 1531 for (f = 0; f < dm->Nf; ++f) { 1532 const char *name; 1533 1534 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1535 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1536 PetscCall(PetscViewerASCIIPushTab(viewer)); 1537 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1538 if (dm->fields[f].adjacency[0]) { 1539 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1541 } else { 1542 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1543 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1544 } 1545 PetscCall(PetscViewerASCIIPopTab(viewer)); 1546 } 1547 } 1548 PetscCall(DMGetCoarseDM(dm, &cdm)); 1549 if (cdm) { 1550 PetscCall(PetscViewerASCIIPushTab(viewer)); 1551 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1552 PetscCall(PetscViewerASCIIPopTab(viewer)); 1553 } 1554 } 1555 PetscFunctionReturn(0); 1556 } 1557 1558 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) { 1559 DMPolytopeType ct; 1560 PetscMPIInt rank; 1561 PetscInt cdim; 1562 1563 PetscFunctionBegin; 1564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1565 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1566 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1567 switch (ct) { 1568 case DM_POLYTOPE_SEGMENT: 1569 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1570 switch (cdim) { 1571 case 1: { 1572 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1573 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1574 1575 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1576 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1577 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1578 } break; 1579 case 2: { 1580 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1581 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1582 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1583 1584 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1585 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)); 1586 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)); 1587 } break; 1588 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1589 } 1590 break; 1591 case DM_POLYTOPE_TRIANGLE: 1592 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)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1594 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1595 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1596 break; 1597 case DM_POLYTOPE_QUADRILATERAL: 1598 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)); 1599 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)); 1600 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1601 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1602 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1603 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1604 break; 1605 case DM_POLYTOPE_FV_GHOST: break; 1606 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1607 } 1608 PetscFunctionReturn(0); 1609 } 1610 1611 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) { 1612 DMPolytopeType ct; 1613 PetscReal centroid[2] = {0., 0.}; 1614 PetscMPIInt rank; 1615 PetscInt fillColor, v, e, d; 1616 1617 PetscFunctionBegin; 1618 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1619 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1620 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1621 switch (ct) { 1622 case DM_POLYTOPE_TRIANGLE: { 1623 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1624 1625 for (v = 0; v < 3; ++v) { 1626 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1627 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1628 } 1629 for (e = 0; e < 3; ++e) { 1630 refCoords[0] = refVertices[e * 2 + 0]; 1631 refCoords[1] = refVertices[e * 2 + 1]; 1632 for (d = 1; d <= edgeDiv; ++d) { 1633 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1634 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1635 } 1636 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1637 for (d = 0; d < edgeDiv; ++d) { 1638 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)); 1639 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1640 } 1641 } 1642 } break; 1643 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1644 } 1645 PetscFunctionReturn(0); 1646 } 1647 1648 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) { 1649 PetscDraw draw; 1650 DM cdm; 1651 PetscSection coordSection; 1652 Vec coordinates; 1653 const PetscScalar *coords; 1654 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1655 PetscReal *refCoords, *edgeCoords; 1656 PetscBool isnull, drawAffine = PETSC_TRUE; 1657 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1658 1659 PetscFunctionBegin; 1660 PetscCall(DMGetCoordinateDim(dm, &dim)); 1661 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1662 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1663 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1664 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1665 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1666 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1667 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1668 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1669 1670 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1671 PetscCall(PetscDrawIsNull(draw, &isnull)); 1672 if (isnull) PetscFunctionReturn(0); 1673 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1674 1675 PetscCall(VecGetLocalSize(coordinates, &N)); 1676 PetscCall(VecGetArrayRead(coordinates, &coords)); 1677 for (c = 0; c < N; c += dim) { 1678 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1679 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1680 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1681 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1682 } 1683 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1684 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1685 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1686 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1687 PetscCall(PetscDrawClear(draw)); 1688 1689 for (c = cStart; c < cEnd; ++c) { 1690 PetscScalar *coords = NULL; 1691 PetscInt numCoords; 1692 1693 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1694 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1695 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1696 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1697 } 1698 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1699 PetscCall(PetscDrawFlush(draw)); 1700 PetscCall(PetscDrawPause(draw)); 1701 PetscCall(PetscDrawSave(draw)); 1702 PetscFunctionReturn(0); 1703 } 1704 1705 #if defined(PETSC_HAVE_EXODUSII) 1706 #include <exodusII.h> 1707 #include <petscviewerexodusii.h> 1708 #endif 1709 1710 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) { 1711 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1712 char name[PETSC_MAX_PATH_LEN]; 1713 1714 PetscFunctionBegin; 1715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1716 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1723 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1724 if (iascii) { 1725 PetscViewerFormat format; 1726 PetscCall(PetscViewerGetFormat(viewer, &format)); 1727 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1728 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1729 } else if (ishdf5) { 1730 #if defined(PETSC_HAVE_HDF5) 1731 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1732 #else 1733 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1734 #endif 1735 } else if (isvtk) { 1736 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1737 } else if (isdraw) { 1738 PetscCall(DMPlexView_Draw(dm, viewer)); 1739 } else if (isglvis) { 1740 PetscCall(DMPlexView_GLVis(dm, viewer)); 1741 #if defined(PETSC_HAVE_EXODUSII) 1742 } else if (isexodus) { 1743 /* 1744 exodusII requires that all sets be part of exactly one cell set. 1745 If the dm does not have a "Cell Sets" label defined, we create one 1746 with ID 1, containig all cells. 1747 Note that if the Cell Sets label is defined but does not cover all cells, 1748 we may still have a problem. This should probably be checked here or in the viewer; 1749 */ 1750 PetscInt numCS; 1751 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1752 if (!numCS) { 1753 PetscInt cStart, cEnd, c; 1754 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1755 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1756 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1757 } 1758 PetscCall(DMView_PlexExodusII(dm, viewer)); 1759 #endif 1760 #if defined(PETSC_HAVE_CGNS) 1761 } else if (iscgns) { 1762 PetscCall(DMView_PlexCGNS(dm, viewer)); 1763 #endif 1764 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1765 /* Optionally view the partition */ 1766 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1767 if (flg) { 1768 Vec ranks; 1769 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1770 PetscCall(VecView(ranks, viewer)); 1771 PetscCall(VecDestroy(&ranks)); 1772 } 1773 /* Optionally view a label */ 1774 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1775 if (flg) { 1776 DMLabel label; 1777 Vec val; 1778 1779 PetscCall(DMGetLabel(dm, name, &label)); 1780 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1781 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1782 PetscCall(VecView(val, viewer)); 1783 PetscCall(VecDestroy(&val)); 1784 } 1785 PetscFunctionReturn(0); 1786 } 1787 1788 /*@ 1789 DMPlexTopologyView - Saves a DMPlex topology into a file 1790 1791 Collective on DM 1792 1793 Input Parameters: 1794 + dm - The DM whose topology is to be saved 1795 - viewer - The PetscViewer for saving 1796 1797 Level: advanced 1798 1799 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1800 @*/ 1801 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) { 1802 PetscBool ishdf5; 1803 1804 PetscFunctionBegin; 1805 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1806 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1807 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1808 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1809 if (ishdf5) { 1810 #if defined(PETSC_HAVE_HDF5) 1811 PetscViewerFormat format; 1812 PetscCall(PetscViewerGetFormat(viewer, &format)); 1813 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1814 IS globalPointNumbering; 1815 1816 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1817 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1818 PetscCall(ISDestroy(&globalPointNumbering)); 1819 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1820 #else 1821 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1822 #endif 1823 } 1824 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1825 PetscFunctionReturn(0); 1826 } 1827 1828 /*@ 1829 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1830 1831 Collective on DM 1832 1833 Input Parameters: 1834 + dm - The DM whose coordinates are to be saved 1835 - viewer - The PetscViewer for saving 1836 1837 Level: advanced 1838 1839 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1840 @*/ 1841 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) { 1842 PetscBool ishdf5; 1843 1844 PetscFunctionBegin; 1845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1846 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1848 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1849 if (ishdf5) { 1850 #if defined(PETSC_HAVE_HDF5) 1851 PetscViewerFormat format; 1852 PetscCall(PetscViewerGetFormat(viewer, &format)); 1853 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1854 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1855 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", 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_CoordinatesView, viewer, 0, 0, 0)); 1861 PetscFunctionReturn(0); 1862 } 1863 1864 /*@ 1865 DMPlexLabelsView - Saves DMPlex labels into a file 1866 1867 Collective on DM 1868 1869 Input Parameters: 1870 + dm - The DM whose labels are to be saved 1871 - viewer - The PetscViewer for saving 1872 1873 Level: advanced 1874 1875 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1876 @*/ 1877 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) { 1878 PetscBool ishdf5; 1879 1880 PetscFunctionBegin; 1881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1882 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1883 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1884 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1885 if (ishdf5) { 1886 #if defined(PETSC_HAVE_HDF5) 1887 IS globalPointNumbering; 1888 PetscViewerFormat format; 1889 1890 PetscCall(PetscViewerGetFormat(viewer, &format)); 1891 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1892 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1893 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1894 PetscCall(ISDestroy(&globalPointNumbering)); 1895 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1896 #else 1897 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1898 #endif 1899 } 1900 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1901 PetscFunctionReturn(0); 1902 } 1903 1904 /*@ 1905 DMPlexSectionView - Saves a section associated with a DMPlex 1906 1907 Collective on DM 1908 1909 Input Parameters: 1910 + dm - The DM that contains the topology on which the section to be saved is defined 1911 . viewer - The PetscViewer for saving 1912 - sectiondm - The DM that contains the section to be saved 1913 1914 Level: advanced 1915 1916 Notes: 1917 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. 1918 1919 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. 1920 1921 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1922 @*/ 1923 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) { 1924 PetscBool ishdf5; 1925 1926 PetscFunctionBegin; 1927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1928 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1929 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1931 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1932 if (ishdf5) { 1933 #if defined(PETSC_HAVE_HDF5) 1934 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1935 #else 1936 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1937 #endif 1938 } 1939 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1940 PetscFunctionReturn(0); 1941 } 1942 1943 /*@ 1944 DMPlexGlobalVectorView - Saves a global vector 1945 1946 Collective on DM 1947 1948 Input Parameters: 1949 + dm - The DM that represents the topology 1950 . viewer - The PetscViewer to save data with 1951 . sectiondm - The DM that contains the global section on which vec is defined 1952 - vec - The global vector to be saved 1953 1954 Level: advanced 1955 1956 Notes: 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 Typical calling sequence 1960 $ DMCreate(PETSC_COMM_WORLD, &dm); 1961 $ DMSetType(dm, DMPLEX); 1962 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1963 $ DMClone(dm, §iondm); 1964 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1965 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1966 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1967 $ PetscSectionSetChart(section, pStart, pEnd); 1968 $ PetscSectionSetUp(section); 1969 $ DMSetLocalSection(sectiondm, section); 1970 $ PetscSectionDestroy(§ion); 1971 $ DMGetGlobalVector(sectiondm, &vec); 1972 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1973 $ DMPlexTopologyView(dm, viewer); 1974 $ DMPlexSectionView(dm, viewer, sectiondm); 1975 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1976 $ DMRestoreGlobalVector(sectiondm, &vec); 1977 $ DMDestroy(§iondm); 1978 $ DMDestroy(&dm); 1979 1980 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1981 @*/ 1982 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 1983 PetscBool ishdf5; 1984 1985 PetscFunctionBegin; 1986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1987 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1988 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1989 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1990 /* Check consistency */ 1991 { 1992 PetscSection section; 1993 PetscBool includesConstraints; 1994 PetscInt m, m1; 1995 1996 PetscCall(VecGetLocalSize(vec, &m1)); 1997 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1998 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1999 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2000 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2001 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2002 } 2003 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2004 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2005 if (ishdf5) { 2006 #if defined(PETSC_HAVE_HDF5) 2007 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2008 #else 2009 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2010 #endif 2011 } 2012 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2013 PetscFunctionReturn(0); 2014 } 2015 2016 /*@ 2017 DMPlexLocalVectorView - Saves a local vector 2018 2019 Collective on DM 2020 2021 Input Parameters: 2022 + dm - The DM that represents the topology 2023 . viewer - The PetscViewer to save data with 2024 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2025 - vec - The local vector to be saved 2026 2027 Level: advanced 2028 2029 Notes: 2030 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. 2031 2032 Typical calling sequence 2033 $ DMCreate(PETSC_COMM_WORLD, &dm); 2034 $ DMSetType(dm, DMPLEX); 2035 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2036 $ DMClone(dm, §iondm); 2037 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2038 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2039 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2040 $ PetscSectionSetChart(section, pStart, pEnd); 2041 $ PetscSectionSetUp(section); 2042 $ DMSetLocalSection(sectiondm, section); 2043 $ DMGetLocalVector(sectiondm, &vec); 2044 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2045 $ DMPlexTopologyView(dm, viewer); 2046 $ DMPlexSectionView(dm, viewer, sectiondm); 2047 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2048 $ DMRestoreLocalVector(sectiondm, &vec); 2049 $ DMDestroy(§iondm); 2050 $ DMDestroy(&dm); 2051 2052 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2053 @*/ 2054 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 2055 PetscBool ishdf5; 2056 2057 PetscFunctionBegin; 2058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2059 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2060 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2061 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2062 /* Check consistency */ 2063 { 2064 PetscSection section; 2065 PetscBool includesConstraints; 2066 PetscInt m, m1; 2067 2068 PetscCall(VecGetLocalSize(vec, &m1)); 2069 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2070 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2071 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2072 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2073 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2074 } 2075 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2076 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2077 if (ishdf5) { 2078 #if defined(PETSC_HAVE_HDF5) 2079 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2080 #else 2081 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2082 #endif 2083 } 2084 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2085 PetscFunctionReturn(0); 2086 } 2087 2088 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) { 2089 PetscBool ishdf5; 2090 2091 PetscFunctionBegin; 2092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2093 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2094 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2095 if (ishdf5) { 2096 #if defined(PETSC_HAVE_HDF5) 2097 PetscViewerFormat format; 2098 PetscCall(PetscViewerGetFormat(viewer, &format)); 2099 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2100 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2101 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2102 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2103 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2104 PetscFunctionReturn(0); 2105 #else 2106 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2107 #endif 2108 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2109 } 2110 2111 /*@ 2112 DMPlexTopologyLoad - Loads a topology into a DMPlex 2113 2114 Collective on DM 2115 2116 Input Parameters: 2117 + dm - The DM into which the topology is loaded 2118 - viewer - The PetscViewer for the saved topology 2119 2120 Output Parameters: 2121 . 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 2122 2123 Level: advanced 2124 2125 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2126 @*/ 2127 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) { 2128 PetscBool ishdf5; 2129 2130 PetscFunctionBegin; 2131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2132 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2133 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2134 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2135 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2136 if (ishdf5) { 2137 #if defined(PETSC_HAVE_HDF5) 2138 PetscViewerFormat format; 2139 PetscCall(PetscViewerGetFormat(viewer, &format)); 2140 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2141 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2142 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2143 #else 2144 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2145 #endif 2146 } 2147 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2148 PetscFunctionReturn(0); 2149 } 2150 2151 /*@ 2152 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2153 2154 Collective on DM 2155 2156 Input Parameters: 2157 + dm - The DM into which the coordinates are loaded 2158 . viewer - The PetscViewer for the saved coordinates 2159 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2160 2161 Level: advanced 2162 2163 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2164 @*/ 2165 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2166 PetscBool ishdf5; 2167 2168 PetscFunctionBegin; 2169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2170 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2171 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2172 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2173 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2174 if (ishdf5) { 2175 #if defined(PETSC_HAVE_HDF5) 2176 PetscViewerFormat format; 2177 PetscCall(PetscViewerGetFormat(viewer, &format)); 2178 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2179 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2180 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2181 #else 2182 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2183 #endif 2184 } 2185 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2186 PetscFunctionReturn(0); 2187 } 2188 2189 /*@ 2190 DMPlexLabelsLoad - Loads labels into a DMPlex 2191 2192 Collective on DM 2193 2194 Input Parameters: 2195 + dm - The DM into which the labels are loaded 2196 . viewer - The PetscViewer for the saved labels 2197 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2198 2199 Level: advanced 2200 2201 Notes: 2202 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2203 2204 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2205 @*/ 2206 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2207 PetscBool ishdf5; 2208 2209 PetscFunctionBegin; 2210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2211 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2212 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2213 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2214 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2215 if (ishdf5) { 2216 #if defined(PETSC_HAVE_HDF5) 2217 PetscViewerFormat format; 2218 2219 PetscCall(PetscViewerGetFormat(viewer, &format)); 2220 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2221 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2222 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2223 #else 2224 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2225 #endif 2226 } 2227 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2228 PetscFunctionReturn(0); 2229 } 2230 2231 /*@ 2232 DMPlexSectionLoad - Loads section into a DMPlex 2233 2234 Collective on DM 2235 2236 Input Parameters: 2237 + dm - The DM that represents the topology 2238 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2239 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2240 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2241 2242 Output Parameters 2243 + 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) 2244 - 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) 2245 2246 Level: advanced 2247 2248 Notes: 2249 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. 2250 2251 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. 2252 2253 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. 2254 2255 Example using 2 processes: 2256 $ NX (number of points on dm): 4 2257 $ sectionA : the on-disk section 2258 $ vecA : a vector associated with sectionA 2259 $ sectionB : sectiondm's local section constructed in this function 2260 $ vecB (local) : a vector associated with sectiondm's local section 2261 $ vecB (global) : a vector associated with sectiondm's global section 2262 $ 2263 $ rank 0 rank 1 2264 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2265 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2266 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2267 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2268 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2269 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2270 $ sectionB->atlasDof : 1 0 1 | 1 3 2271 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2272 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2273 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2274 $ 2275 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2276 2277 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2278 @*/ 2279 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) { 2280 PetscBool ishdf5; 2281 2282 PetscFunctionBegin; 2283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2284 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2285 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2286 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2287 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2288 if (localDofSF) PetscValidPointer(localDofSF, 6); 2289 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2290 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2291 if (ishdf5) { 2292 #if defined(PETSC_HAVE_HDF5) 2293 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2294 #else 2295 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2296 #endif 2297 } 2298 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2299 PetscFunctionReturn(0); 2300 } 2301 2302 /*@ 2303 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2304 2305 Collective on DM 2306 2307 Input Parameters: 2308 + dm - The DM that represents the topology 2309 . viewer - The PetscViewer that represents the on-disk vector data 2310 . sectiondm - The DM that contains the global section on which vec is defined 2311 . sf - The SF that migrates the on-disk vector data into vec 2312 - vec - The global vector to set values of 2313 2314 Level: advanced 2315 2316 Notes: 2317 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. 2318 2319 Typical calling sequence 2320 $ DMCreate(PETSC_COMM_WORLD, &dm); 2321 $ DMSetType(dm, DMPLEX); 2322 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2323 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2324 $ DMClone(dm, §iondm); 2325 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2326 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2327 $ DMGetGlobalVector(sectiondm, &vec); 2328 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2329 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2330 $ DMRestoreGlobalVector(sectiondm, &vec); 2331 $ PetscSFDestroy(&gsf); 2332 $ PetscSFDestroy(&sfX); 2333 $ DMDestroy(§iondm); 2334 $ DMDestroy(&dm); 2335 2336 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2337 @*/ 2338 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2339 PetscBool ishdf5; 2340 2341 PetscFunctionBegin; 2342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2344 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2345 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2346 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2347 /* Check consistency */ 2348 { 2349 PetscSection section; 2350 PetscBool includesConstraints; 2351 PetscInt m, m1; 2352 2353 PetscCall(VecGetLocalSize(vec, &m1)); 2354 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2355 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2356 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2357 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2358 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2359 } 2360 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2361 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2362 if (ishdf5) { 2363 #if defined(PETSC_HAVE_HDF5) 2364 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2365 #else 2366 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2367 #endif 2368 } 2369 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2370 PetscFunctionReturn(0); 2371 } 2372 2373 /*@ 2374 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2375 2376 Collective on DM 2377 2378 Input Parameters: 2379 + dm - The DM that represents the topology 2380 . viewer - The PetscViewer that represents the on-disk vector data 2381 . sectiondm - The DM that contains the local section on which vec is defined 2382 . sf - The SF that migrates the on-disk vector data into vec 2383 - vec - The local vector to set values of 2384 2385 Level: advanced 2386 2387 Notes: 2388 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2389 2390 Typical calling sequence 2391 $ DMCreate(PETSC_COMM_WORLD, &dm); 2392 $ DMSetType(dm, DMPLEX); 2393 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2394 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2395 $ DMClone(dm, §iondm); 2396 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2397 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2398 $ DMGetLocalVector(sectiondm, &vec); 2399 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2400 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2401 $ DMRestoreLocalVector(sectiondm, &vec); 2402 $ PetscSFDestroy(&lsf); 2403 $ PetscSFDestroy(&sfX); 2404 $ DMDestroy(§iondm); 2405 $ DMDestroy(&dm); 2406 2407 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2408 @*/ 2409 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2410 PetscBool ishdf5; 2411 2412 PetscFunctionBegin; 2413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2414 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2415 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2416 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2417 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2418 /* Check consistency */ 2419 { 2420 PetscSection section; 2421 PetscBool includesConstraints; 2422 PetscInt m, m1; 2423 2424 PetscCall(VecGetLocalSize(vec, &m1)); 2425 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2426 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2427 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2428 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2429 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2430 } 2431 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2432 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2433 if (ishdf5) { 2434 #if defined(PETSC_HAVE_HDF5) 2435 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2436 #else 2437 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2438 #endif 2439 } 2440 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2441 PetscFunctionReturn(0); 2442 } 2443 2444 PetscErrorCode DMDestroy_Plex(DM dm) { 2445 DM_Plex *mesh = (DM_Plex *)dm->data; 2446 2447 PetscFunctionBegin; 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2460 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2461 if (--mesh->refct > 0) PetscFunctionReturn(0); 2462 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2463 PetscCall(PetscFree(mesh->cones)); 2464 PetscCall(PetscFree(mesh->coneOrientations)); 2465 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2466 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2467 PetscCall(PetscFree(mesh->supports)); 2468 PetscCall(PetscFree(mesh->facesTmp)); 2469 PetscCall(PetscFree(mesh->tetgenOpts)); 2470 PetscCall(PetscFree(mesh->triangleOpts)); 2471 PetscCall(PetscFree(mesh->transformType)); 2472 PetscCall(PetscFree(mesh->distributionName)); 2473 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2474 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2475 PetscCall(ISDestroy(&mesh->subpointIS)); 2476 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2477 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2478 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2479 PetscCall(ISDestroy(&mesh->anchorIS)); 2480 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2481 PetscCall(PetscFree(mesh->parents)); 2482 PetscCall(PetscFree(mesh->childIDs)); 2483 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2484 PetscCall(PetscFree(mesh->children)); 2485 PetscCall(DMDestroy(&mesh->referenceTree)); 2486 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2487 PetscCall(PetscFree(mesh->neighbors)); 2488 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2489 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2490 PetscCall(PetscFree(mesh)); 2491 PetscFunctionReturn(0); 2492 } 2493 2494 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) { 2495 PetscSection sectionGlobal; 2496 PetscInt bs = -1, mbs; 2497 PetscInt localSize, localStart = 0; 2498 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2499 MatType mtype; 2500 ISLocalToGlobalMapping ltog; 2501 2502 PetscFunctionBegin; 2503 PetscCall(MatInitializePackage()); 2504 mtype = dm->mattype; 2505 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2506 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2507 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2508 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2509 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2510 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2511 PetscCall(MatSetType(*J, mtype)); 2512 PetscCall(MatSetFromOptions(*J)); 2513 PetscCall(MatGetBlockSize(*J, &mbs)); 2514 if (mbs > 1) bs = mbs; 2515 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2516 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2517 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2522 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2523 if (!isShell) { 2524 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2525 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2526 PetscInt pStart, pEnd, p, dof, cdof; 2527 2528 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2529 2530 PetscCall(PetscCalloc1(localSize, &pblocks)); 2531 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2532 for (p = pStart; p < pEnd; ++p) { 2533 PetscInt bdof, offset; 2534 2535 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2536 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2537 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2538 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2539 dof = dof < 0 ? -(dof + 1) : dof; 2540 bdof = cdof && (dof - cdof) ? 1 : dof; 2541 if (dof) { 2542 if (bs < 0) { 2543 bs = bdof; 2544 } else if (bs != bdof) { 2545 bs = 1; 2546 } 2547 } 2548 } 2549 /* Must have same blocksize on all procs (some might have no points) */ 2550 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2551 bsLocal[1] = bs; 2552 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2553 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2554 else bs = bsMinMax[0]; 2555 bs = PetscMax(1, bs); 2556 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2557 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2558 PetscCall(MatSetBlockSize(*J, bs)); 2559 PetscCall(MatSetUp(*J)); 2560 } else { 2561 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2562 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2563 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2564 } 2565 { // Consolidate blocks 2566 PetscInt nblocks = 0; 2567 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2568 if (pblocks[i] == 0) continue; 2569 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2570 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]); 2571 } 2572 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2573 } 2574 PetscCall(PetscFree(pblocks)); 2575 } 2576 PetscCall(MatSetDM(*J, dm)); 2577 PetscFunctionReturn(0); 2578 } 2579 2580 /*@ 2581 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2582 2583 Not collective 2584 2585 Input Parameter: 2586 . mesh - The DMPlex 2587 2588 Output Parameters: 2589 . subsection - The subdomain section 2590 2591 Level: developer 2592 2593 .seealso: 2594 @*/ 2595 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) { 2596 DM_Plex *mesh = (DM_Plex *)dm->data; 2597 2598 PetscFunctionBegin; 2599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2600 if (!mesh->subdomainSection) { 2601 PetscSection section; 2602 PetscSF sf; 2603 2604 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2605 PetscCall(DMGetLocalSection(dm, §ion)); 2606 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2607 PetscCall(PetscSFDestroy(&sf)); 2608 } 2609 *subsection = mesh->subdomainSection; 2610 PetscFunctionReturn(0); 2611 } 2612 2613 /*@ 2614 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2615 2616 Not collective 2617 2618 Input Parameter: 2619 . mesh - The DMPlex 2620 2621 Output Parameters: 2622 + pStart - The first mesh point 2623 - pEnd - The upper bound for mesh points 2624 2625 Level: beginner 2626 2627 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2628 @*/ 2629 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) { 2630 DM_Plex *mesh = (DM_Plex *)dm->data; 2631 2632 PetscFunctionBegin; 2633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2634 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2635 PetscFunctionReturn(0); 2636 } 2637 2638 /*@ 2639 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2640 2641 Not collective 2642 2643 Input Parameters: 2644 + mesh - The DMPlex 2645 . pStart - The first mesh point 2646 - pEnd - The upper bound for mesh points 2647 2648 Output Parameters: 2649 2650 Level: beginner 2651 2652 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2653 @*/ 2654 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) { 2655 DM_Plex *mesh = (DM_Plex *)dm->data; 2656 2657 PetscFunctionBegin; 2658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2659 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2660 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2661 PetscFunctionReturn(0); 2662 } 2663 2664 /*@ 2665 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2666 2667 Not collective 2668 2669 Input Parameters: 2670 + mesh - The DMPlex 2671 - p - The point, which must lie in the chart set with DMPlexSetChart() 2672 2673 Output Parameter: 2674 . size - The cone size for point p 2675 2676 Level: beginner 2677 2678 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2679 @*/ 2680 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) { 2681 DM_Plex *mesh = (DM_Plex *)dm->data; 2682 2683 PetscFunctionBegin; 2684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2685 PetscValidIntPointer(size, 3); 2686 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2687 PetscFunctionReturn(0); 2688 } 2689 2690 /*@ 2691 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2692 2693 Not collective 2694 2695 Input Parameters: 2696 + mesh - The DMPlex 2697 . p - The point, which must lie in the chart set with DMPlexSetChart() 2698 - size - The cone size for point p 2699 2700 Output Parameter: 2701 2702 Note: 2703 This should be called after DMPlexSetChart(). 2704 2705 Level: beginner 2706 2707 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2708 @*/ 2709 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) { 2710 DM_Plex *mesh = (DM_Plex *)dm->data; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2715 PetscFunctionReturn(0); 2716 } 2717 2718 /*@ 2719 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2720 2721 Not collective 2722 2723 Input Parameters: 2724 + mesh - The DMPlex 2725 . p - The point, which must lie in the chart set with DMPlexSetChart() 2726 - size - The additional cone size for point p 2727 2728 Output Parameter: 2729 2730 Note: 2731 This should be called after DMPlexSetChart(). 2732 2733 Level: beginner 2734 2735 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2736 @*/ 2737 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) { 2738 DM_Plex *mesh = (DM_Plex *)dm->data; 2739 PetscFunctionBegin; 2740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2741 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2742 PetscFunctionReturn(0); 2743 } 2744 2745 /*@C 2746 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2747 2748 Not collective 2749 2750 Input Parameters: 2751 + dm - The DMPlex 2752 - p - The point, which must lie in the chart set with DMPlexSetChart() 2753 2754 Output Parameter: 2755 . cone - An array of points which are on the in-edges for point p 2756 2757 Level: beginner 2758 2759 Fortran Notes: 2760 Since it returns an array, this routine is only available in Fortran 90, and you must 2761 include petsc.h90 in your code. 2762 You must also call DMPlexRestoreCone() after you finish using the returned array. 2763 DMPlexRestoreCone() is not needed/available in C. 2764 2765 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2766 @*/ 2767 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) { 2768 DM_Plex *mesh = (DM_Plex *)dm->data; 2769 PetscInt off; 2770 2771 PetscFunctionBegin; 2772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2773 PetscValidPointer(cone, 3); 2774 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2775 *cone = &mesh->cones[off]; 2776 PetscFunctionReturn(0); 2777 } 2778 2779 /*@C 2780 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2781 2782 Not collective 2783 2784 Input Parameters: 2785 + dm - The DMPlex 2786 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2787 2788 Output Parameters: 2789 + pConesSection - PetscSection describing the layout of pCones 2790 - pCones - An array of points which are on the in-edges for the point set p 2791 2792 Level: intermediate 2793 2794 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2795 @*/ 2796 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) { 2797 PetscSection cs, newcs; 2798 PetscInt *cones; 2799 PetscInt *newarr = NULL; 2800 PetscInt n; 2801 2802 PetscFunctionBegin; 2803 PetscCall(DMPlexGetCones(dm, &cones)); 2804 PetscCall(DMPlexGetConeSection(dm, &cs)); 2805 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2806 if (pConesSection) *pConesSection = newcs; 2807 if (pCones) { 2808 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2809 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2810 } 2811 PetscFunctionReturn(0); 2812 } 2813 2814 /*@ 2815 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2816 2817 Not collective 2818 2819 Input Parameters: 2820 + dm - The DMPlex 2821 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2822 2823 Output Parameter: 2824 . expandedPoints - An array of vertices recursively expanded from input points 2825 2826 Level: advanced 2827 2828 Notes: 2829 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2830 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2831 2832 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2833 @*/ 2834 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) { 2835 IS *expandedPointsAll; 2836 PetscInt depth; 2837 2838 PetscFunctionBegin; 2839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2840 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2841 PetscValidPointer(expandedPoints, 3); 2842 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2843 *expandedPoints = expandedPointsAll[0]; 2844 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2845 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2846 PetscFunctionReturn(0); 2847 } 2848 2849 /*@ 2850 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). 2851 2852 Not collective 2853 2854 Input Parameters: 2855 + dm - The DMPlex 2856 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2857 2858 Output Parameters: 2859 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2860 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2861 - sections - (optional) An array of sections which describe mappings from points to their cone points 2862 2863 Level: advanced 2864 2865 Notes: 2866 Like DMPlexGetConeTuple() but recursive. 2867 2868 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. 2869 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2870 2871 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: 2872 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2873 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2874 2875 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2876 @*/ 2877 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2878 const PetscInt *arr0 = NULL, *cone = NULL; 2879 PetscInt *arr = NULL, *newarr = NULL; 2880 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2881 IS *expandedPoints_; 2882 PetscSection *sections_; 2883 2884 PetscFunctionBegin; 2885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2886 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2887 if (depth) PetscValidIntPointer(depth, 3); 2888 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2889 if (sections) PetscValidPointer(sections, 5); 2890 PetscCall(ISGetLocalSize(points, &n)); 2891 PetscCall(ISGetIndices(points, &arr0)); 2892 PetscCall(DMPlexGetDepth(dm, &depth_)); 2893 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2894 PetscCall(PetscCalloc1(depth_, §ions_)); 2895 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2896 for (d = depth_ - 1; d >= 0; d--) { 2897 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2898 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2899 for (i = 0; i < n; i++) { 2900 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2901 if (arr[i] >= start && arr[i] < end) { 2902 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2903 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2904 } else { 2905 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2906 } 2907 } 2908 PetscCall(PetscSectionSetUp(sections_[d])); 2909 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2910 PetscCall(PetscMalloc1(newn, &newarr)); 2911 for (i = 0; i < n; i++) { 2912 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2913 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2914 if (cn > 1) { 2915 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2916 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2917 } else { 2918 newarr[co] = arr[i]; 2919 } 2920 } 2921 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2922 arr = newarr; 2923 n = newn; 2924 } 2925 PetscCall(ISRestoreIndices(points, &arr0)); 2926 *depth = depth_; 2927 if (expandedPoints) *expandedPoints = expandedPoints_; 2928 else { 2929 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2930 PetscCall(PetscFree(expandedPoints_)); 2931 } 2932 if (sections) *sections = sections_; 2933 else { 2934 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2935 PetscCall(PetscFree(sections_)); 2936 } 2937 PetscFunctionReturn(0); 2938 } 2939 2940 /*@ 2941 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2942 2943 Not collective 2944 2945 Input Parameters: 2946 + dm - The DMPlex 2947 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2948 2949 Output Parameters: 2950 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2951 . expandedPoints - (optional) An array of recursively expanded cones 2952 - sections - (optional) An array of sections which describe mappings from points to their cone points 2953 2954 Level: advanced 2955 2956 Notes: 2957 See DMPlexGetConeRecursive() for details. 2958 2959 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2960 @*/ 2961 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2962 PetscInt d, depth_; 2963 2964 PetscFunctionBegin; 2965 PetscCall(DMPlexGetDepth(dm, &depth_)); 2966 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2967 if (depth) *depth = 0; 2968 if (expandedPoints) { 2969 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2970 PetscCall(PetscFree(*expandedPoints)); 2971 } 2972 if (sections) { 2973 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2974 PetscCall(PetscFree(*sections)); 2975 } 2976 PetscFunctionReturn(0); 2977 } 2978 2979 /*@ 2980 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 2981 2982 Not collective 2983 2984 Input Parameters: 2985 + mesh - The DMPlex 2986 . p - The point, which must lie in the chart set with DMPlexSetChart() 2987 - cone - An array of points which are on the in-edges for point p 2988 2989 Output Parameter: 2990 2991 Note: 2992 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2993 2994 Level: beginner 2995 2996 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2997 @*/ 2998 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) { 2999 DM_Plex *mesh = (DM_Plex *)dm->data; 3000 PetscInt pStart, pEnd; 3001 PetscInt dof, off, c; 3002 3003 PetscFunctionBegin; 3004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3005 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3006 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3007 if (dof) PetscValidIntPointer(cone, 3); 3008 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3009 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); 3010 for (c = 0; c < dof; ++c) { 3011 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); 3012 mesh->cones[off + c] = cone[c]; 3013 } 3014 PetscFunctionReturn(0); 3015 } 3016 3017 /*@C 3018 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3019 3020 Not collective 3021 3022 Input Parameters: 3023 + mesh - The DMPlex 3024 - p - The point, which must lie in the chart set with DMPlexSetChart() 3025 3026 Output Parameter: 3027 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3028 integer giving the prescription for cone traversal. 3029 3030 Level: beginner 3031 3032 Notes: 3033 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3034 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3035 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3036 with the identity. 3037 3038 Fortran Notes: 3039 Since it returns an array, this routine is only available in Fortran 90, and you must 3040 include petsc.h90 in your code. 3041 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3042 DMPlexRestoreConeOrientation() is not needed/available in C. 3043 3044 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3045 @*/ 3046 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) { 3047 DM_Plex *mesh = (DM_Plex *)dm->data; 3048 PetscInt off; 3049 3050 PetscFunctionBegin; 3051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3052 if (PetscDefined(USE_DEBUG)) { 3053 PetscInt dof; 3054 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3055 if (dof) PetscValidPointer(coneOrientation, 3); 3056 } 3057 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3058 3059 *coneOrientation = &mesh->coneOrientations[off]; 3060 PetscFunctionReturn(0); 3061 } 3062 3063 /*@ 3064 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3065 3066 Not collective 3067 3068 Input Parameters: 3069 + mesh - The DMPlex 3070 . p - The point, which must lie in the chart set with DMPlexSetChart() 3071 - coneOrientation - An array of orientations 3072 Output Parameter: 3073 3074 Notes: 3075 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3076 3077 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3078 3079 Level: beginner 3080 3081 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3082 @*/ 3083 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) { 3084 DM_Plex *mesh = (DM_Plex *)dm->data; 3085 PetscInt pStart, pEnd; 3086 PetscInt dof, off, c; 3087 3088 PetscFunctionBegin; 3089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3090 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3091 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3092 if (dof) PetscValidIntPointer(coneOrientation, 3); 3093 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3094 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); 3095 for (c = 0; c < dof; ++c) { 3096 PetscInt cdof, o = coneOrientation[c]; 3097 3098 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3099 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); 3100 mesh->coneOrientations[off + c] = o; 3101 } 3102 PetscFunctionReturn(0); 3103 } 3104 3105 /*@ 3106 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3107 3108 Not collective 3109 3110 Input Parameters: 3111 + mesh - The DMPlex 3112 . p - The point, which must lie in the chart set with DMPlexSetChart() 3113 . conePos - The local index in the cone where the point should be put 3114 - conePoint - The mesh point to insert 3115 3116 Level: beginner 3117 3118 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3119 @*/ 3120 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) { 3121 DM_Plex *mesh = (DM_Plex *)dm->data; 3122 PetscInt pStart, pEnd; 3123 PetscInt dof, off; 3124 3125 PetscFunctionBegin; 3126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3127 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3128 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); 3129 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); 3130 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3131 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3132 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); 3133 mesh->cones[off + conePos] = conePoint; 3134 PetscFunctionReturn(0); 3135 } 3136 3137 /*@ 3138 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3139 3140 Not collective 3141 3142 Input Parameters: 3143 + mesh - The DMPlex 3144 . p - The point, which must lie in the chart set with DMPlexSetChart() 3145 . conePos - The local index in the cone where the point should be put 3146 - coneOrientation - The point orientation to insert 3147 3148 Level: beginner 3149 3150 Notes: 3151 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3152 3153 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3154 @*/ 3155 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) { 3156 DM_Plex *mesh = (DM_Plex *)dm->data; 3157 PetscInt pStart, pEnd; 3158 PetscInt dof, off; 3159 3160 PetscFunctionBegin; 3161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3162 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3163 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3164 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3165 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3166 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); 3167 mesh->coneOrientations[off + conePos] = coneOrientation; 3168 PetscFunctionReturn(0); 3169 } 3170 3171 /*@ 3172 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3173 3174 Not collective 3175 3176 Input Parameters: 3177 + mesh - The DMPlex 3178 - p - The point, which must lie in the chart set with DMPlexSetChart() 3179 3180 Output Parameter: 3181 . size - The support size for point p 3182 3183 Level: beginner 3184 3185 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3186 @*/ 3187 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) { 3188 DM_Plex *mesh = (DM_Plex *)dm->data; 3189 3190 PetscFunctionBegin; 3191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3192 PetscValidIntPointer(size, 3); 3193 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3194 PetscFunctionReturn(0); 3195 } 3196 3197 /*@ 3198 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3199 3200 Not collective 3201 3202 Input Parameters: 3203 + mesh - The DMPlex 3204 . p - The point, which must lie in the chart set with DMPlexSetChart() 3205 - size - The support size for point p 3206 3207 Output Parameter: 3208 3209 Note: 3210 This should be called after DMPlexSetChart(). 3211 3212 Level: beginner 3213 3214 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3215 @*/ 3216 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) { 3217 DM_Plex *mesh = (DM_Plex *)dm->data; 3218 3219 PetscFunctionBegin; 3220 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3221 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3222 PetscFunctionReturn(0); 3223 } 3224 3225 /*@C 3226 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3227 3228 Not collective 3229 3230 Input Parameters: 3231 + mesh - The DMPlex 3232 - p - The point, which must lie in the chart set with DMPlexSetChart() 3233 3234 Output Parameter: 3235 . support - An array of points which are on the out-edges for point p 3236 3237 Level: beginner 3238 3239 Fortran Notes: 3240 Since it returns an array, this routine is only available in Fortran 90, and you must 3241 include petsc.h90 in your code. 3242 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3243 DMPlexRestoreSupport() is not needed/available in C. 3244 3245 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3246 @*/ 3247 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) { 3248 DM_Plex *mesh = (DM_Plex *)dm->data; 3249 PetscInt off; 3250 3251 PetscFunctionBegin; 3252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3253 PetscValidPointer(support, 3); 3254 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3255 *support = &mesh->supports[off]; 3256 PetscFunctionReturn(0); 3257 } 3258 3259 /*@ 3260 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3261 3262 Not collective 3263 3264 Input Parameters: 3265 + mesh - The DMPlex 3266 . p - The point, which must lie in the chart set with DMPlexSetChart() 3267 - support - An array of points which are on the out-edges for point p 3268 3269 Output Parameter: 3270 3271 Note: 3272 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3273 3274 Level: beginner 3275 3276 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3277 @*/ 3278 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) { 3279 DM_Plex *mesh = (DM_Plex *)dm->data; 3280 PetscInt pStart, pEnd; 3281 PetscInt dof, off, c; 3282 3283 PetscFunctionBegin; 3284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3285 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3286 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3287 if (dof) PetscValidIntPointer(support, 3); 3288 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3289 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); 3290 for (c = 0; c < dof; ++c) { 3291 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); 3292 mesh->supports[off + c] = support[c]; 3293 } 3294 PetscFunctionReturn(0); 3295 } 3296 3297 /*@ 3298 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3299 3300 Not collective 3301 3302 Input Parameters: 3303 + mesh - The DMPlex 3304 . p - The point, which must lie in the chart set with DMPlexSetChart() 3305 . supportPos - The local index in the cone where the point should be put 3306 - supportPoint - The mesh point to insert 3307 3308 Level: beginner 3309 3310 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3311 @*/ 3312 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) { 3313 DM_Plex *mesh = (DM_Plex *)dm->data; 3314 PetscInt pStart, pEnd; 3315 PetscInt dof, off; 3316 3317 PetscFunctionBegin; 3318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3319 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3320 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3321 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3322 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); 3323 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); 3324 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); 3325 mesh->supports[off + supportPos] = supportPoint; 3326 PetscFunctionReturn(0); 3327 } 3328 3329 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3330 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3331 switch (ct) { 3332 case DM_POLYTOPE_SEGMENT: 3333 if (o == -1) return -2; 3334 break; 3335 case DM_POLYTOPE_TRIANGLE: 3336 if (o == -3) return -1; 3337 if (o == -2) return -3; 3338 if (o == -1) return -2; 3339 break; 3340 case DM_POLYTOPE_QUADRILATERAL: 3341 if (o == -4) return -2; 3342 if (o == -3) return -1; 3343 if (o == -2) return -4; 3344 if (o == -1) return -3; 3345 break; 3346 default: return o; 3347 } 3348 return o; 3349 } 3350 3351 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3352 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3353 switch (ct) { 3354 case DM_POLYTOPE_SEGMENT: 3355 if ((o == -2) || (o == 1)) return -1; 3356 if (o == -1) return 0; 3357 break; 3358 case DM_POLYTOPE_TRIANGLE: 3359 if (o == -3) return -2; 3360 if (o == -2) return -1; 3361 if (o == -1) return -3; 3362 break; 3363 case DM_POLYTOPE_QUADRILATERAL: 3364 if (o == -4) return -2; 3365 if (o == -3) return -1; 3366 if (o == -2) return -4; 3367 if (o == -1) return -3; 3368 break; 3369 default: return o; 3370 } 3371 return o; 3372 } 3373 3374 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3375 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) { 3376 PetscInt pStart, pEnd, p; 3377 3378 PetscFunctionBegin; 3379 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3380 for (p = pStart; p < pEnd; ++p) { 3381 const PetscInt *cone, *ornt; 3382 PetscInt coneSize, c; 3383 3384 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3385 PetscCall(DMPlexGetCone(dm, p, &cone)); 3386 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3387 for (c = 0; c < coneSize; ++c) { 3388 DMPolytopeType ct; 3389 const PetscInt o = ornt[c]; 3390 3391 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3392 switch (ct) { 3393 case DM_POLYTOPE_SEGMENT: 3394 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3395 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3396 break; 3397 case DM_POLYTOPE_TRIANGLE: 3398 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3399 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3400 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3401 break; 3402 case DM_POLYTOPE_QUADRILATERAL: 3403 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3404 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3405 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3406 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3407 break; 3408 default: break; 3409 } 3410 } 3411 } 3412 PetscFunctionReturn(0); 3413 } 3414 3415 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3416 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3417 PetscInt *closure; 3418 const PetscInt *tmp = NULL, *tmpO = NULL; 3419 PetscInt off = 0, tmpSize, t; 3420 3421 PetscFunctionBeginHot; 3422 if (ornt) { 3423 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3424 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3425 } 3426 if (*points) { 3427 closure = *points; 3428 } else { 3429 PetscInt maxConeSize, maxSupportSize; 3430 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3431 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3432 } 3433 if (useCone) { 3434 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3435 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3436 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3437 } else { 3438 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3439 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3440 } 3441 if (ct == DM_POLYTOPE_UNKNOWN) { 3442 closure[off++] = p; 3443 closure[off++] = 0; 3444 for (t = 0; t < tmpSize; ++t) { 3445 closure[off++] = tmp[t]; 3446 closure[off++] = tmpO ? tmpO[t] : 0; 3447 } 3448 } else { 3449 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3450 3451 /* We assume that cells with a valid type have faces with a valid type */ 3452 closure[off++] = p; 3453 closure[off++] = ornt; 3454 for (t = 0; t < tmpSize; ++t) { 3455 DMPolytopeType ft; 3456 3457 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3458 closure[off++] = tmp[arr[t]]; 3459 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3460 } 3461 } 3462 if (numPoints) *numPoints = tmpSize + 1; 3463 if (points) *points = closure; 3464 PetscFunctionReturn(0); 3465 } 3466 3467 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3468 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) { 3469 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3470 const PetscInt *cone, *ornt; 3471 PetscInt *pts, *closure = NULL; 3472 DMPolytopeType ft; 3473 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3474 PetscInt dim, coneSize, c, d, clSize, cl; 3475 3476 PetscFunctionBeginHot; 3477 PetscCall(DMGetDimension(dm, &dim)); 3478 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3479 PetscCall(DMPlexGetCone(dm, point, &cone)); 3480 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3481 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3482 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3483 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3484 maxSize = PetscMax(coneSeries, supportSeries); 3485 if (*points) { 3486 pts = *points; 3487 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3488 c = 0; 3489 pts[c++] = point; 3490 pts[c++] = o; 3491 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3492 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3493 for (cl = 0; cl < clSize * 2; cl += 2) { 3494 pts[c++] = closure[cl]; 3495 pts[c++] = closure[cl + 1]; 3496 } 3497 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3498 for (cl = 0; cl < clSize * 2; cl += 2) { 3499 pts[c++] = closure[cl]; 3500 pts[c++] = closure[cl + 1]; 3501 } 3502 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3503 for (d = 2; d < coneSize; ++d) { 3504 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3505 pts[c++] = cone[arr[d * 2 + 0]]; 3506 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3507 } 3508 if (dim >= 3) { 3509 for (d = 2; d < coneSize; ++d) { 3510 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3511 const PetscInt *fcone, *fornt; 3512 PetscInt fconeSize, fc, i; 3513 3514 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3515 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3516 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3517 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3518 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3519 for (fc = 0; fc < fconeSize; ++fc) { 3520 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3521 const PetscInt co = farr[fc * 2 + 1]; 3522 3523 for (i = 0; i < c; i += 2) 3524 if (pts[i] == cp) break; 3525 if (i == c) { 3526 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3527 pts[c++] = cp; 3528 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3529 } 3530 } 3531 } 3532 } 3533 *numPoints = c / 2; 3534 *points = pts; 3535 PetscFunctionReturn(0); 3536 } 3537 3538 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3539 DMPolytopeType ct; 3540 PetscInt *closure, *fifo; 3541 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3542 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3543 PetscInt depth, maxSize; 3544 3545 PetscFunctionBeginHot; 3546 PetscCall(DMPlexGetDepth(dm, &depth)); 3547 if (depth == 1) { 3548 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3549 PetscFunctionReturn(0); 3550 } 3551 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3552 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3553 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3554 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3555 PetscFunctionReturn(0); 3556 } 3557 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3558 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3559 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3560 maxSize = PetscMax(coneSeries, supportSeries); 3561 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3562 if (*points) { 3563 closure = *points; 3564 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3565 closure[closureSize++] = p; 3566 closure[closureSize++] = ornt; 3567 fifo[fifoSize++] = p; 3568 fifo[fifoSize++] = ornt; 3569 fifo[fifoSize++] = ct; 3570 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3571 while (fifoSize - fifoStart) { 3572 const PetscInt q = fifo[fifoStart++]; 3573 const PetscInt o = fifo[fifoStart++]; 3574 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3575 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3576 const PetscInt *tmp, *tmpO; 3577 PetscInt tmpSize, t; 3578 3579 if (PetscDefined(USE_DEBUG)) { 3580 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3581 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); 3582 } 3583 if (useCone) { 3584 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3585 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3586 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3587 } else { 3588 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3589 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3590 tmpO = NULL; 3591 } 3592 for (t = 0; t < tmpSize; ++t) { 3593 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3594 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3595 const PetscInt cp = tmp[ip]; 3596 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3597 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3598 PetscInt c; 3599 3600 /* Check for duplicate */ 3601 for (c = 0; c < closureSize; c += 2) { 3602 if (closure[c] == cp) break; 3603 } 3604 if (c == closureSize) { 3605 closure[closureSize++] = cp; 3606 closure[closureSize++] = co; 3607 fifo[fifoSize++] = cp; 3608 fifo[fifoSize++] = co; 3609 fifo[fifoSize++] = ct; 3610 } 3611 } 3612 } 3613 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3614 if (numPoints) *numPoints = closureSize / 2; 3615 if (points) *points = closure; 3616 PetscFunctionReturn(0); 3617 } 3618 3619 /*@C 3620 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3621 3622 Not collective 3623 3624 Input Parameters: 3625 + dm - The DMPlex 3626 . p - The mesh point 3627 - useCone - PETSC_TRUE for the closure, otherwise return the star 3628 3629 Input/Output Parameter: 3630 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3631 if NULL on input, internal storage will be returned, otherwise the provided array is used 3632 3633 Output Parameter: 3634 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3635 3636 Note: 3637 If using internal storage (points is NULL on input), each call overwrites the last output. 3638 3639 Fortran Note: 3640 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3641 3642 Level: beginner 3643 3644 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3645 @*/ 3646 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3647 PetscFunctionBeginHot; 3648 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3649 if (numPoints) PetscValidIntPointer(numPoints, 4); 3650 if (points) PetscValidPointer(points, 5); 3651 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3652 PetscFunctionReturn(0); 3653 } 3654 3655 /*@C 3656 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3657 3658 Not collective 3659 3660 Input Parameters: 3661 + dm - The DMPlex 3662 . p - The mesh point 3663 . useCone - PETSC_TRUE for the closure, otherwise return the star 3664 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3665 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3666 3667 Note: 3668 If not using internal storage (points is not NULL on input), this call is unnecessary 3669 3670 Level: beginner 3671 3672 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3673 @*/ 3674 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3675 PetscFunctionBeginHot; 3676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3677 if (numPoints) *numPoints = 0; 3678 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3679 PetscFunctionReturn(0); 3680 } 3681 3682 /*@ 3683 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3684 3685 Not collective 3686 3687 Input Parameter: 3688 . mesh - The DMPlex 3689 3690 Output Parameters: 3691 + maxConeSize - The maximum number of in-edges 3692 - maxSupportSize - The maximum number of out-edges 3693 3694 Level: beginner 3695 3696 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3697 @*/ 3698 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) { 3699 DM_Plex *mesh = (DM_Plex *)dm->data; 3700 3701 PetscFunctionBegin; 3702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3703 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3704 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3705 PetscFunctionReturn(0); 3706 } 3707 3708 PetscErrorCode DMSetUp_Plex(DM dm) { 3709 DM_Plex *mesh = (DM_Plex *)dm->data; 3710 PetscInt size, maxSupportSize; 3711 3712 PetscFunctionBegin; 3713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3714 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3715 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3716 PetscCall(PetscMalloc1(size, &mesh->cones)); 3717 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3718 PetscCall(PetscLogObjectMemory((PetscObject)dm, size * 2 * sizeof(PetscInt))); 3719 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3720 if (maxSupportSize) { 3721 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3722 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3723 PetscCall(PetscMalloc1(size, &mesh->supports)); 3724 PetscCall(PetscLogObjectMemory((PetscObject)dm, size * sizeof(PetscInt))); 3725 } 3726 PetscFunctionReturn(0); 3727 } 3728 3729 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) { 3730 PetscFunctionBegin; 3731 if (subdm) PetscCall(DMClone(dm, subdm)); 3732 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3733 if (subdm) (*subdm)->useNatural = dm->useNatural; 3734 if (dm->useNatural && dm->sfMigration) { 3735 PetscSF sfNatural; 3736 3737 (*subdm)->sfMigration = dm->sfMigration; 3738 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3739 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3740 (*subdm)->sfNatural = sfNatural; 3741 } 3742 PetscFunctionReturn(0); 3743 } 3744 3745 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) { 3746 PetscInt i = 0; 3747 3748 PetscFunctionBegin; 3749 PetscCall(DMClone(dms[0], superdm)); 3750 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3751 (*superdm)->useNatural = PETSC_FALSE; 3752 for (i = 0; i < len; i++) { 3753 if (dms[i]->useNatural && dms[i]->sfMigration) { 3754 PetscSF sfNatural; 3755 3756 (*superdm)->sfMigration = dms[i]->sfMigration; 3757 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3758 (*superdm)->useNatural = PETSC_TRUE; 3759 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3760 (*superdm)->sfNatural = sfNatural; 3761 break; 3762 } 3763 } 3764 PetscFunctionReturn(0); 3765 } 3766 3767 /*@ 3768 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3769 3770 Not collective 3771 3772 Input Parameter: 3773 . mesh - The DMPlex 3774 3775 Output Parameter: 3776 3777 Note: 3778 This should be called after all calls to DMPlexSetCone() 3779 3780 Level: beginner 3781 3782 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3783 @*/ 3784 PetscErrorCode DMPlexSymmetrize(DM dm) { 3785 DM_Plex *mesh = (DM_Plex *)dm->data; 3786 PetscInt *offsets; 3787 PetscInt supportSize; 3788 PetscInt pStart, pEnd, p; 3789 3790 PetscFunctionBegin; 3791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3792 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3793 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3794 /* Calculate support sizes */ 3795 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3796 for (p = pStart; p < pEnd; ++p) { 3797 PetscInt dof, off, c; 3798 3799 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3800 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3801 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3802 } 3803 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3804 /* Calculate supports */ 3805 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3806 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3807 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3808 for (p = pStart; p < pEnd; ++p) { 3809 PetscInt dof, off, c; 3810 3811 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3812 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3813 for (c = off; c < off + dof; ++c) { 3814 const PetscInt q = mesh->cones[c]; 3815 PetscInt offS; 3816 3817 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3818 3819 mesh->supports[offS + offsets[q]] = p; 3820 ++offsets[q]; 3821 } 3822 } 3823 PetscCall(PetscFree(offsets)); 3824 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3825 PetscFunctionReturn(0); 3826 } 3827 3828 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) { 3829 IS stratumIS; 3830 3831 PetscFunctionBegin; 3832 if (pStart >= pEnd) PetscFunctionReturn(0); 3833 if (PetscDefined(USE_DEBUG)) { 3834 PetscInt qStart, qEnd, numLevels, level; 3835 PetscBool overlap = PETSC_FALSE; 3836 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3837 for (level = 0; level < numLevels; level++) { 3838 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3839 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 3840 overlap = PETSC_TRUE; 3841 break; 3842 } 3843 } 3844 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); 3845 } 3846 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 3847 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3848 PetscCall(ISDestroy(&stratumIS)); 3849 PetscFunctionReturn(0); 3850 } 3851 3852 /*@ 3853 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3854 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3855 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3856 the DAG. 3857 3858 Collective on dm 3859 3860 Input Parameter: 3861 . mesh - The DMPlex 3862 3863 Output Parameter: 3864 3865 Notes: 3866 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3867 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3868 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3869 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3870 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3871 3872 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3873 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3874 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 3875 to interpolate only that one (e0), so that 3876 $ cone(c0) = {e0, v2} 3877 $ cone(e0) = {v0, v1} 3878 If DMPlexStratify() is run on this mesh, it will give depths 3879 $ depth 0 = {v0, v1, v2} 3880 $ depth 1 = {e0, c0} 3881 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3882 3883 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3884 3885 Level: beginner 3886 3887 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3888 @*/ 3889 PetscErrorCode DMPlexStratify(DM dm) { 3890 DM_Plex *mesh = (DM_Plex *)dm->data; 3891 DMLabel label; 3892 PetscInt pStart, pEnd, p; 3893 PetscInt numRoots = 0, numLeaves = 0; 3894 3895 PetscFunctionBegin; 3896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3897 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 3898 3899 /* Create depth label */ 3900 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3901 PetscCall(DMCreateLabel(dm, "depth")); 3902 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3903 3904 { 3905 /* Initialize roots and count leaves */ 3906 PetscInt sMin = PETSC_MAX_INT; 3907 PetscInt sMax = PETSC_MIN_INT; 3908 PetscInt coneSize, supportSize; 3909 3910 for (p = pStart; p < pEnd; ++p) { 3911 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3912 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3913 if (!coneSize && supportSize) { 3914 sMin = PetscMin(p, sMin); 3915 sMax = PetscMax(p, sMax); 3916 ++numRoots; 3917 } else if (!supportSize && coneSize) { 3918 ++numLeaves; 3919 } else if (!supportSize && !coneSize) { 3920 /* Isolated points */ 3921 sMin = PetscMin(p, sMin); 3922 sMax = PetscMax(p, sMax); 3923 } 3924 } 3925 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 3926 } 3927 3928 if (numRoots + numLeaves == (pEnd - pStart)) { 3929 PetscInt sMin = PETSC_MAX_INT; 3930 PetscInt sMax = PETSC_MIN_INT; 3931 PetscInt coneSize, supportSize; 3932 3933 for (p = pStart; p < pEnd; ++p) { 3934 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3935 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3936 if (!supportSize && coneSize) { 3937 sMin = PetscMin(p, sMin); 3938 sMax = PetscMax(p, sMax); 3939 } 3940 } 3941 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 3942 } else { 3943 PetscInt level = 0; 3944 PetscInt qStart, qEnd, q; 3945 3946 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3947 while (qEnd > qStart) { 3948 PetscInt sMin = PETSC_MAX_INT; 3949 PetscInt sMax = PETSC_MIN_INT; 3950 3951 for (q = qStart; q < qEnd; ++q) { 3952 const PetscInt *support; 3953 PetscInt supportSize, s; 3954 3955 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3956 PetscCall(DMPlexGetSupport(dm, q, &support)); 3957 for (s = 0; s < supportSize; ++s) { 3958 sMin = PetscMin(support[s], sMin); 3959 sMax = PetscMax(support[s], sMax); 3960 } 3961 } 3962 PetscCall(DMLabelGetNumValues(label, &level)); 3963 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 3964 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3965 } 3966 } 3967 { /* just in case there is an empty process */ 3968 PetscInt numValues, maxValues = 0, v; 3969 3970 PetscCall(DMLabelGetNumValues(label, &numValues)); 3971 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 3972 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 3973 } 3974 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 3975 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 3976 PetscFunctionReturn(0); 3977 } 3978 3979 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) { 3980 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3981 PetscInt dim, depth, pheight, coneSize; 3982 3983 PetscFunctionBeginHot; 3984 PetscCall(DMGetDimension(dm, &dim)); 3985 PetscCall(DMPlexGetDepth(dm, &depth)); 3986 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3987 pheight = depth - pdepth; 3988 if (depth <= 1) { 3989 switch (pdepth) { 3990 case 0: ct = DM_POLYTOPE_POINT; break; 3991 case 1: 3992 switch (coneSize) { 3993 case 2: ct = DM_POLYTOPE_SEGMENT; break; 3994 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 3995 case 4: 3996 switch (dim) { 3997 case 2: ct = DM_POLYTOPE_QUADRILATERAL; break; 3998 case 3: ct = DM_POLYTOPE_TETRAHEDRON; break; 3999 default: break; 4000 } 4001 break; 4002 case 5: ct = DM_POLYTOPE_PYRAMID; break; 4003 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4004 case 8: ct = DM_POLYTOPE_HEXAHEDRON; break; 4005 default: break; 4006 } 4007 } 4008 } else { 4009 if (pdepth == 0) { 4010 ct = DM_POLYTOPE_POINT; 4011 } else if (pheight == 0) { 4012 switch (dim) { 4013 case 1: 4014 switch (coneSize) { 4015 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4016 default: break; 4017 } 4018 break; 4019 case 2: 4020 switch (coneSize) { 4021 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4022 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4023 default: break; 4024 } 4025 break; 4026 case 3: 4027 switch (coneSize) { 4028 case 4: ct = DM_POLYTOPE_TETRAHEDRON; break; 4029 case 5: { 4030 const PetscInt *cone; 4031 PetscInt faceConeSize; 4032 4033 PetscCall(DMPlexGetCone(dm, p, &cone)); 4034 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4035 switch (faceConeSize) { 4036 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4037 case 4: ct = DM_POLYTOPE_PYRAMID; break; 4038 } 4039 } break; 4040 case 6: ct = DM_POLYTOPE_HEXAHEDRON; break; 4041 default: break; 4042 } 4043 break; 4044 default: break; 4045 } 4046 } else if (pheight > 0) { 4047 switch (coneSize) { 4048 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4049 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4050 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4051 default: break; 4052 } 4053 } 4054 } 4055 *pt = ct; 4056 PetscFunctionReturn(0); 4057 } 4058 4059 /*@ 4060 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4061 4062 Collective on dm 4063 4064 Input Parameter: 4065 . mesh - The DMPlex 4066 4067 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4068 4069 Level: developer 4070 4071 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4072 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4073 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4074 4075 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4076 @*/ 4077 PetscErrorCode DMPlexComputeCellTypes(DM dm) { 4078 DM_Plex *mesh; 4079 DMLabel ctLabel; 4080 PetscInt pStart, pEnd, p; 4081 4082 PetscFunctionBegin; 4083 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4084 mesh = (DM_Plex *)dm->data; 4085 PetscCall(DMCreateLabel(dm, "celltype")); 4086 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4087 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4088 for (p = pStart; p < pEnd; ++p) { 4089 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4090 PetscInt pdepth; 4091 4092 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4093 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4094 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4095 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4096 } 4097 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4098 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4099 PetscFunctionReturn(0); 4100 } 4101 4102 /*@C 4103 DMPlexGetJoin - Get an array for the join of the set of points 4104 4105 Not Collective 4106 4107 Input Parameters: 4108 + dm - The DMPlex object 4109 . numPoints - The number of input points for the join 4110 - points - The input points 4111 4112 Output Parameters: 4113 + numCoveredPoints - The number of points in the join 4114 - coveredPoints - The points in the join 4115 4116 Level: intermediate 4117 4118 Note: Currently, this is restricted to a single level join 4119 4120 Fortran Notes: 4121 Since it returns an array, this routine is only available in Fortran 90, and you must 4122 include petsc.h90 in your code. 4123 4124 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4125 4126 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4127 @*/ 4128 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4129 DM_Plex *mesh = (DM_Plex *)dm->data; 4130 PetscInt *join[2]; 4131 PetscInt joinSize, i = 0; 4132 PetscInt dof, off, p, c, m; 4133 PetscInt maxSupportSize; 4134 4135 PetscFunctionBegin; 4136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4137 PetscValidIntPointer(points, 3); 4138 PetscValidIntPointer(numCoveredPoints, 4); 4139 PetscValidPointer(coveredPoints, 5); 4140 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4141 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4142 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4143 /* Copy in support of first point */ 4144 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4145 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4146 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4147 /* Check each successive support */ 4148 for (p = 1; p < numPoints; ++p) { 4149 PetscInt newJoinSize = 0; 4150 4151 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4152 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4153 for (c = 0; c < dof; ++c) { 4154 const PetscInt point = mesh->supports[off + c]; 4155 4156 for (m = 0; m < joinSize; ++m) { 4157 if (point == join[i][m]) { 4158 join[1 - i][newJoinSize++] = point; 4159 break; 4160 } 4161 } 4162 } 4163 joinSize = newJoinSize; 4164 i = 1 - i; 4165 } 4166 *numCoveredPoints = joinSize; 4167 *coveredPoints = join[i]; 4168 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4169 PetscFunctionReturn(0); 4170 } 4171 4172 /*@C 4173 DMPlexRestoreJoin - Restore an array for the join of the set of points 4174 4175 Not Collective 4176 4177 Input Parameters: 4178 + dm - The DMPlex object 4179 . numPoints - The number of input points for the join 4180 - points - The input points 4181 4182 Output Parameters: 4183 + numCoveredPoints - The number of points in the join 4184 - coveredPoints - The points in the join 4185 4186 Fortran Notes: 4187 Since it returns an array, this routine is only available in Fortran 90, and you must 4188 include petsc.h90 in your code. 4189 4190 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4191 4192 Level: intermediate 4193 4194 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4195 @*/ 4196 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4197 PetscFunctionBegin; 4198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4199 if (points) PetscValidIntPointer(points, 3); 4200 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4201 PetscValidPointer(coveredPoints, 5); 4202 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4203 if (numCoveredPoints) *numCoveredPoints = 0; 4204 PetscFunctionReturn(0); 4205 } 4206 4207 /*@C 4208 DMPlexGetFullJoin - Get an array for the join of the set of points 4209 4210 Not Collective 4211 4212 Input Parameters: 4213 + dm - The DMPlex object 4214 . numPoints - The number of input points for the join 4215 - points - The input points 4216 4217 Output Parameters: 4218 + numCoveredPoints - The number of points in the join 4219 - coveredPoints - The points in the join 4220 4221 Fortran Notes: 4222 Since it returns an array, this routine is only available in Fortran 90, and you must 4223 include petsc.h90 in your code. 4224 4225 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4226 4227 Level: intermediate 4228 4229 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4230 @*/ 4231 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4232 PetscInt *offsets, **closures; 4233 PetscInt *join[2]; 4234 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4235 PetscInt p, d, c, m, ms; 4236 4237 PetscFunctionBegin; 4238 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4239 PetscValidIntPointer(points, 3); 4240 PetscValidIntPointer(numCoveredPoints, 4); 4241 PetscValidPointer(coveredPoints, 5); 4242 4243 PetscCall(DMPlexGetDepth(dm, &depth)); 4244 PetscCall(PetscCalloc1(numPoints, &closures)); 4245 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4246 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4247 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4248 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4249 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4250 4251 for (p = 0; p < numPoints; ++p) { 4252 PetscInt closureSize; 4253 4254 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4255 4256 offsets[p * (depth + 2) + 0] = 0; 4257 for (d = 0; d < depth + 1; ++d) { 4258 PetscInt pStart, pEnd, i; 4259 4260 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4261 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4262 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4263 offsets[p * (depth + 2) + d + 1] = i; 4264 break; 4265 } 4266 } 4267 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4268 } 4269 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); 4270 } 4271 for (d = 0; d < depth + 1; ++d) { 4272 PetscInt dof; 4273 4274 /* Copy in support of first point */ 4275 dof = offsets[d + 1] - offsets[d]; 4276 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4277 /* Check each successive cone */ 4278 for (p = 1; p < numPoints && joinSize; ++p) { 4279 PetscInt newJoinSize = 0; 4280 4281 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4282 for (c = 0; c < dof; ++c) { 4283 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4284 4285 for (m = 0; m < joinSize; ++m) { 4286 if (point == join[i][m]) { 4287 join[1 - i][newJoinSize++] = point; 4288 break; 4289 } 4290 } 4291 } 4292 joinSize = newJoinSize; 4293 i = 1 - i; 4294 } 4295 if (joinSize) break; 4296 } 4297 *numCoveredPoints = joinSize; 4298 *coveredPoints = join[i]; 4299 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4300 PetscCall(PetscFree(closures)); 4301 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4302 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4303 PetscFunctionReturn(0); 4304 } 4305 4306 /*@C 4307 DMPlexGetMeet - Get an array for the meet of the set of points 4308 4309 Not Collective 4310 4311 Input Parameters: 4312 + dm - The DMPlex object 4313 . numPoints - The number of input points for the meet 4314 - points - The input points 4315 4316 Output Parameters: 4317 + numCoveredPoints - The number of points in the meet 4318 - coveredPoints - The points in the meet 4319 4320 Level: intermediate 4321 4322 Note: Currently, this is restricted to a single level meet 4323 4324 Fortran Notes: 4325 Since it returns an array, this routine is only available in Fortran 90, and you must 4326 include petsc.h90 in your code. 4327 4328 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4329 4330 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4331 @*/ 4332 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) { 4333 DM_Plex *mesh = (DM_Plex *)dm->data; 4334 PetscInt *meet[2]; 4335 PetscInt meetSize, i = 0; 4336 PetscInt dof, off, p, c, m; 4337 PetscInt maxConeSize; 4338 4339 PetscFunctionBegin; 4340 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4341 PetscValidIntPointer(points, 3); 4342 PetscValidIntPointer(numCoveringPoints, 4); 4343 PetscValidPointer(coveringPoints, 5); 4344 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4345 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4346 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4347 /* Copy in cone of first point */ 4348 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4349 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4350 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4351 /* Check each successive cone */ 4352 for (p = 1; p < numPoints; ++p) { 4353 PetscInt newMeetSize = 0; 4354 4355 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4356 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4357 for (c = 0; c < dof; ++c) { 4358 const PetscInt point = mesh->cones[off + c]; 4359 4360 for (m = 0; m < meetSize; ++m) { 4361 if (point == meet[i][m]) { 4362 meet[1 - i][newMeetSize++] = point; 4363 break; 4364 } 4365 } 4366 } 4367 meetSize = newMeetSize; 4368 i = 1 - i; 4369 } 4370 *numCoveringPoints = meetSize; 4371 *coveringPoints = meet[i]; 4372 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4373 PetscFunctionReturn(0); 4374 } 4375 4376 /*@C 4377 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4378 4379 Not Collective 4380 4381 Input Parameters: 4382 + dm - The DMPlex object 4383 . numPoints - The number of input points for the meet 4384 - points - The input points 4385 4386 Output Parameters: 4387 + numCoveredPoints - The number of points in the meet 4388 - coveredPoints - The points in the meet 4389 4390 Level: intermediate 4391 4392 Fortran Notes: 4393 Since it returns an array, this routine is only available in Fortran 90, and you must 4394 include petsc.h90 in your code. 4395 4396 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4397 4398 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4399 @*/ 4400 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4401 PetscFunctionBegin; 4402 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4403 if (points) PetscValidIntPointer(points, 3); 4404 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4405 PetscValidPointer(coveredPoints, 5); 4406 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4407 if (numCoveredPoints) *numCoveredPoints = 0; 4408 PetscFunctionReturn(0); 4409 } 4410 4411 /*@C 4412 DMPlexGetFullMeet - Get an array for the meet of the set of points 4413 4414 Not Collective 4415 4416 Input Parameters: 4417 + dm - The DMPlex object 4418 . numPoints - The number of input points for the meet 4419 - points - The input points 4420 4421 Output Parameters: 4422 + numCoveredPoints - The number of points in the meet 4423 - coveredPoints - The points in the meet 4424 4425 Level: intermediate 4426 4427 Fortran Notes: 4428 Since it returns an array, this routine is only available in Fortran 90, and you must 4429 include petsc.h90 in your code. 4430 4431 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4432 4433 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4434 @*/ 4435 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4436 PetscInt *offsets, **closures; 4437 PetscInt *meet[2]; 4438 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4439 PetscInt p, h, c, m, mc; 4440 4441 PetscFunctionBegin; 4442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4443 PetscValidIntPointer(points, 3); 4444 PetscValidIntPointer(numCoveredPoints, 4); 4445 PetscValidPointer(coveredPoints, 5); 4446 4447 PetscCall(DMPlexGetDepth(dm, &height)); 4448 PetscCall(PetscMalloc1(numPoints, &closures)); 4449 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4450 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4451 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4452 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4453 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4454 4455 for (p = 0; p < numPoints; ++p) { 4456 PetscInt closureSize; 4457 4458 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4459 4460 offsets[p * (height + 2) + 0] = 0; 4461 for (h = 0; h < height + 1; ++h) { 4462 PetscInt pStart, pEnd, i; 4463 4464 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4465 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4466 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4467 offsets[p * (height + 2) + h + 1] = i; 4468 break; 4469 } 4470 } 4471 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4472 } 4473 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); 4474 } 4475 for (h = 0; h < height + 1; ++h) { 4476 PetscInt dof; 4477 4478 /* Copy in cone of first point */ 4479 dof = offsets[h + 1] - offsets[h]; 4480 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4481 /* Check each successive cone */ 4482 for (p = 1; p < numPoints && meetSize; ++p) { 4483 PetscInt newMeetSize = 0; 4484 4485 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4486 for (c = 0; c < dof; ++c) { 4487 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4488 4489 for (m = 0; m < meetSize; ++m) { 4490 if (point == meet[i][m]) { 4491 meet[1 - i][newMeetSize++] = point; 4492 break; 4493 } 4494 } 4495 } 4496 meetSize = newMeetSize; 4497 i = 1 - i; 4498 } 4499 if (meetSize) break; 4500 } 4501 *numCoveredPoints = meetSize; 4502 *coveredPoints = meet[i]; 4503 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4504 PetscCall(PetscFree(closures)); 4505 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4506 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4507 PetscFunctionReturn(0); 4508 } 4509 4510 /*@C 4511 DMPlexEqual - Determine if two DMs have the same topology 4512 4513 Not Collective 4514 4515 Input Parameters: 4516 + dmA - A DMPlex object 4517 - dmB - A DMPlex object 4518 4519 Output Parameters: 4520 . equal - PETSC_TRUE if the topologies are identical 4521 4522 Level: intermediate 4523 4524 Notes: 4525 We are not solving graph isomorphism, so we do not permutation. 4526 4527 .seealso: `DMPlexGetCone()` 4528 @*/ 4529 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) { 4530 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4531 4532 PetscFunctionBegin; 4533 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4534 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4535 PetscValidBoolPointer(equal, 3); 4536 4537 *equal = PETSC_FALSE; 4538 PetscCall(DMPlexGetDepth(dmA, &depth)); 4539 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4540 if (depth != depthB) PetscFunctionReturn(0); 4541 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4542 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4543 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4544 for (p = pStart; p < pEnd; ++p) { 4545 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4546 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4547 4548 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4549 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4550 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4551 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4552 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4553 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4554 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4555 for (c = 0; c < coneSize; ++c) { 4556 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4557 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4558 } 4559 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4560 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4561 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4562 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4563 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4564 for (s = 0; s < supportSize; ++s) { 4565 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4566 } 4567 } 4568 *equal = PETSC_TRUE; 4569 PetscFunctionReturn(0); 4570 } 4571 4572 /*@C 4573 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4574 4575 Not Collective 4576 4577 Input Parameters: 4578 + dm - The DMPlex 4579 . cellDim - The cell dimension 4580 - numCorners - The number of vertices on a cell 4581 4582 Output Parameters: 4583 . numFaceVertices - The number of vertices on a face 4584 4585 Level: developer 4586 4587 Notes: 4588 Of course this can only work for a restricted set of symmetric shapes 4589 4590 .seealso: `DMPlexGetCone()` 4591 @*/ 4592 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) { 4593 MPI_Comm comm; 4594 4595 PetscFunctionBegin; 4596 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4597 PetscValidIntPointer(numFaceVertices, 4); 4598 switch (cellDim) { 4599 case 0: *numFaceVertices = 0; break; 4600 case 1: *numFaceVertices = 1; break; 4601 case 2: 4602 switch (numCorners) { 4603 case 3: /* triangle */ 4604 *numFaceVertices = 2; /* Edge has 2 vertices */ 4605 break; 4606 case 4: /* quadrilateral */ 4607 *numFaceVertices = 2; /* Edge has 2 vertices */ 4608 break; 4609 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4610 *numFaceVertices = 3; /* Edge has 3 vertices */ 4611 break; 4612 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4613 *numFaceVertices = 3; /* Edge has 3 vertices */ 4614 break; 4615 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4616 } 4617 break; 4618 case 3: 4619 switch (numCorners) { 4620 case 4: /* tetradehdron */ 4621 *numFaceVertices = 3; /* Face has 3 vertices */ 4622 break; 4623 case 6: /* tet cohesive cells */ 4624 *numFaceVertices = 4; /* Face has 4 vertices */ 4625 break; 4626 case 8: /* hexahedron */ 4627 *numFaceVertices = 4; /* Face has 4 vertices */ 4628 break; 4629 case 9: /* tet cohesive Lagrange cells */ 4630 *numFaceVertices = 6; /* Face has 6 vertices */ 4631 break; 4632 case 10: /* quadratic tetrahedron */ 4633 *numFaceVertices = 6; /* Face has 6 vertices */ 4634 break; 4635 case 12: /* hex cohesive Lagrange cells */ 4636 *numFaceVertices = 6; /* Face has 6 vertices */ 4637 break; 4638 case 18: /* quadratic tet cohesive Lagrange cells */ 4639 *numFaceVertices = 6; /* Face has 6 vertices */ 4640 break; 4641 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4642 *numFaceVertices = 9; /* Face has 9 vertices */ 4643 break; 4644 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4645 } 4646 break; 4647 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4648 } 4649 PetscFunctionReturn(0); 4650 } 4651 4652 /*@ 4653 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4654 4655 Not Collective 4656 4657 Input Parameter: 4658 . dm - The DMPlex object 4659 4660 Output Parameter: 4661 . depthLabel - The DMLabel recording point depth 4662 4663 Level: developer 4664 4665 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4666 @*/ 4667 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) { 4668 PetscFunctionBegin; 4669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4670 PetscValidPointer(depthLabel, 2); 4671 *depthLabel = dm->depthLabel; 4672 PetscFunctionReturn(0); 4673 } 4674 4675 /*@ 4676 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4677 4678 Not Collective 4679 4680 Input Parameter: 4681 . dm - The DMPlex object 4682 4683 Output Parameter: 4684 . depth - The number of strata (breadth first levels) in the DAG 4685 4686 Level: developer 4687 4688 Notes: 4689 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4690 The point depth is described more in detail in DMPlexGetDepthStratum(). 4691 An empty mesh gives -1. 4692 4693 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4694 @*/ 4695 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) { 4696 DMLabel label; 4697 PetscInt d = 0; 4698 4699 PetscFunctionBegin; 4700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4701 PetscValidIntPointer(depth, 2); 4702 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4703 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4704 *depth = d - 1; 4705 PetscFunctionReturn(0); 4706 } 4707 4708 /*@ 4709 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4710 4711 Not Collective 4712 4713 Input Parameters: 4714 + dm - The DMPlex object 4715 - depth - The requested depth 4716 4717 Output Parameters: 4718 + start - The first point at this depth 4719 - end - One beyond the last point at this depth 4720 4721 Notes: 4722 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4723 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4724 higher dimension, e.g., "edges". 4725 4726 Level: developer 4727 4728 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4729 @*/ 4730 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) { 4731 DMLabel label; 4732 PetscInt pStart, pEnd; 4733 4734 PetscFunctionBegin; 4735 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4736 if (start) { 4737 PetscValidIntPointer(start, 3); 4738 *start = 0; 4739 } 4740 if (end) { 4741 PetscValidIntPointer(end, 4); 4742 *end = 0; 4743 } 4744 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4745 if (pStart == pEnd) PetscFunctionReturn(0); 4746 if (depth < 0) { 4747 if (start) *start = pStart; 4748 if (end) *end = pEnd; 4749 PetscFunctionReturn(0); 4750 } 4751 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4752 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4753 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4754 PetscFunctionReturn(0); 4755 } 4756 4757 /*@ 4758 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4759 4760 Not Collective 4761 4762 Input Parameters: 4763 + dm - The DMPlex object 4764 - height - The requested height 4765 4766 Output Parameters: 4767 + start - The first point at this height 4768 - end - One beyond the last point at this height 4769 4770 Notes: 4771 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4772 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4773 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4774 4775 Level: developer 4776 4777 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4778 @*/ 4779 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) { 4780 DMLabel label; 4781 PetscInt depth, pStart, pEnd; 4782 4783 PetscFunctionBegin; 4784 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4785 if (start) { 4786 PetscValidIntPointer(start, 3); 4787 *start = 0; 4788 } 4789 if (end) { 4790 PetscValidIntPointer(end, 4); 4791 *end = 0; 4792 } 4793 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4794 if (pStart == pEnd) PetscFunctionReturn(0); 4795 if (height < 0) { 4796 if (start) *start = pStart; 4797 if (end) *end = pEnd; 4798 PetscFunctionReturn(0); 4799 } 4800 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4801 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4802 PetscCall(DMLabelGetNumValues(label, &depth)); 4803 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 4804 PetscFunctionReturn(0); 4805 } 4806 4807 /*@ 4808 DMPlexGetPointDepth - Get the depth of a given point 4809 4810 Not Collective 4811 4812 Input Parameters: 4813 + dm - The DMPlex object 4814 - point - The point 4815 4816 Output Parameter: 4817 . depth - The depth of the point 4818 4819 Level: intermediate 4820 4821 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4822 @*/ 4823 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) { 4824 PetscFunctionBegin; 4825 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4826 PetscValidIntPointer(depth, 3); 4827 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4828 PetscFunctionReturn(0); 4829 } 4830 4831 /*@ 4832 DMPlexGetPointHeight - Get the height of a given point 4833 4834 Not Collective 4835 4836 Input Parameters: 4837 + dm - The DMPlex object 4838 - point - The point 4839 4840 Output Parameter: 4841 . height - The height of the point 4842 4843 Level: intermediate 4844 4845 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4846 @*/ 4847 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) { 4848 PetscInt n, pDepth; 4849 4850 PetscFunctionBegin; 4851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4852 PetscValidIntPointer(height, 3); 4853 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4854 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4855 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4856 PetscFunctionReturn(0); 4857 } 4858 4859 /*@ 4860 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4861 4862 Not Collective 4863 4864 Input Parameter: 4865 . dm - The DMPlex object 4866 4867 Output Parameter: 4868 . celltypeLabel - The DMLabel recording cell polytope type 4869 4870 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4871 DMCreateLabel(dm, "celltype") beforehand. 4872 4873 Level: developer 4874 4875 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4876 @*/ 4877 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) { 4878 PetscFunctionBegin; 4879 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4880 PetscValidPointer(celltypeLabel, 2); 4881 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4882 *celltypeLabel = dm->celltypeLabel; 4883 PetscFunctionReturn(0); 4884 } 4885 4886 /*@ 4887 DMPlexGetCellType - Get the polytope type of a given cell 4888 4889 Not Collective 4890 4891 Input Parameters: 4892 + dm - The DMPlex object 4893 - cell - The cell 4894 4895 Output Parameter: 4896 . celltype - The polytope type of the cell 4897 4898 Level: intermediate 4899 4900 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4901 @*/ 4902 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) { 4903 DMLabel label; 4904 PetscInt ct; 4905 4906 PetscFunctionBegin; 4907 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4908 PetscValidPointer(celltype, 3); 4909 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4910 PetscCall(DMLabelGetValue(label, cell, &ct)); 4911 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4912 *celltype = (DMPolytopeType)ct; 4913 PetscFunctionReturn(0); 4914 } 4915 4916 /*@ 4917 DMPlexSetCellType - Set the polytope type of a given cell 4918 4919 Not Collective 4920 4921 Input Parameters: 4922 + dm - The DMPlex object 4923 . cell - The cell 4924 - celltype - The polytope type of the cell 4925 4926 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4927 is executed. This function will override the computed type. However, if automatic classification will not succeed 4928 and a user wants to manually specify all types, the classification must be disabled by calling 4929 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4930 4931 Level: advanced 4932 4933 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 4934 @*/ 4935 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) { 4936 DMLabel label; 4937 4938 PetscFunctionBegin; 4939 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4940 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4941 PetscCall(DMLabelSetValue(label, cell, celltype)); 4942 PetscFunctionReturn(0); 4943 } 4944 4945 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) { 4946 PetscSection section, s; 4947 Mat m; 4948 PetscInt maxHeight; 4949 4950 PetscFunctionBegin; 4951 PetscCall(DMClone(dm, cdm)); 4952 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 4953 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 4954 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 4955 PetscCall(DMSetLocalSection(*cdm, section)); 4956 PetscCall(PetscSectionDestroy(§ion)); 4957 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 4958 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 4959 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 4960 PetscCall(PetscSectionDestroy(&s)); 4961 PetscCall(MatDestroy(&m)); 4962 4963 PetscCall(DMSetNumFields(*cdm, 1)); 4964 PetscCall(DMCreateDS(*cdm)); 4965 PetscFunctionReturn(0); 4966 } 4967 4968 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) { 4969 Vec coordsLocal, cellCoordsLocal; 4970 DM coordsDM, cellCoordsDM; 4971 4972 PetscFunctionBegin; 4973 *field = NULL; 4974 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 4975 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 4976 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 4977 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 4978 if (coordsLocal && coordsDM) { 4979 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 4980 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 4981 } 4982 PetscFunctionReturn(0); 4983 } 4984 4985 /*@C 4986 DMPlexGetConeSection - Return a section which describes the layout of cone data 4987 4988 Not Collective 4989 4990 Input Parameters: 4991 . dm - The DMPlex object 4992 4993 Output Parameter: 4994 . section - The PetscSection object 4995 4996 Level: developer 4997 4998 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 4999 @*/ 5000 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) { 5001 DM_Plex *mesh = (DM_Plex *)dm->data; 5002 5003 PetscFunctionBegin; 5004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5005 if (section) *section = mesh->coneSection; 5006 PetscFunctionReturn(0); 5007 } 5008 5009 /*@C 5010 DMPlexGetSupportSection - Return a section which describes the layout of support data 5011 5012 Not Collective 5013 5014 Input Parameters: 5015 . dm - The DMPlex object 5016 5017 Output Parameter: 5018 . section - The PetscSection object 5019 5020 Level: developer 5021 5022 .seealso: `DMPlexGetConeSection()` 5023 @*/ 5024 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) { 5025 DM_Plex *mesh = (DM_Plex *)dm->data; 5026 5027 PetscFunctionBegin; 5028 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5029 if (section) *section = mesh->supportSection; 5030 PetscFunctionReturn(0); 5031 } 5032 5033 /*@C 5034 DMPlexGetCones - Return cone data 5035 5036 Not Collective 5037 5038 Input Parameters: 5039 . dm - The DMPlex object 5040 5041 Output Parameter: 5042 . cones - The cone for each point 5043 5044 Level: developer 5045 5046 .seealso: `DMPlexGetConeSection()` 5047 @*/ 5048 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) { 5049 DM_Plex *mesh = (DM_Plex *)dm->data; 5050 5051 PetscFunctionBegin; 5052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5053 if (cones) *cones = mesh->cones; 5054 PetscFunctionReturn(0); 5055 } 5056 5057 /*@C 5058 DMPlexGetConeOrientations - Return cone orientation data 5059 5060 Not Collective 5061 5062 Input Parameters: 5063 . dm - The DMPlex object 5064 5065 Output Parameter: 5066 . coneOrientations - The array of cone orientations for all points 5067 5068 Level: developer 5069 5070 Notes: 5071 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5072 5073 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5074 5075 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5076 @*/ 5077 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) { 5078 DM_Plex *mesh = (DM_Plex *)dm->data; 5079 5080 PetscFunctionBegin; 5081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5082 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5083 PetscFunctionReturn(0); 5084 } 5085 5086 /******************************** FEM Support **********************************/ 5087 5088 /* 5089 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5090 representing a line in the section. 5091 */ 5092 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) { 5093 PetscFunctionBeginHot; 5094 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5095 if (line < 0) { 5096 *k = 0; 5097 *Nc = 0; 5098 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5099 *k = 1; 5100 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5101 /* An order k SEM disc has k-1 dofs on an edge */ 5102 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5103 *k = *k / *Nc + 1; 5104 } 5105 PetscFunctionReturn(0); 5106 } 5107 5108 /*@ 5109 5110 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5111 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5112 section provided (or the section of the DM). 5113 5114 Input Parameters: 5115 + dm - The DM 5116 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5117 - section - The PetscSection to reorder, or NULL for the default section 5118 5119 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5120 degree of the basis. 5121 5122 Example: 5123 A typical interpolated single-quad mesh might order points as 5124 .vb 5125 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5126 5127 v4 -- e6 -- v3 5128 | | 5129 e7 c0 e8 5130 | | 5131 v1 -- e5 -- v2 5132 .ve 5133 5134 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5135 dofs in the order of points, e.g., 5136 .vb 5137 c0 -> [0,1,2,3] 5138 v1 -> [4] 5139 ... 5140 e5 -> [8, 9] 5141 .ve 5142 5143 which corresponds to the dofs 5144 .vb 5145 6 10 11 7 5146 13 2 3 15 5147 12 0 1 14 5148 4 8 9 5 5149 .ve 5150 5151 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5152 .vb 5153 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5154 .ve 5155 5156 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5157 .vb 5158 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5159 .ve 5160 5161 Level: developer 5162 5163 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5164 @*/ 5165 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) { 5166 DMLabel label; 5167 PetscInt dim, depth = -1, eStart = -1, Nf; 5168 PetscBool vertexchart; 5169 5170 PetscFunctionBegin; 5171 PetscCall(DMGetDimension(dm, &dim)); 5172 if (dim < 1) PetscFunctionReturn(0); 5173 if (point < 0) { 5174 PetscInt sStart, sEnd; 5175 5176 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5177 point = sEnd - sStart ? sStart : point; 5178 } 5179 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5180 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5181 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5182 if (depth == 1) { 5183 eStart = point; 5184 } else if (depth == dim) { 5185 const PetscInt *cone; 5186 5187 PetscCall(DMPlexGetCone(dm, point, &cone)); 5188 if (dim == 2) eStart = cone[0]; 5189 else if (dim == 3) { 5190 const PetscInt *cone2; 5191 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5192 eStart = cone2[0]; 5193 } 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); 5194 } 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); 5195 { /* Determine whether the chart covers all points or just vertices. */ 5196 PetscInt pStart, pEnd, cStart, cEnd; 5197 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5198 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5199 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5200 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5201 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5202 } 5203 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5204 for (PetscInt d = 1; d <= dim; d++) { 5205 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5206 PetscInt *perm; 5207 5208 for (f = 0; f < Nf; ++f) { 5209 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5210 size += PetscPowInt(k + 1, d) * Nc; 5211 } 5212 PetscCall(PetscMalloc1(size, &perm)); 5213 for (f = 0; f < Nf; ++f) { 5214 switch (d) { 5215 case 1: 5216 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5217 /* 5218 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5219 We want [ vtx0; edge of length k-1; vtx1 ] 5220 */ 5221 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5222 for (i = 0; i < k - 1; i++) 5223 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5224 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5225 foffset = offset; 5226 break; 5227 case 2: 5228 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5229 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5230 /* The SEM order is 5231 5232 v_lb, {e_b}, v_rb, 5233 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5234 v_lt, reverse {e_t}, v_rt 5235 */ 5236 { 5237 const PetscInt of = 0; 5238 const PetscInt oeb = of + PetscSqr(k - 1); 5239 const PetscInt oer = oeb + (k - 1); 5240 const PetscInt oet = oer + (k - 1); 5241 const PetscInt oel = oet + (k - 1); 5242 const PetscInt ovlb = oel + (k - 1); 5243 const PetscInt ovrb = ovlb + 1; 5244 const PetscInt ovrt = ovrb + 1; 5245 const PetscInt ovlt = ovrt + 1; 5246 PetscInt o; 5247 5248 /* bottom */ 5249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5250 for (o = oeb; o < oer; ++o) 5251 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5252 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5253 /* middle */ 5254 for (i = 0; i < k - 1; ++i) { 5255 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5256 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5257 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5258 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5259 } 5260 /* top */ 5261 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5262 for (o = oel - 1; o >= oet; --o) 5263 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5264 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5265 foffset = offset; 5266 } 5267 break; 5268 case 3: 5269 /* The original hex closure is 5270 5271 {c, 5272 f_b, f_t, f_f, f_b, f_r, f_l, 5273 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5274 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5275 */ 5276 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5277 /* The SEM order is 5278 Bottom Slice 5279 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5280 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5281 v_blb, {e_bb}, v_brb, 5282 5283 Middle Slice (j) 5284 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5285 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5286 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5287 5288 Top Slice 5289 v_tlf, {e_tf}, v_trf, 5290 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5291 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5292 */ 5293 { 5294 const PetscInt oc = 0; 5295 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5296 const PetscInt oft = ofb + PetscSqr(k - 1); 5297 const PetscInt off = oft + PetscSqr(k - 1); 5298 const PetscInt ofk = off + PetscSqr(k - 1); 5299 const PetscInt ofr = ofk + PetscSqr(k - 1); 5300 const PetscInt ofl = ofr + PetscSqr(k - 1); 5301 const PetscInt oebl = ofl + PetscSqr(k - 1); 5302 const PetscInt oebb = oebl + (k - 1); 5303 const PetscInt oebr = oebb + (k - 1); 5304 const PetscInt oebf = oebr + (k - 1); 5305 const PetscInt oetf = oebf + (k - 1); 5306 const PetscInt oetr = oetf + (k - 1); 5307 const PetscInt oetb = oetr + (k - 1); 5308 const PetscInt oetl = oetb + (k - 1); 5309 const PetscInt oerf = oetl + (k - 1); 5310 const PetscInt oelf = oerf + (k - 1); 5311 const PetscInt oelb = oelf + (k - 1); 5312 const PetscInt oerb = oelb + (k - 1); 5313 const PetscInt ovblf = oerb + (k - 1); 5314 const PetscInt ovblb = ovblf + 1; 5315 const PetscInt ovbrb = ovblb + 1; 5316 const PetscInt ovbrf = ovbrb + 1; 5317 const PetscInt ovtlf = ovbrf + 1; 5318 const PetscInt ovtrf = ovtlf + 1; 5319 const PetscInt ovtrb = ovtrf + 1; 5320 const PetscInt ovtlb = ovtrb + 1; 5321 PetscInt o, n; 5322 5323 /* Bottom Slice */ 5324 /* bottom */ 5325 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5326 for (o = oetf - 1; o >= oebf; --o) 5327 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5328 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5329 /* middle */ 5330 for (i = 0; i < k - 1; ++i) { 5331 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5332 for (n = 0; n < k - 1; ++n) { 5333 o = ofb + n * (k - 1) + i; 5334 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5335 } 5336 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5337 } 5338 /* top */ 5339 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5340 for (o = oebb; o < oebr; ++o) 5341 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5342 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5343 5344 /* Middle Slice */ 5345 for (j = 0; j < k - 1; ++j) { 5346 /* bottom */ 5347 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5348 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5349 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5350 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5351 /* middle */ 5352 for (i = 0; i < k - 1; ++i) { 5353 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5354 for (n = 0; n < k - 1; ++n) 5355 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5356 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5357 } 5358 /* top */ 5359 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5360 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5361 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5362 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5363 } 5364 5365 /* Top Slice */ 5366 /* bottom */ 5367 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5368 for (o = oetf; o < oetr; ++o) 5369 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5370 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5371 /* middle */ 5372 for (i = 0; i < k - 1; ++i) { 5373 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5374 for (n = 0; n < k - 1; ++n) 5375 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5376 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5377 } 5378 /* top */ 5379 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5380 for (o = oetl - 1; o >= oetb; --o) 5381 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5382 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5383 5384 foffset = offset; 5385 } 5386 break; 5387 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5388 } 5389 } 5390 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5391 /* Check permutation */ 5392 { 5393 PetscInt *check; 5394 5395 PetscCall(PetscMalloc1(size, &check)); 5396 for (i = 0; i < size; ++i) { 5397 check[i] = -1; 5398 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5399 } 5400 for (i = 0; i < size; ++i) check[perm[i]] = i; 5401 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5402 PetscCall(PetscFree(check)); 5403 } 5404 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5405 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5406 PetscInt *loc_perm; 5407 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5408 for (PetscInt i = 0; i < size; i++) { 5409 loc_perm[i] = perm[i]; 5410 loc_perm[size + i] = size + perm[i]; 5411 } 5412 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5413 } 5414 } 5415 PetscFunctionReturn(0); 5416 } 5417 5418 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) { 5419 PetscDS prob; 5420 PetscInt depth, Nf, h; 5421 DMLabel label; 5422 5423 PetscFunctionBeginHot; 5424 PetscCall(DMGetDS(dm, &prob)); 5425 Nf = prob->Nf; 5426 label = dm->depthLabel; 5427 *dspace = NULL; 5428 if (field < Nf) { 5429 PetscObject disc = prob->disc[field]; 5430 5431 if (disc->classid == PETSCFE_CLASSID) { 5432 PetscDualSpace dsp; 5433 5434 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5435 PetscCall(DMLabelGetNumValues(label, &depth)); 5436 PetscCall(DMLabelGetValue(label, point, &h)); 5437 h = depth - 1 - h; 5438 if (h) { 5439 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5440 } else { 5441 *dspace = dsp; 5442 } 5443 } 5444 } 5445 PetscFunctionReturn(0); 5446 } 5447 5448 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5449 PetscScalar *array; 5450 const PetscScalar *vArray; 5451 const PetscInt *cone, *coneO; 5452 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5453 5454 PetscFunctionBeginHot; 5455 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5456 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5457 PetscCall(DMPlexGetCone(dm, point, &cone)); 5458 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5459 if (!values || !*values) { 5460 if ((point >= pStart) && (point < pEnd)) { 5461 PetscInt dof; 5462 5463 PetscCall(PetscSectionGetDof(section, point, &dof)); 5464 size += dof; 5465 } 5466 for (p = 0; p < numPoints; ++p) { 5467 const PetscInt cp = cone[p]; 5468 PetscInt dof; 5469 5470 if ((cp < pStart) || (cp >= pEnd)) continue; 5471 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5472 size += dof; 5473 } 5474 if (!values) { 5475 if (csize) *csize = size; 5476 PetscFunctionReturn(0); 5477 } 5478 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5479 } else { 5480 array = *values; 5481 } 5482 size = 0; 5483 PetscCall(VecGetArrayRead(v, &vArray)); 5484 if ((point >= pStart) && (point < pEnd)) { 5485 PetscInt dof, off, d; 5486 const PetscScalar *varr; 5487 5488 PetscCall(PetscSectionGetDof(section, point, &dof)); 5489 PetscCall(PetscSectionGetOffset(section, point, &off)); 5490 varr = &vArray[off]; 5491 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5492 size += dof; 5493 } 5494 for (p = 0; p < numPoints; ++p) { 5495 const PetscInt cp = cone[p]; 5496 PetscInt o = coneO[p]; 5497 PetscInt dof, off, d; 5498 const PetscScalar *varr; 5499 5500 if ((cp < pStart) || (cp >= pEnd)) continue; 5501 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5502 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5503 varr = &vArray[off]; 5504 if (o >= 0) { 5505 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5506 } else { 5507 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5508 } 5509 size += dof; 5510 } 5511 PetscCall(VecRestoreArrayRead(v, &vArray)); 5512 if (!*values) { 5513 if (csize) *csize = size; 5514 *values = array; 5515 } else { 5516 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5517 *csize = size; 5518 } 5519 PetscFunctionReturn(0); 5520 } 5521 5522 /* Compress out points not in the section */ 5523 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) { 5524 const PetscInt np = *numPoints; 5525 PetscInt pStart, pEnd, p, q; 5526 5527 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5528 for (p = 0, q = 0; p < np; ++p) { 5529 const PetscInt r = points[p * 2]; 5530 if ((r >= pStart) && (r < pEnd)) { 5531 points[q * 2] = r; 5532 points[q * 2 + 1] = points[p * 2 + 1]; 5533 ++q; 5534 } 5535 } 5536 *numPoints = q; 5537 return 0; 5538 } 5539 5540 /* Compressed closure does not apply closure permutation */ 5541 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5542 const PetscInt *cla = NULL; 5543 PetscInt np, *pts = NULL; 5544 5545 PetscFunctionBeginHot; 5546 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5547 if (*clPoints) { 5548 PetscInt dof, off; 5549 5550 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5551 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5552 PetscCall(ISGetIndices(*clPoints, &cla)); 5553 np = dof / 2; 5554 pts = (PetscInt *)&cla[off]; 5555 } else { 5556 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5557 PetscCall(CompressPoints_Private(section, &np, pts)); 5558 } 5559 *numPoints = np; 5560 *points = pts; 5561 *clp = cla; 5562 PetscFunctionReturn(0); 5563 } 5564 5565 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5566 PetscFunctionBeginHot; 5567 if (!*clPoints) { 5568 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5569 } else { 5570 PetscCall(ISRestoreIndices(*clPoints, clp)); 5571 } 5572 *numPoints = 0; 5573 *points = NULL; 5574 *clSec = NULL; 5575 *clPoints = NULL; 5576 *clp = NULL; 5577 PetscFunctionReturn(0); 5578 } 5579 5580 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) { 5581 PetscInt offset = 0, p; 5582 const PetscInt **perms = NULL; 5583 const PetscScalar **flips = NULL; 5584 5585 PetscFunctionBeginHot; 5586 *size = 0; 5587 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5588 for (p = 0; p < numPoints; p++) { 5589 const PetscInt point = points[2 * p]; 5590 const PetscInt *perm = perms ? perms[p] : NULL; 5591 const PetscScalar *flip = flips ? flips[p] : NULL; 5592 PetscInt dof, off, d; 5593 const PetscScalar *varr; 5594 5595 PetscCall(PetscSectionGetDof(section, point, &dof)); 5596 PetscCall(PetscSectionGetOffset(section, point, &off)); 5597 varr = &vArray[off]; 5598 if (clperm) { 5599 if (perm) { 5600 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5601 } else { 5602 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5603 } 5604 if (flip) { 5605 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5606 } 5607 } else { 5608 if (perm) { 5609 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5610 } else { 5611 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5612 } 5613 if (flip) { 5614 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5615 } 5616 } 5617 offset += dof; 5618 } 5619 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5620 *size = offset; 5621 PetscFunctionReturn(0); 5622 } 5623 5624 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[]) { 5625 PetscInt offset = 0, f; 5626 5627 PetscFunctionBeginHot; 5628 *size = 0; 5629 for (f = 0; f < numFields; ++f) { 5630 PetscInt p; 5631 const PetscInt **perms = NULL; 5632 const PetscScalar **flips = NULL; 5633 5634 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5635 for (p = 0; p < numPoints; p++) { 5636 const PetscInt point = points[2 * p]; 5637 PetscInt fdof, foff, b; 5638 const PetscScalar *varr; 5639 const PetscInt *perm = perms ? perms[p] : NULL; 5640 const PetscScalar *flip = flips ? flips[p] : NULL; 5641 5642 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5643 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5644 varr = &vArray[foff]; 5645 if (clperm) { 5646 if (perm) { 5647 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5648 } else { 5649 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5650 } 5651 if (flip) { 5652 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5653 } 5654 } else { 5655 if (perm) { 5656 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5657 } else { 5658 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5659 } 5660 if (flip) { 5661 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5662 } 5663 } 5664 offset += fdof; 5665 } 5666 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5667 } 5668 *size = offset; 5669 PetscFunctionReturn(0); 5670 } 5671 5672 /*@C 5673 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5674 5675 Not collective 5676 5677 Input Parameters: 5678 + dm - The DM 5679 . section - The section describing the layout in v, or NULL to use the default section 5680 . v - The local vector 5681 - point - The point in the DM 5682 5683 Input/Output Parameters: 5684 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5685 - values - An array to use for the values, or NULL to have it allocated automatically; 5686 if the user provided NULL, it is a borrowed array and should not be freed 5687 5688 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5689 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5690 $ assembly function, and a user may already have allocated storage for this operation. 5691 $ 5692 $ A typical use could be 5693 $ 5694 $ values = NULL; 5695 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5696 $ for (cl = 0; cl < clSize; ++cl) { 5697 $ <Compute on closure> 5698 $ } 5699 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5700 $ 5701 $ or 5702 $ 5703 $ PetscMalloc1(clMaxSize, &values); 5704 $ for (p = pStart; p < pEnd; ++p) { 5705 $ clSize = clMaxSize; 5706 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5707 $ for (cl = 0; cl < clSize; ++cl) { 5708 $ <Compute on closure> 5709 $ } 5710 $ } 5711 $ PetscFree(values); 5712 5713 Fortran Notes: 5714 Since it returns an array, this routine is only available in Fortran 90, and you must 5715 include petsc.h90 in your code. 5716 5717 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5718 5719 Level: intermediate 5720 5721 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5722 @*/ 5723 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5724 PetscSection clSection; 5725 IS clPoints; 5726 PetscInt *points = NULL; 5727 const PetscInt *clp, *perm; 5728 PetscInt depth, numFields, numPoints, asize; 5729 5730 PetscFunctionBeginHot; 5731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5732 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5733 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5734 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5735 PetscCall(DMPlexGetDepth(dm, &depth)); 5736 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5737 if (depth == 1 && numFields < 2) { 5738 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5739 PetscFunctionReturn(0); 5740 } 5741 /* Get points */ 5742 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5743 /* Get sizes */ 5744 asize = 0; 5745 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5746 PetscInt dof; 5747 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5748 asize += dof; 5749 } 5750 if (values) { 5751 const PetscScalar *vArray; 5752 PetscInt size; 5753 5754 if (*values) { 5755 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); 5756 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5757 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5758 PetscCall(VecGetArrayRead(v, &vArray)); 5759 /* Get values */ 5760 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5761 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5762 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5763 /* Cleanup array */ 5764 PetscCall(VecRestoreArrayRead(v, &vArray)); 5765 } 5766 if (csize) *csize = asize; 5767 /* Cleanup points */ 5768 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5769 PetscFunctionReturn(0); 5770 } 5771 5772 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) { 5773 DMLabel depthLabel; 5774 PetscSection clSection; 5775 IS clPoints; 5776 PetscScalar *array; 5777 const PetscScalar *vArray; 5778 PetscInt *points = NULL; 5779 const PetscInt *clp, *perm = NULL; 5780 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5781 5782 PetscFunctionBeginHot; 5783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5784 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5785 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5786 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5787 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5788 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5789 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5790 if (mdepth == 1 && numFields < 2) { 5791 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5792 PetscFunctionReturn(0); 5793 } 5794 /* Get points */ 5795 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5796 for (clsize = 0, p = 0; p < Np; p++) { 5797 PetscInt dof; 5798 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 5799 clsize += dof; 5800 } 5801 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 5802 /* Filter points */ 5803 for (p = 0; p < numPoints * 2; p += 2) { 5804 PetscInt dep; 5805 5806 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5807 if (dep != depth) continue; 5808 points[Np * 2 + 0] = points[p]; 5809 points[Np * 2 + 1] = points[p + 1]; 5810 ++Np; 5811 } 5812 /* Get array */ 5813 if (!values || !*values) { 5814 PetscInt asize = 0, dof; 5815 5816 for (p = 0; p < Np * 2; p += 2) { 5817 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5818 asize += dof; 5819 } 5820 if (!values) { 5821 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5822 if (csize) *csize = asize; 5823 PetscFunctionReturn(0); 5824 } 5825 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5826 } else { 5827 array = *values; 5828 } 5829 PetscCall(VecGetArrayRead(v, &vArray)); 5830 /* Get values */ 5831 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5832 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5833 /* Cleanup points */ 5834 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5835 /* Cleanup array */ 5836 PetscCall(VecRestoreArrayRead(v, &vArray)); 5837 if (!*values) { 5838 if (csize) *csize = size; 5839 *values = array; 5840 } else { 5841 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5842 *csize = size; 5843 } 5844 PetscFunctionReturn(0); 5845 } 5846 5847 /*@C 5848 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5849 5850 Not collective 5851 5852 Input Parameters: 5853 + dm - The DM 5854 . section - The section describing the layout in v, or NULL to use the default section 5855 . v - The local vector 5856 . point - The point in the DM 5857 . csize - The number of values in the closure, or NULL 5858 - values - The array of values, which is a borrowed array and should not be freed 5859 5860 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5861 5862 Fortran Notes: 5863 Since it returns an array, this routine is only available in Fortran 90, and you must 5864 include petsc.h90 in your code. 5865 5866 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5867 5868 Level: intermediate 5869 5870 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5871 @*/ 5872 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5873 PetscInt size = 0; 5874 5875 PetscFunctionBegin; 5876 /* Should work without recalculating size */ 5877 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 5878 *values = NULL; 5879 PetscFunctionReturn(0); 5880 } 5881 5882 static inline void add(PetscScalar *x, PetscScalar y) { 5883 *x += y; 5884 } 5885 static inline void insert(PetscScalar *x, PetscScalar y) { 5886 *x = y; 5887 } 5888 5889 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[]) { 5890 PetscInt cdof; /* The number of constraints on this point */ 5891 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5892 PetscScalar *a; 5893 PetscInt off, cind = 0, k; 5894 5895 PetscFunctionBegin; 5896 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5897 PetscCall(PetscSectionGetOffset(section, point, &off)); 5898 a = &array[off]; 5899 if (!cdof || setBC) { 5900 if (clperm) { 5901 if (perm) { 5902 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5903 } else { 5904 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5905 } 5906 } else { 5907 if (perm) { 5908 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5909 } else { 5910 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5911 } 5912 } 5913 } else { 5914 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5915 if (clperm) { 5916 if (perm) { 5917 for (k = 0; k < dof; ++k) { 5918 if ((cind < cdof) && (k == cdofs[cind])) { 5919 ++cind; 5920 continue; 5921 } 5922 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5923 } 5924 } else { 5925 for (k = 0; k < dof; ++k) { 5926 if ((cind < cdof) && (k == cdofs[cind])) { 5927 ++cind; 5928 continue; 5929 } 5930 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5931 } 5932 } 5933 } else { 5934 if (perm) { 5935 for (k = 0; k < dof; ++k) { 5936 if ((cind < cdof) && (k == cdofs[cind])) { 5937 ++cind; 5938 continue; 5939 } 5940 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5941 } 5942 } else { 5943 for (k = 0; k < dof; ++k) { 5944 if ((cind < cdof) && (k == cdofs[cind])) { 5945 ++cind; 5946 continue; 5947 } 5948 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5949 } 5950 } 5951 } 5952 } 5953 PetscFunctionReturn(0); 5954 } 5955 5956 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[]) { 5957 PetscInt cdof; /* The number of constraints on this point */ 5958 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5959 PetscScalar *a; 5960 PetscInt off, cind = 0, k; 5961 5962 PetscFunctionBegin; 5963 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5964 PetscCall(PetscSectionGetOffset(section, point, &off)); 5965 a = &array[off]; 5966 if (cdof) { 5967 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5968 if (clperm) { 5969 if (perm) { 5970 for (k = 0; k < dof; ++k) { 5971 if ((cind < cdof) && (k == cdofs[cind])) { 5972 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5973 cind++; 5974 } 5975 } 5976 } else { 5977 for (k = 0; k < dof; ++k) { 5978 if ((cind < cdof) && (k == cdofs[cind])) { 5979 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5980 cind++; 5981 } 5982 } 5983 } 5984 } else { 5985 if (perm) { 5986 for (k = 0; k < dof; ++k) { 5987 if ((cind < cdof) && (k == cdofs[cind])) { 5988 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5989 cind++; 5990 } 5991 } 5992 } else { 5993 for (k = 0; k < dof; ++k) { 5994 if ((cind < cdof) && (k == cdofs[cind])) { 5995 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5996 cind++; 5997 } 5998 } 5999 } 6000 } 6001 } 6002 PetscFunctionReturn(0); 6003 } 6004 6005 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[]) { 6006 PetscScalar *a; 6007 PetscInt fdof, foff, fcdof, foffset = *offset; 6008 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6009 PetscInt cind = 0, b; 6010 6011 PetscFunctionBegin; 6012 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6013 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6014 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6015 a = &array[foff]; 6016 if (!fcdof || setBC) { 6017 if (clperm) { 6018 if (perm) { 6019 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6020 } else { 6021 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6022 } 6023 } else { 6024 if (perm) { 6025 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6026 } else { 6027 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6028 } 6029 } 6030 } else { 6031 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6032 if (clperm) { 6033 if (perm) { 6034 for (b = 0; b < fdof; b++) { 6035 if ((cind < fcdof) && (b == fcdofs[cind])) { 6036 ++cind; 6037 continue; 6038 } 6039 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6040 } 6041 } else { 6042 for (b = 0; b < fdof; b++) { 6043 if ((cind < fcdof) && (b == fcdofs[cind])) { 6044 ++cind; 6045 continue; 6046 } 6047 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6048 } 6049 } 6050 } else { 6051 if (perm) { 6052 for (b = 0; b < fdof; b++) { 6053 if ((cind < fcdof) && (b == fcdofs[cind])) { 6054 ++cind; 6055 continue; 6056 } 6057 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6058 } 6059 } else { 6060 for (b = 0; b < fdof; b++) { 6061 if ((cind < fcdof) && (b == fcdofs[cind])) { 6062 ++cind; 6063 continue; 6064 } 6065 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6066 } 6067 } 6068 } 6069 } 6070 *offset += fdof; 6071 PetscFunctionReturn(0); 6072 } 6073 6074 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[]) { 6075 PetscScalar *a; 6076 PetscInt fdof, foff, fcdof, foffset = *offset; 6077 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6078 PetscInt Nc, cind = 0, ncind = 0, b; 6079 PetscBool ncSet, fcSet; 6080 6081 PetscFunctionBegin; 6082 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6083 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6084 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6085 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6086 a = &array[foff]; 6087 if (fcdof) { 6088 /* We just override fcdof and fcdofs with Ncc and comps */ 6089 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6090 if (clperm) { 6091 if (perm) { 6092 if (comps) { 6093 for (b = 0; b < fdof; b++) { 6094 ncSet = fcSet = PETSC_FALSE; 6095 if (b % Nc == comps[ncind]) { 6096 ncind = (ncind + 1) % Ncc; 6097 ncSet = PETSC_TRUE; 6098 } 6099 if ((cind < fcdof) && (b == fcdofs[cind])) { 6100 ++cind; 6101 fcSet = PETSC_TRUE; 6102 } 6103 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6104 } 6105 } else { 6106 for (b = 0; b < fdof; b++) { 6107 if ((cind < fcdof) && (b == fcdofs[cind])) { 6108 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6109 ++cind; 6110 } 6111 } 6112 } 6113 } else { 6114 if (comps) { 6115 for (b = 0; b < fdof; b++) { 6116 ncSet = fcSet = PETSC_FALSE; 6117 if (b % Nc == comps[ncind]) { 6118 ncind = (ncind + 1) % Ncc; 6119 ncSet = PETSC_TRUE; 6120 } 6121 if ((cind < fcdof) && (b == fcdofs[cind])) { 6122 ++cind; 6123 fcSet = PETSC_TRUE; 6124 } 6125 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6126 } 6127 } else { 6128 for (b = 0; b < fdof; b++) { 6129 if ((cind < fcdof) && (b == fcdofs[cind])) { 6130 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6131 ++cind; 6132 } 6133 } 6134 } 6135 } 6136 } else { 6137 if (perm) { 6138 if (comps) { 6139 for (b = 0; b < fdof; b++) { 6140 ncSet = fcSet = PETSC_FALSE; 6141 if (b % Nc == comps[ncind]) { 6142 ncind = (ncind + 1) % Ncc; 6143 ncSet = PETSC_TRUE; 6144 } 6145 if ((cind < fcdof) && (b == fcdofs[cind])) { 6146 ++cind; 6147 fcSet = PETSC_TRUE; 6148 } 6149 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6150 } 6151 } else { 6152 for (b = 0; b < fdof; b++) { 6153 if ((cind < fcdof) && (b == fcdofs[cind])) { 6154 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6155 ++cind; 6156 } 6157 } 6158 } 6159 } else { 6160 if (comps) { 6161 for (b = 0; b < fdof; b++) { 6162 ncSet = fcSet = PETSC_FALSE; 6163 if (b % Nc == comps[ncind]) { 6164 ncind = (ncind + 1) % Ncc; 6165 ncSet = PETSC_TRUE; 6166 } 6167 if ((cind < fcdof) && (b == fcdofs[cind])) { 6168 ++cind; 6169 fcSet = PETSC_TRUE; 6170 } 6171 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6172 } 6173 } else { 6174 for (b = 0; b < fdof; b++) { 6175 if ((cind < fcdof) && (b == fcdofs[cind])) { 6176 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6177 ++cind; 6178 } 6179 } 6180 } 6181 } 6182 } 6183 } 6184 *offset += fdof; 6185 PetscFunctionReturn(0); 6186 } 6187 6188 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6189 PetscScalar *array; 6190 const PetscInt *cone, *coneO; 6191 PetscInt pStart, pEnd, p, numPoints, off, dof; 6192 6193 PetscFunctionBeginHot; 6194 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6195 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6196 PetscCall(DMPlexGetCone(dm, point, &cone)); 6197 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6198 PetscCall(VecGetArray(v, &array)); 6199 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6200 const PetscInt cp = !p ? point : cone[p - 1]; 6201 const PetscInt o = !p ? 0 : coneO[p - 1]; 6202 6203 if ((cp < pStart) || (cp >= pEnd)) { 6204 dof = 0; 6205 continue; 6206 } 6207 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6208 /* ADD_VALUES */ 6209 { 6210 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6211 PetscScalar *a; 6212 PetscInt cdof, coff, cind = 0, k; 6213 6214 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6215 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6216 a = &array[coff]; 6217 if (!cdof) { 6218 if (o >= 0) { 6219 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6220 } else { 6221 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6222 } 6223 } else { 6224 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6225 if (o >= 0) { 6226 for (k = 0; k < dof; ++k) { 6227 if ((cind < cdof) && (k == cdofs[cind])) { 6228 ++cind; 6229 continue; 6230 } 6231 a[k] += values[off + k]; 6232 } 6233 } else { 6234 for (k = 0; k < dof; ++k) { 6235 if ((cind < cdof) && (k == cdofs[cind])) { 6236 ++cind; 6237 continue; 6238 } 6239 a[k] += values[off + dof - k - 1]; 6240 } 6241 } 6242 } 6243 } 6244 } 6245 PetscCall(VecRestoreArray(v, &array)); 6246 PetscFunctionReturn(0); 6247 } 6248 6249 /*@C 6250 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6251 6252 Not collective 6253 6254 Input Parameters: 6255 + dm - The DM 6256 . section - The section describing the layout in v, or NULL to use the default section 6257 . v - The local vector 6258 . point - The point in the DM 6259 . values - The array of values 6260 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6261 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6262 6263 Fortran Notes: 6264 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6265 6266 Level: intermediate 6267 6268 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6269 @*/ 6270 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6271 PetscSection clSection; 6272 IS clPoints; 6273 PetscScalar *array; 6274 PetscInt *points = NULL; 6275 const PetscInt *clp, *clperm = NULL; 6276 PetscInt depth, numFields, numPoints, p, clsize; 6277 6278 PetscFunctionBeginHot; 6279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6280 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6281 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6282 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6283 PetscCall(DMPlexGetDepth(dm, &depth)); 6284 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6285 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6286 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6287 PetscFunctionReturn(0); 6288 } 6289 /* Get points */ 6290 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6291 for (clsize = 0, p = 0; p < numPoints; p++) { 6292 PetscInt dof; 6293 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6294 clsize += dof; 6295 } 6296 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6297 /* Get array */ 6298 PetscCall(VecGetArray(v, &array)); 6299 /* Get values */ 6300 if (numFields > 0) { 6301 PetscInt offset = 0, f; 6302 for (f = 0; f < numFields; ++f) { 6303 const PetscInt **perms = NULL; 6304 const PetscScalar **flips = NULL; 6305 6306 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6307 switch (mode) { 6308 case INSERT_VALUES: 6309 for (p = 0; p < numPoints; p++) { 6310 const PetscInt point = points[2 * p]; 6311 const PetscInt *perm = perms ? perms[p] : NULL; 6312 const PetscScalar *flip = flips ? flips[p] : NULL; 6313 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6314 } 6315 break; 6316 case INSERT_ALL_VALUES: 6317 for (p = 0; p < numPoints; p++) { 6318 const PetscInt point = points[2 * p]; 6319 const PetscInt *perm = perms ? perms[p] : NULL; 6320 const PetscScalar *flip = flips ? flips[p] : NULL; 6321 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6322 } 6323 break; 6324 case INSERT_BC_VALUES: 6325 for (p = 0; p < numPoints; p++) { 6326 const PetscInt point = points[2 * p]; 6327 const PetscInt *perm = perms ? perms[p] : NULL; 6328 const PetscScalar *flip = flips ? flips[p] : NULL; 6329 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6330 } 6331 break; 6332 case ADD_VALUES: 6333 for (p = 0; p < numPoints; p++) { 6334 const PetscInt point = points[2 * p]; 6335 const PetscInt *perm = perms ? perms[p] : NULL; 6336 const PetscScalar *flip = flips ? flips[p] : NULL; 6337 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6338 } 6339 break; 6340 case ADD_ALL_VALUES: 6341 for (p = 0; p < numPoints; p++) { 6342 const PetscInt point = points[2 * p]; 6343 const PetscInt *perm = perms ? perms[p] : NULL; 6344 const PetscScalar *flip = flips ? flips[p] : NULL; 6345 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6346 } 6347 break; 6348 case ADD_BC_VALUES: 6349 for (p = 0; p < numPoints; p++) { 6350 const PetscInt point = points[2 * p]; 6351 const PetscInt *perm = perms ? perms[p] : NULL; 6352 const PetscScalar *flip = flips ? flips[p] : NULL; 6353 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6354 } 6355 break; 6356 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6357 } 6358 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6359 } 6360 } else { 6361 PetscInt dof, off; 6362 const PetscInt **perms = NULL; 6363 const PetscScalar **flips = NULL; 6364 6365 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6366 switch (mode) { 6367 case INSERT_VALUES: 6368 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6369 const PetscInt point = points[2 * p]; 6370 const PetscInt *perm = perms ? perms[p] : NULL; 6371 const PetscScalar *flip = flips ? flips[p] : NULL; 6372 PetscCall(PetscSectionGetDof(section, point, &dof)); 6373 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6374 } 6375 break; 6376 case INSERT_ALL_VALUES: 6377 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6378 const PetscInt point = points[2 * p]; 6379 const PetscInt *perm = perms ? perms[p] : NULL; 6380 const PetscScalar *flip = flips ? flips[p] : NULL; 6381 PetscCall(PetscSectionGetDof(section, point, &dof)); 6382 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6383 } 6384 break; 6385 case INSERT_BC_VALUES: 6386 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6387 const PetscInt point = points[2 * p]; 6388 const PetscInt *perm = perms ? perms[p] : NULL; 6389 const PetscScalar *flip = flips ? flips[p] : NULL; 6390 PetscCall(PetscSectionGetDof(section, point, &dof)); 6391 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6392 } 6393 break; 6394 case ADD_VALUES: 6395 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6396 const PetscInt point = points[2 * p]; 6397 const PetscInt *perm = perms ? perms[p] : NULL; 6398 const PetscScalar *flip = flips ? flips[p] : NULL; 6399 PetscCall(PetscSectionGetDof(section, point, &dof)); 6400 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6401 } 6402 break; 6403 case ADD_ALL_VALUES: 6404 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6405 const PetscInt point = points[2 * p]; 6406 const PetscInt *perm = perms ? perms[p] : NULL; 6407 const PetscScalar *flip = flips ? flips[p] : NULL; 6408 PetscCall(PetscSectionGetDof(section, point, &dof)); 6409 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6410 } 6411 break; 6412 case ADD_BC_VALUES: 6413 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6414 const PetscInt point = points[2 * p]; 6415 const PetscInt *perm = perms ? perms[p] : NULL; 6416 const PetscScalar *flip = flips ? flips[p] : NULL; 6417 PetscCall(PetscSectionGetDof(section, point, &dof)); 6418 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6419 } 6420 break; 6421 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6422 } 6423 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6424 } 6425 /* Cleanup points */ 6426 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6427 /* Cleanup array */ 6428 PetscCall(VecRestoreArray(v, &array)); 6429 PetscFunctionReturn(0); 6430 } 6431 6432 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6433 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) { 6434 PetscFunctionBegin; 6435 *contains = PETSC_TRUE; 6436 if (label) { 6437 PetscInt fdof; 6438 6439 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6440 if (!*contains) { 6441 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6442 *offset += fdof; 6443 PetscFunctionReturn(0); 6444 } 6445 } 6446 PetscFunctionReturn(0); 6447 } 6448 6449 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6450 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) { 6451 PetscSection clSection; 6452 IS clPoints; 6453 PetscScalar *array; 6454 PetscInt *points = NULL; 6455 const PetscInt *clp; 6456 PetscInt numFields, numPoints, p; 6457 PetscInt offset = 0, f; 6458 6459 PetscFunctionBeginHot; 6460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6461 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6462 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6463 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6464 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6465 /* Get points */ 6466 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6467 /* Get array */ 6468 PetscCall(VecGetArray(v, &array)); 6469 /* Get values */ 6470 for (f = 0; f < numFields; ++f) { 6471 const PetscInt **perms = NULL; 6472 const PetscScalar **flips = NULL; 6473 PetscBool contains; 6474 6475 if (!fieldActive[f]) { 6476 for (p = 0; p < numPoints * 2; p += 2) { 6477 PetscInt fdof; 6478 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6479 offset += fdof; 6480 } 6481 continue; 6482 } 6483 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6484 switch (mode) { 6485 case INSERT_VALUES: 6486 for (p = 0; p < numPoints; p++) { 6487 const PetscInt point = points[2 * p]; 6488 const PetscInt *perm = perms ? perms[p] : NULL; 6489 const PetscScalar *flip = flips ? flips[p] : NULL; 6490 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6491 if (!contains) continue; 6492 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6493 } 6494 break; 6495 case INSERT_ALL_VALUES: 6496 for (p = 0; p < numPoints; p++) { 6497 const PetscInt point = points[2 * p]; 6498 const PetscInt *perm = perms ? perms[p] : NULL; 6499 const PetscScalar *flip = flips ? flips[p] : NULL; 6500 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6501 if (!contains) continue; 6502 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6503 } 6504 break; 6505 case INSERT_BC_VALUES: 6506 for (p = 0; p < numPoints; p++) { 6507 const PetscInt point = points[2 * p]; 6508 const PetscInt *perm = perms ? perms[p] : NULL; 6509 const PetscScalar *flip = flips ? flips[p] : NULL; 6510 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6511 if (!contains) continue; 6512 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, 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 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6521 if (!contains) continue; 6522 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6523 } 6524 break; 6525 case ADD_ALL_VALUES: 6526 for (p = 0; p < numPoints; p++) { 6527 const PetscInt point = points[2 * p]; 6528 const PetscInt *perm = perms ? perms[p] : NULL; 6529 const PetscScalar *flip = flips ? flips[p] : NULL; 6530 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6531 if (!contains) continue; 6532 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6533 } 6534 break; 6535 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6536 } 6537 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6538 } 6539 /* Cleanup points */ 6540 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6541 /* Cleanup array */ 6542 PetscCall(VecRestoreArray(v, &array)); 6543 PetscFunctionReturn(0); 6544 } 6545 6546 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) { 6547 PetscMPIInt rank; 6548 PetscInt i, j; 6549 6550 PetscFunctionBegin; 6551 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6552 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6553 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6554 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6555 numCIndices = numCIndices ? numCIndices : numRIndices; 6556 if (!values) PetscFunctionReturn(0); 6557 for (i = 0; i < numRIndices; i++) { 6558 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6559 for (j = 0; j < numCIndices; j++) { 6560 #if defined(PETSC_USE_COMPLEX) 6561 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6562 #else 6563 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6564 #endif 6565 } 6566 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6567 } 6568 PetscFunctionReturn(0); 6569 } 6570 6571 /* 6572 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6573 6574 Input Parameters: 6575 + section - The section for this data layout 6576 . islocal - Is the section (and thus indices being requested) local or global? 6577 . point - The point contributing dofs with these indices 6578 . off - The global offset of this point 6579 . loff - The local offset of each field 6580 . setBC - The flag determining whether to include indices of boundary values 6581 . perm - A permutation of the dofs on this point, or NULL 6582 - indperm - A permutation of the entire indices array, or NULL 6583 6584 Output Parameter: 6585 . indices - Indices for dofs on this point 6586 6587 Level: developer 6588 6589 Note: The indices could be local or global, depending on the value of 'off'. 6590 */ 6591 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) { 6592 PetscInt dof; /* The number of unknowns on this point */ 6593 PetscInt cdof; /* The number of constraints on this point */ 6594 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6595 PetscInt cind = 0, k; 6596 6597 PetscFunctionBegin; 6598 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6599 PetscCall(PetscSectionGetDof(section, point, &dof)); 6600 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6601 if (!cdof || setBC) { 6602 for (k = 0; k < dof; ++k) { 6603 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6604 const PetscInt ind = indperm ? indperm[preind] : preind; 6605 6606 indices[ind] = off + k; 6607 } 6608 } else { 6609 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6610 for (k = 0; k < dof; ++k) { 6611 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6612 const PetscInt ind = indperm ? indperm[preind] : preind; 6613 6614 if ((cind < cdof) && (k == cdofs[cind])) { 6615 /* Insert check for returning constrained indices */ 6616 indices[ind] = -(off + k + 1); 6617 ++cind; 6618 } else { 6619 indices[ind] = off + k - (islocal ? 0 : cind); 6620 } 6621 } 6622 } 6623 *loff += dof; 6624 PetscFunctionReturn(0); 6625 } 6626 6627 /* 6628 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6629 6630 Input Parameters: 6631 + section - a section (global or local) 6632 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6633 . point - point within section 6634 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6635 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6636 . setBC - identify constrained (boundary condition) points via involution. 6637 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6638 . permsoff - offset 6639 - indperm - index permutation 6640 6641 Output Parameter: 6642 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6643 . indices - array to hold indices (as defined by section) of each dof associated with point 6644 6645 Notes: 6646 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6647 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6648 in the local vector. 6649 6650 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6651 significant). It is invalid to call with a global section and setBC=true. 6652 6653 Developer Note: 6654 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6655 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6656 offset could be obtained from the section instead of passing it explicitly as we do now. 6657 6658 Example: 6659 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6660 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6661 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6662 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. 6663 6664 Level: developer 6665 */ 6666 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[]) { 6667 PetscInt numFields, foff, f; 6668 6669 PetscFunctionBegin; 6670 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6671 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6672 for (f = 0, foff = 0; f < numFields; ++f) { 6673 PetscInt fdof, cfdof; 6674 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6675 PetscInt cind = 0, b; 6676 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6677 6678 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6679 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6680 if (!cfdof || setBC) { 6681 for (b = 0; b < fdof; ++b) { 6682 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6683 const PetscInt ind = indperm ? indperm[preind] : preind; 6684 6685 indices[ind] = off + foff + b; 6686 } 6687 } else { 6688 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6689 for (b = 0; b < fdof; ++b) { 6690 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6691 const PetscInt ind = indperm ? indperm[preind] : preind; 6692 6693 if ((cind < cfdof) && (b == fcdofs[cind])) { 6694 indices[ind] = -(off + foff + b + 1); 6695 ++cind; 6696 } else { 6697 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6698 } 6699 } 6700 } 6701 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6702 foffs[f] += fdof; 6703 } 6704 PetscFunctionReturn(0); 6705 } 6706 6707 /* 6708 This version believes the globalSection offsets for each field, rather than just the point offset 6709 6710 . foffs - The offset into 'indices' for each field, since it is segregated by field 6711 6712 Notes: 6713 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6714 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6715 */ 6716 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) { 6717 PetscInt numFields, foff, f; 6718 6719 PetscFunctionBegin; 6720 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6721 for (f = 0; f < numFields; ++f) { 6722 PetscInt fdof, cfdof; 6723 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6724 PetscInt cind = 0, b; 6725 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6726 6727 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6728 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6729 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6730 if (!cfdof) { 6731 for (b = 0; b < fdof; ++b) { 6732 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6733 const PetscInt ind = indperm ? indperm[preind] : preind; 6734 6735 indices[ind] = foff + b; 6736 } 6737 } else { 6738 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6739 for (b = 0; b < fdof; ++b) { 6740 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6741 const PetscInt ind = indperm ? indperm[preind] : preind; 6742 6743 if ((cind < cfdof) && (b == fcdofs[cind])) { 6744 indices[ind] = -(foff + b + 1); 6745 ++cind; 6746 } else { 6747 indices[ind] = foff + b - cind; 6748 } 6749 } 6750 } 6751 foffs[f] += fdof; 6752 } 6753 PetscFunctionReturn(0); 6754 } 6755 6756 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) { 6757 Mat cMat; 6758 PetscSection aSec, cSec; 6759 IS aIS; 6760 PetscInt aStart = -1, aEnd = -1; 6761 const PetscInt *anchors; 6762 PetscInt numFields, f, p, q, newP = 0; 6763 PetscInt newNumPoints = 0, newNumIndices = 0; 6764 PetscInt *newPoints, *indices, *newIndices; 6765 PetscInt maxAnchor, maxDof; 6766 PetscInt newOffsets[32]; 6767 PetscInt *pointMatOffsets[32]; 6768 PetscInt *newPointOffsets[32]; 6769 PetscScalar *pointMat[32]; 6770 PetscScalar *newValues = NULL, *tmpValues; 6771 PetscBool anyConstrained = PETSC_FALSE; 6772 6773 PetscFunctionBegin; 6774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6775 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6776 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6777 6778 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6779 /* if there are point-to-point constraints */ 6780 if (aSec) { 6781 PetscCall(PetscArrayzero(newOffsets, 32)); 6782 PetscCall(ISGetIndices(aIS, &anchors)); 6783 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6784 /* figure out how many points are going to be in the new element matrix 6785 * (we allow double counting, because it's all just going to be summed 6786 * into the global matrix anyway) */ 6787 for (p = 0; p < 2 * numPoints; p += 2) { 6788 PetscInt b = points[p]; 6789 PetscInt bDof = 0, bSecDof; 6790 6791 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6792 if (!bSecDof) continue; 6793 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6794 if (bDof) { 6795 /* this point is constrained */ 6796 /* it is going to be replaced by its anchors */ 6797 PetscInt bOff, q; 6798 6799 anyConstrained = PETSC_TRUE; 6800 newNumPoints += bDof; 6801 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6802 for (q = 0; q < bDof; q++) { 6803 PetscInt a = anchors[bOff + q]; 6804 PetscInt aDof; 6805 6806 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6807 newNumIndices += aDof; 6808 for (f = 0; f < numFields; ++f) { 6809 PetscInt fDof; 6810 6811 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6812 newOffsets[f + 1] += fDof; 6813 } 6814 } 6815 } else { 6816 /* this point is not constrained */ 6817 newNumPoints++; 6818 newNumIndices += bSecDof; 6819 for (f = 0; f < numFields; ++f) { 6820 PetscInt fDof; 6821 6822 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6823 newOffsets[f + 1] += fDof; 6824 } 6825 } 6826 } 6827 } 6828 if (!anyConstrained) { 6829 if (outNumPoints) *outNumPoints = 0; 6830 if (outNumIndices) *outNumIndices = 0; 6831 if (outPoints) *outPoints = NULL; 6832 if (outValues) *outValues = NULL; 6833 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6834 PetscFunctionReturn(0); 6835 } 6836 6837 if (outNumPoints) *outNumPoints = newNumPoints; 6838 if (outNumIndices) *outNumIndices = newNumIndices; 6839 6840 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 6841 6842 if (!outPoints && !outValues) { 6843 if (offsets) { 6844 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 6845 } 6846 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6847 PetscFunctionReturn(0); 6848 } 6849 6850 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6851 6852 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6853 6854 /* workspaces */ 6855 if (numFields) { 6856 for (f = 0; f < numFields; f++) { 6857 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 6858 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 6859 } 6860 } else { 6861 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 6862 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 6863 } 6864 6865 /* get workspaces for the point-to-point matrices */ 6866 if (numFields) { 6867 PetscInt totalOffset, totalMatOffset; 6868 6869 for (p = 0; p < numPoints; p++) { 6870 PetscInt b = points[2 * p]; 6871 PetscInt bDof = 0, bSecDof; 6872 6873 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6874 if (!bSecDof) { 6875 for (f = 0; f < numFields; f++) { 6876 newPointOffsets[f][p + 1] = 0; 6877 pointMatOffsets[f][p + 1] = 0; 6878 } 6879 continue; 6880 } 6881 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6882 if (bDof) { 6883 for (f = 0; f < numFields; f++) { 6884 PetscInt fDof, q, bOff, allFDof = 0; 6885 6886 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6887 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6888 for (q = 0; q < bDof; q++) { 6889 PetscInt a = anchors[bOff + q]; 6890 PetscInt aFDof; 6891 6892 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6893 allFDof += aFDof; 6894 } 6895 newPointOffsets[f][p + 1] = allFDof; 6896 pointMatOffsets[f][p + 1] = fDof * allFDof; 6897 } 6898 } else { 6899 for (f = 0; f < numFields; f++) { 6900 PetscInt fDof; 6901 6902 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6903 newPointOffsets[f][p + 1] = fDof; 6904 pointMatOffsets[f][p + 1] = 0; 6905 } 6906 } 6907 } 6908 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6909 newPointOffsets[f][0] = totalOffset; 6910 pointMatOffsets[f][0] = totalMatOffset; 6911 for (p = 0; p < numPoints; p++) { 6912 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 6913 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 6914 } 6915 totalOffset = newPointOffsets[f][numPoints]; 6916 totalMatOffset = pointMatOffsets[f][numPoints]; 6917 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 6918 } 6919 } else { 6920 for (p = 0; p < numPoints; p++) { 6921 PetscInt b = points[2 * p]; 6922 PetscInt bDof = 0, bSecDof; 6923 6924 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6925 if (!bSecDof) { 6926 newPointOffsets[0][p + 1] = 0; 6927 pointMatOffsets[0][p + 1] = 0; 6928 continue; 6929 } 6930 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6931 if (bDof) { 6932 PetscInt bOff, q, allDof = 0; 6933 6934 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6935 for (q = 0; q < bDof; q++) { 6936 PetscInt a = anchors[bOff + q], aDof; 6937 6938 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6939 allDof += aDof; 6940 } 6941 newPointOffsets[0][p + 1] = allDof; 6942 pointMatOffsets[0][p + 1] = bSecDof * allDof; 6943 } else { 6944 newPointOffsets[0][p + 1] = bSecDof; 6945 pointMatOffsets[0][p + 1] = 0; 6946 } 6947 } 6948 newPointOffsets[0][0] = 0; 6949 pointMatOffsets[0][0] = 0; 6950 for (p = 0; p < numPoints; p++) { 6951 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 6952 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 6953 } 6954 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 6955 } 6956 6957 /* output arrays */ 6958 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 6959 6960 /* get the point-to-point matrices; construct newPoints */ 6961 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6962 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6963 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 6964 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 6965 if (numFields) { 6966 for (p = 0, newP = 0; p < numPoints; p++) { 6967 PetscInt b = points[2 * p]; 6968 PetscInt o = points[2 * p + 1]; 6969 PetscInt bDof = 0, bSecDof; 6970 6971 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6972 if (!bSecDof) continue; 6973 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6974 if (bDof) { 6975 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6976 6977 fStart[0] = 0; 6978 fEnd[0] = 0; 6979 for (f = 0; f < numFields; f++) { 6980 PetscInt fDof; 6981 6982 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6983 fStart[f + 1] = fStart[f] + fDof; 6984 fEnd[f + 1] = fStart[f + 1]; 6985 } 6986 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6987 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6988 6989 fAnchorStart[0] = 0; 6990 fAnchorEnd[0] = 0; 6991 for (f = 0; f < numFields; f++) { 6992 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6993 6994 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 6995 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 6996 } 6997 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6998 for (q = 0; q < bDof; q++) { 6999 PetscInt a = anchors[bOff + q], aOff; 7000 7001 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7002 newPoints[2 * (newP + q)] = a; 7003 newPoints[2 * (newP + q) + 1] = 0; 7004 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7005 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7006 } 7007 newP += bDof; 7008 7009 if (outValues) { 7010 /* get the point-to-point submatrix */ 7011 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])); 7012 } 7013 } else { 7014 newPoints[2 * newP] = b; 7015 newPoints[2 * newP + 1] = o; 7016 newP++; 7017 } 7018 } 7019 } else { 7020 for (p = 0; p < numPoints; p++) { 7021 PetscInt b = points[2 * p]; 7022 PetscInt o = points[2 * p + 1]; 7023 PetscInt bDof = 0, bSecDof; 7024 7025 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7026 if (!bSecDof) continue; 7027 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7028 if (bDof) { 7029 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7030 7031 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7032 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7033 7034 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7035 for (q = 0; q < bDof; q++) { 7036 PetscInt a = anchors[bOff + q], aOff; 7037 7038 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7039 7040 newPoints[2 * (newP + q)] = a; 7041 newPoints[2 * (newP + q) + 1] = 0; 7042 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7043 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7044 } 7045 newP += bDof; 7046 7047 /* get the point-to-point submatrix */ 7048 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7049 } else { 7050 newPoints[2 * newP] = b; 7051 newPoints[2 * newP + 1] = o; 7052 newP++; 7053 } 7054 } 7055 } 7056 7057 if (outValues) { 7058 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7059 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7060 /* multiply constraints on the right */ 7061 if (numFields) { 7062 for (f = 0; f < numFields; f++) { 7063 PetscInt oldOff = offsets[f]; 7064 7065 for (p = 0; p < numPoints; p++) { 7066 PetscInt cStart = newPointOffsets[f][p]; 7067 PetscInt b = points[2 * p]; 7068 PetscInt c, r, k; 7069 PetscInt dof; 7070 7071 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7072 if (!dof) continue; 7073 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7074 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7075 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7076 7077 for (r = 0; r < numIndices; r++) { 7078 for (c = 0; c < nCols; c++) { 7079 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7080 } 7081 } 7082 } else { 7083 /* copy this column as is */ 7084 for (r = 0; r < numIndices; r++) { 7085 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7086 } 7087 } 7088 oldOff += dof; 7089 } 7090 } 7091 } else { 7092 PetscInt oldOff = 0; 7093 for (p = 0; p < numPoints; p++) { 7094 PetscInt cStart = newPointOffsets[0][p]; 7095 PetscInt b = points[2 * p]; 7096 PetscInt c, r, k; 7097 PetscInt dof; 7098 7099 PetscCall(PetscSectionGetDof(section, b, &dof)); 7100 if (!dof) continue; 7101 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7102 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7103 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7104 7105 for (r = 0; r < numIndices; r++) { 7106 for (c = 0; c < nCols; c++) { 7107 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7108 } 7109 } 7110 } else { 7111 /* copy this column as is */ 7112 for (r = 0; r < numIndices; r++) { 7113 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7114 } 7115 } 7116 oldOff += dof; 7117 } 7118 } 7119 7120 if (multiplyLeft) { 7121 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7122 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7123 /* multiply constraints transpose on the left */ 7124 if (numFields) { 7125 for (f = 0; f < numFields; f++) { 7126 PetscInt oldOff = offsets[f]; 7127 7128 for (p = 0; p < numPoints; p++) { 7129 PetscInt rStart = newPointOffsets[f][p]; 7130 PetscInt b = points[2 * p]; 7131 PetscInt c, r, k; 7132 PetscInt dof; 7133 7134 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7135 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7136 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7137 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7138 7139 for (r = 0; r < nRows; r++) { 7140 for (c = 0; c < newNumIndices; c++) { 7141 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7142 } 7143 } 7144 } else { 7145 /* copy this row as is */ 7146 for (r = 0; r < dof; r++) { 7147 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7148 } 7149 } 7150 oldOff += dof; 7151 } 7152 } 7153 } else { 7154 PetscInt oldOff = 0; 7155 7156 for (p = 0; p < numPoints; p++) { 7157 PetscInt rStart = newPointOffsets[0][p]; 7158 PetscInt b = points[2 * p]; 7159 PetscInt c, r, k; 7160 PetscInt dof; 7161 7162 PetscCall(PetscSectionGetDof(section, b, &dof)); 7163 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7164 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7165 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7166 7167 for (r = 0; r < nRows; r++) { 7168 for (c = 0; c < newNumIndices; c++) { 7169 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7170 } 7171 } 7172 } else { 7173 /* copy this row as is */ 7174 for (r = 0; r < dof; r++) { 7175 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7176 } 7177 } 7178 oldOff += dof; 7179 } 7180 } 7181 7182 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7183 } else { 7184 newValues = tmpValues; 7185 } 7186 } 7187 7188 /* clean up */ 7189 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7190 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7191 7192 if (numFields) { 7193 for (f = 0; f < numFields; f++) { 7194 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7195 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7196 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7197 } 7198 } else { 7199 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7200 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7201 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7202 } 7203 PetscCall(ISRestoreIndices(aIS, &anchors)); 7204 7205 /* output */ 7206 if (outPoints) { 7207 *outPoints = newPoints; 7208 } else { 7209 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7210 } 7211 if (outValues) *outValues = newValues; 7212 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7213 PetscFunctionReturn(0); 7214 } 7215 7216 /*@C 7217 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7218 7219 Not collective 7220 7221 Input Parameters: 7222 + dm - The DM 7223 . section - The PetscSection describing the points (a local section) 7224 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7225 . point - The point defining the closure 7226 - useClPerm - Use the closure point permutation if available 7227 7228 Output Parameters: 7229 + numIndices - The number of dof indices in the closure of point with the input sections 7230 . indices - The dof indices 7231 . outOffsets - Array to write the field offsets into, or NULL 7232 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7233 7234 Notes: 7235 Must call DMPlexRestoreClosureIndices() to free allocated memory 7236 7237 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7238 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7239 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7240 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7241 indices (with the above semantics) are implied. 7242 7243 Level: advanced 7244 7245 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7246 @*/ 7247 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7248 /* Closure ordering */ 7249 PetscSection clSection; 7250 IS clPoints; 7251 const PetscInt *clp; 7252 PetscInt *points; 7253 const PetscInt *clperm = NULL; 7254 /* Dof permutation and sign flips */ 7255 const PetscInt **perms[32] = {NULL}; 7256 const PetscScalar **flips[32] = {NULL}; 7257 PetscScalar *valCopy = NULL; 7258 /* Hanging node constraints */ 7259 PetscInt *pointsC = NULL; 7260 PetscScalar *valuesC = NULL; 7261 PetscInt NclC, NiC; 7262 7263 PetscInt *idx; 7264 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7265 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7266 7267 PetscFunctionBeginHot; 7268 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7269 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7270 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7271 if (numIndices) PetscValidIntPointer(numIndices, 6); 7272 if (indices) PetscValidPointer(indices, 7); 7273 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7274 if (values) PetscValidPointer(values, 9); 7275 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7276 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7277 PetscCall(PetscArrayzero(offsets, 32)); 7278 /* 1) Get points in closure */ 7279 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7280 if (useClPerm) { 7281 PetscInt depth, clsize; 7282 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7283 for (clsize = 0, p = 0; p < Ncl; p++) { 7284 PetscInt dof; 7285 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7286 clsize += dof; 7287 } 7288 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7289 } 7290 /* 2) Get number of indices on these points and field offsets from section */ 7291 for (p = 0; p < Ncl * 2; p += 2) { 7292 PetscInt dof, fdof; 7293 7294 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7295 for (f = 0; f < Nf; ++f) { 7296 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7297 offsets[f + 1] += fdof; 7298 } 7299 Ni += dof; 7300 } 7301 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7302 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7303 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7304 for (f = 0; f < PetscMax(1, Nf); ++f) { 7305 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7306 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7307 /* may need to apply sign changes to the element matrix */ 7308 if (values && flips[f]) { 7309 PetscInt foffset = offsets[f]; 7310 7311 for (p = 0; p < Ncl; ++p) { 7312 PetscInt pnt = points[2 * p], fdof; 7313 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7314 7315 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7316 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7317 if (flip) { 7318 PetscInt i, j, k; 7319 7320 if (!valCopy) { 7321 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7322 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7323 *values = valCopy; 7324 } 7325 for (i = 0; i < fdof; ++i) { 7326 PetscScalar fval = flip[i]; 7327 7328 for (k = 0; k < Ni; ++k) { 7329 valCopy[Ni * (foffset + i) + k] *= fval; 7330 valCopy[Ni * k + (foffset + i)] *= fval; 7331 } 7332 } 7333 } 7334 foffset += fdof; 7335 } 7336 } 7337 } 7338 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7339 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7340 if (NclC) { 7341 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7342 for (f = 0; f < PetscMax(1, Nf); ++f) { 7343 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7344 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7345 } 7346 for (f = 0; f < PetscMax(1, Nf); ++f) { 7347 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7348 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7349 } 7350 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7351 Ncl = NclC; 7352 Ni = NiC; 7353 points = pointsC; 7354 if (values) *values = valuesC; 7355 } 7356 /* 5) Calculate indices */ 7357 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7358 if (Nf) { 7359 PetscInt idxOff; 7360 PetscBool useFieldOffsets; 7361 7362 if (outOffsets) { 7363 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7364 } 7365 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7366 if (useFieldOffsets) { 7367 for (p = 0; p < Ncl; ++p) { 7368 const PetscInt pnt = points[p * 2]; 7369 7370 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7371 } 7372 } else { 7373 for (p = 0; p < Ncl; ++p) { 7374 const PetscInt pnt = points[p * 2]; 7375 7376 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7377 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7378 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7379 * global section. */ 7380 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7381 } 7382 } 7383 } else { 7384 PetscInt off = 0, idxOff; 7385 7386 for (p = 0; p < Ncl; ++p) { 7387 const PetscInt pnt = points[p * 2]; 7388 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7389 7390 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7391 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7392 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7393 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7394 } 7395 } 7396 /* 6) Cleanup */ 7397 for (f = 0; f < PetscMax(1, Nf); ++f) { 7398 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7399 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7400 } 7401 if (NclC) { 7402 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7403 } else { 7404 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7405 } 7406 7407 if (numIndices) *numIndices = Ni; 7408 if (indices) *indices = idx; 7409 PetscFunctionReturn(0); 7410 } 7411 7412 /*@C 7413 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7414 7415 Not collective 7416 7417 Input Parameters: 7418 + dm - The DM 7419 . section - The PetscSection describing the points (a local section) 7420 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7421 . point - The point defining the closure 7422 - useClPerm - Use the closure point permutation if available 7423 7424 Output Parameters: 7425 + numIndices - The number of dof indices in the closure of point with the input sections 7426 . indices - The dof indices 7427 . outOffsets - Array to write the field offsets into, or NULL 7428 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7429 7430 Notes: 7431 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7432 7433 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7434 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7435 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7436 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7437 indices (with the above semantics) are implied. 7438 7439 Level: advanced 7440 7441 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7442 @*/ 7443 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7444 PetscFunctionBegin; 7445 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7446 PetscValidPointer(indices, 7); 7447 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7448 PetscFunctionReturn(0); 7449 } 7450 7451 /*@C 7452 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7453 7454 Not collective 7455 7456 Input Parameters: 7457 + dm - The DM 7458 . section - The section describing the layout in v, or NULL to use the default section 7459 . globalSection - The section describing the layout in v, or NULL to use the default global section 7460 . A - The matrix 7461 . point - The point in the DM 7462 . values - The array of values 7463 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7464 7465 Fortran Notes: 7466 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7467 7468 Level: intermediate 7469 7470 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7471 @*/ 7472 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7473 DM_Plex *mesh = (DM_Plex *)dm->data; 7474 PetscInt *indices; 7475 PetscInt numIndices; 7476 const PetscScalar *valuesOrig = values; 7477 PetscErrorCode ierr; 7478 7479 PetscFunctionBegin; 7480 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7481 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7482 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7483 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7484 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7485 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7486 7487 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7488 7489 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7490 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7491 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7492 if (ierr) { 7493 PetscMPIInt rank; 7494 7495 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7496 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7497 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7498 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7499 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7500 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7501 } 7502 if (mesh->printFEM > 1) { 7503 PetscInt i; 7504 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7505 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7506 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7507 } 7508 7509 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7510 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7511 PetscFunctionReturn(0); 7512 } 7513 7514 /*@C 7515 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7516 7517 Not collective 7518 7519 Input Parameters: 7520 + dmRow - The DM for the row fields 7521 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7522 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7523 . dmCol - The DM for the column fields 7524 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7525 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7526 . A - The matrix 7527 . point - The point in the DMs 7528 . values - The array of values 7529 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7530 7531 Level: intermediate 7532 7533 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7534 @*/ 7535 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7536 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7537 PetscInt *indicesRow, *indicesCol; 7538 PetscInt numIndicesRow, numIndicesCol; 7539 const PetscScalar *valuesOrig = values; 7540 PetscErrorCode ierr; 7541 7542 PetscFunctionBegin; 7543 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7544 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7545 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7546 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7547 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7548 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7549 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7550 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7551 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7552 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7553 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7554 7555 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7556 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7557 7558 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7559 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7560 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7561 if (ierr) { 7562 PetscMPIInt rank; 7563 7564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7565 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7566 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7567 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7568 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7569 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7570 } 7571 7572 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7573 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7574 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7575 PetscFunctionReturn(0); 7576 } 7577 7578 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7579 DM_Plex *mesh = (DM_Plex *)dmf->data; 7580 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7581 PetscInt *cpoints = NULL; 7582 PetscInt *findices, *cindices; 7583 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7584 PetscInt foffsets[32], coffsets[32]; 7585 DMPolytopeType ct; 7586 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7587 PetscErrorCode ierr; 7588 7589 PetscFunctionBegin; 7590 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7591 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7592 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7593 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7594 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7595 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7596 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7597 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7598 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7599 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7600 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7601 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7602 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7603 PetscCall(PetscArrayzero(foffsets, 32)); 7604 PetscCall(PetscArrayzero(coffsets, 32)); 7605 /* Column indices */ 7606 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7607 maxFPoints = numCPoints; 7608 /* Compress out points not in the section */ 7609 /* TODO: Squeeze out points with 0 dof as well */ 7610 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7611 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7612 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7613 cpoints[q * 2] = cpoints[p]; 7614 cpoints[q * 2 + 1] = cpoints[p + 1]; 7615 ++q; 7616 } 7617 } 7618 numCPoints = q; 7619 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7620 PetscInt fdof; 7621 7622 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7623 if (!dof) continue; 7624 for (f = 0; f < numFields; ++f) { 7625 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7626 coffsets[f + 1] += fdof; 7627 } 7628 numCIndices += dof; 7629 } 7630 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7631 /* Row indices */ 7632 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7633 { 7634 DMPlexTransform tr; 7635 DMPolytopeType *rct; 7636 PetscInt *rsize, *rcone, *rornt, Nt; 7637 7638 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7639 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7640 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7641 numSubcells = rsize[Nt - 1]; 7642 PetscCall(DMPlexTransformDestroy(&tr)); 7643 } 7644 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7645 for (r = 0, q = 0; r < numSubcells; ++r) { 7646 /* TODO Map from coarse to fine cells */ 7647 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7648 /* Compress out points not in the section */ 7649 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7650 for (p = 0; p < numFPoints * 2; p += 2) { 7651 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7652 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7653 if (!dof) continue; 7654 for (s = 0; s < q; ++s) 7655 if (fpoints[p] == ftotpoints[s * 2]) break; 7656 if (s < q) continue; 7657 ftotpoints[q * 2] = fpoints[p]; 7658 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7659 ++q; 7660 } 7661 } 7662 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7663 } 7664 numFPoints = q; 7665 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7666 PetscInt fdof; 7667 7668 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7669 if (!dof) continue; 7670 for (f = 0; f < numFields; ++f) { 7671 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7672 foffsets[f + 1] += fdof; 7673 } 7674 numFIndices += dof; 7675 } 7676 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7677 7678 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7679 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7680 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7681 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7682 if (numFields) { 7683 const PetscInt **permsF[32] = {NULL}; 7684 const PetscInt **permsC[32] = {NULL}; 7685 7686 for (f = 0; f < numFields; f++) { 7687 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7688 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7689 } 7690 for (p = 0; p < numFPoints; p++) { 7691 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7692 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7693 } 7694 for (p = 0; p < numCPoints; p++) { 7695 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7696 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7697 } 7698 for (f = 0; f < numFields; f++) { 7699 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7700 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7701 } 7702 } else { 7703 const PetscInt **permsF = NULL; 7704 const PetscInt **permsC = NULL; 7705 7706 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7707 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7708 for (p = 0, off = 0; p < numFPoints; p++) { 7709 const PetscInt *perm = permsF ? permsF[p] : NULL; 7710 7711 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7712 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7713 } 7714 for (p = 0, off = 0; p < numCPoints; p++) { 7715 const PetscInt *perm = permsC ? permsC[p] : NULL; 7716 7717 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7718 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7719 } 7720 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7721 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7722 } 7723 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7724 /* TODO: flips */ 7725 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7726 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7727 if (ierr) { 7728 PetscMPIInt rank; 7729 7730 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7731 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7732 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7733 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7734 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7735 } 7736 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7737 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7738 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7739 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7740 PetscFunctionReturn(0); 7741 } 7742 7743 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) { 7744 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7745 PetscInt *cpoints = NULL; 7746 PetscInt foffsets[32], coffsets[32]; 7747 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7748 DMPolytopeType ct; 7749 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7750 7751 PetscFunctionBegin; 7752 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7753 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7754 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7755 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7756 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7757 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7758 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7759 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7760 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7761 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7762 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7763 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7764 PetscCall(PetscArrayzero(foffsets, 32)); 7765 PetscCall(PetscArrayzero(coffsets, 32)); 7766 /* Column indices */ 7767 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7768 maxFPoints = numCPoints; 7769 /* Compress out points not in the section */ 7770 /* TODO: Squeeze out points with 0 dof as well */ 7771 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7772 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7773 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7774 cpoints[q * 2] = cpoints[p]; 7775 cpoints[q * 2 + 1] = cpoints[p + 1]; 7776 ++q; 7777 } 7778 } 7779 numCPoints = q; 7780 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7781 PetscInt fdof; 7782 7783 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7784 if (!dof) continue; 7785 for (f = 0; f < numFields; ++f) { 7786 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7787 coffsets[f + 1] += fdof; 7788 } 7789 numCIndices += dof; 7790 } 7791 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7792 /* Row indices */ 7793 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7794 { 7795 DMPlexTransform tr; 7796 DMPolytopeType *rct; 7797 PetscInt *rsize, *rcone, *rornt, Nt; 7798 7799 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7800 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7801 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7802 numSubcells = rsize[Nt - 1]; 7803 PetscCall(DMPlexTransformDestroy(&tr)); 7804 } 7805 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7806 for (r = 0, q = 0; r < numSubcells; ++r) { 7807 /* TODO Map from coarse to fine cells */ 7808 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7809 /* Compress out points not in the section */ 7810 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7811 for (p = 0; p < numFPoints * 2; p += 2) { 7812 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7813 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7814 if (!dof) continue; 7815 for (s = 0; s < q; ++s) 7816 if (fpoints[p] == ftotpoints[s * 2]) break; 7817 if (s < q) continue; 7818 ftotpoints[q * 2] = fpoints[p]; 7819 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7820 ++q; 7821 } 7822 } 7823 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7824 } 7825 numFPoints = q; 7826 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7827 PetscInt fdof; 7828 7829 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7830 if (!dof) continue; 7831 for (f = 0; f < numFields; ++f) { 7832 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7833 foffsets[f + 1] += fdof; 7834 } 7835 numFIndices += dof; 7836 } 7837 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7838 7839 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7840 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7841 if (numFields) { 7842 const PetscInt **permsF[32] = {NULL}; 7843 const PetscInt **permsC[32] = {NULL}; 7844 7845 for (f = 0; f < numFields; f++) { 7846 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7847 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7848 } 7849 for (p = 0; p < numFPoints; p++) { 7850 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7851 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7852 } 7853 for (p = 0; p < numCPoints; p++) { 7854 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7855 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7856 } 7857 for (f = 0; f < numFields; f++) { 7858 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7859 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7860 } 7861 } else { 7862 const PetscInt **permsF = NULL; 7863 const PetscInt **permsC = NULL; 7864 7865 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7866 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7867 for (p = 0, off = 0; p < numFPoints; p++) { 7868 const PetscInt *perm = permsF ? permsF[p] : NULL; 7869 7870 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7871 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7872 } 7873 for (p = 0, off = 0; p < numCPoints; p++) { 7874 const PetscInt *perm = permsC ? permsC[p] : NULL; 7875 7876 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7877 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7878 } 7879 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7880 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7881 } 7882 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7883 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7884 PetscFunctionReturn(0); 7885 } 7886 7887 /*@C 7888 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7889 7890 Input Parameter: 7891 . dm - The DMPlex object 7892 7893 Output Parameter: 7894 . cellHeight - The height of a cell 7895 7896 Level: developer 7897 7898 .seealso `DMPlexSetVTKCellHeight()` 7899 @*/ 7900 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) { 7901 DM_Plex *mesh = (DM_Plex *)dm->data; 7902 7903 PetscFunctionBegin; 7904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7905 PetscValidIntPointer(cellHeight, 2); 7906 *cellHeight = mesh->vtkCellHeight; 7907 PetscFunctionReturn(0); 7908 } 7909 7910 /*@C 7911 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7912 7913 Input Parameters: 7914 + dm - The DMPlex object 7915 - cellHeight - The height of a cell 7916 7917 Level: developer 7918 7919 .seealso `DMPlexGetVTKCellHeight()` 7920 @*/ 7921 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) { 7922 DM_Plex *mesh = (DM_Plex *)dm->data; 7923 7924 PetscFunctionBegin; 7925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7926 mesh->vtkCellHeight = cellHeight; 7927 PetscFunctionReturn(0); 7928 } 7929 7930 /*@ 7931 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7932 7933 Input Parameter: 7934 . dm - The DMPlex object 7935 7936 Output Parameters: 7937 + gcStart - The first ghost cell, or NULL 7938 - gcEnd - The upper bound on ghost cells, or NULL 7939 7940 Level: advanced 7941 7942 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7943 @*/ 7944 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) { 7945 DMLabel ctLabel; 7946 7947 PetscFunctionBegin; 7948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7949 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7950 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7951 // Reset label for fast lookup 7952 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 7953 PetscFunctionReturn(0); 7954 } 7955 7956 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) { 7957 PetscSection section, globalSection; 7958 PetscInt *numbers, p; 7959 7960 PetscFunctionBegin; 7961 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 7962 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 7963 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 7964 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 7965 PetscCall(PetscSectionSetUp(section)); 7966 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 7967 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 7968 for (p = pStart; p < pEnd; ++p) { 7969 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 7970 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 7971 else numbers[p - pStart] += shift; 7972 } 7973 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 7974 if (globalSize) { 7975 PetscLayout layout; 7976 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 7977 PetscCall(PetscLayoutGetSize(layout, globalSize)); 7978 PetscCall(PetscLayoutDestroy(&layout)); 7979 } 7980 PetscCall(PetscSectionDestroy(§ion)); 7981 PetscCall(PetscSectionDestroy(&globalSection)); 7982 PetscFunctionReturn(0); 7983 } 7984 7985 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) { 7986 PetscInt cellHeight, cStart, cEnd; 7987 7988 PetscFunctionBegin; 7989 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 7990 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 7991 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 7992 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 7993 PetscFunctionReturn(0); 7994 } 7995 7996 /*@ 7997 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 7998 7999 Input Parameter: 8000 . dm - The DMPlex object 8001 8002 Output Parameter: 8003 . globalCellNumbers - Global cell numbers for all cells on this process 8004 8005 Level: developer 8006 8007 .seealso `DMPlexGetVertexNumbering()` 8008 @*/ 8009 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) { 8010 DM_Plex *mesh = (DM_Plex *)dm->data; 8011 8012 PetscFunctionBegin; 8013 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8014 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8015 *globalCellNumbers = mesh->globalCellNumbers; 8016 PetscFunctionReturn(0); 8017 } 8018 8019 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) { 8020 PetscInt vStart, vEnd; 8021 8022 PetscFunctionBegin; 8023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8024 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8025 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8026 PetscFunctionReturn(0); 8027 } 8028 8029 /*@ 8030 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8031 8032 Input Parameter: 8033 . dm - The DMPlex object 8034 8035 Output Parameter: 8036 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8037 8038 Level: developer 8039 8040 .seealso `DMPlexGetCellNumbering()` 8041 @*/ 8042 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) { 8043 DM_Plex *mesh = (DM_Plex *)dm->data; 8044 8045 PetscFunctionBegin; 8046 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8047 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8048 *globalVertexNumbers = mesh->globalVertexNumbers; 8049 PetscFunctionReturn(0); 8050 } 8051 8052 /*@ 8053 DMPlexCreatePointNumbering - Create a global numbering for all points. 8054 8055 Collective on dm 8056 8057 Input Parameter: 8058 . dm - The DMPlex object 8059 8060 Output Parameter: 8061 . globalPointNumbers - Global numbers for all points on this process 8062 8063 Notes: 8064 8065 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8066 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8067 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8068 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8069 8070 The partitioned mesh is 8071 ``` 8072 (2)--0--(3)--1--(4) (1)--0--(2) 8073 ``` 8074 and its global numbering is 8075 ``` 8076 (3)--0--(4)--1--(5)--2--(6) 8077 ``` 8078 Then the global numbering is provided as 8079 ``` 8080 [0] Number of indices in set 5 8081 [0] 0 0 8082 [0] 1 1 8083 [0] 2 3 8084 [0] 3 4 8085 [0] 4 -6 8086 [1] Number of indices in set 3 8087 [1] 0 2 8088 [1] 1 5 8089 [1] 2 6 8090 ``` 8091 8092 Level: developer 8093 8094 .seealso `DMPlexGetCellNumbering()` 8095 @*/ 8096 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) { 8097 IS nums[4]; 8098 PetscInt depths[4], gdepths[4], starts[4]; 8099 PetscInt depth, d, shift = 0; 8100 PetscBool empty = PETSC_FALSE; 8101 8102 PetscFunctionBegin; 8103 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8104 PetscCall(DMPlexGetDepth(dm, &depth)); 8105 // For unstratified meshes use dim instead of depth 8106 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8107 // If any stratum is empty, we must mark all empty 8108 for (d = 0; d <= depth; ++d) { 8109 PetscInt end; 8110 8111 depths[d] = depth - d; 8112 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8113 if (!(starts[d] - end)) empty = PETSC_TRUE; 8114 } 8115 if (empty) 8116 for (d = 0; d <= depth; ++d) { 8117 depths[d] = -1; 8118 starts[d] = -1; 8119 } 8120 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8121 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8122 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]); 8123 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8124 for (d = 0; d <= depth; ++d) { 8125 PetscInt pStart, pEnd, gsize; 8126 8127 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8128 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8129 shift += gsize; 8130 } 8131 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8132 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8133 PetscFunctionReturn(0); 8134 } 8135 8136 /*@ 8137 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8138 8139 Input Parameter: 8140 . dm - The DMPlex object 8141 8142 Output Parameter: 8143 . ranks - The rank field 8144 8145 Options Database Keys: 8146 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8147 8148 Level: intermediate 8149 8150 .seealso: `DMView()` 8151 @*/ 8152 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) { 8153 DM rdm; 8154 PetscFE fe; 8155 PetscScalar *r; 8156 PetscMPIInt rank; 8157 DMPolytopeType ct; 8158 PetscInt dim, cStart, cEnd, c; 8159 PetscBool simplex; 8160 8161 PetscFunctionBeginUser; 8162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8163 PetscValidPointer(ranks, 2); 8164 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8165 PetscCall(DMClone(dm, &rdm)); 8166 PetscCall(DMGetDimension(rdm, &dim)); 8167 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8168 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8169 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8170 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8171 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8172 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8173 PetscCall(PetscFEDestroy(&fe)); 8174 PetscCall(DMCreateDS(rdm)); 8175 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8176 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8177 PetscCall(VecGetArray(*ranks, &r)); 8178 for (c = cStart; c < cEnd; ++c) { 8179 PetscScalar *lr; 8180 8181 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8182 if (lr) *lr = rank; 8183 } 8184 PetscCall(VecRestoreArray(*ranks, &r)); 8185 PetscCall(DMDestroy(&rdm)); 8186 PetscFunctionReturn(0); 8187 } 8188 8189 /*@ 8190 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8191 8192 Input Parameters: 8193 + dm - The DMPlex 8194 - label - The DMLabel 8195 8196 Output Parameter: 8197 . val - The label value field 8198 8199 Options Database Keys: 8200 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8201 8202 Level: intermediate 8203 8204 .seealso: `DMView()` 8205 @*/ 8206 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) { 8207 DM rdm; 8208 PetscFE fe; 8209 PetscScalar *v; 8210 PetscInt dim, cStart, cEnd, c; 8211 8212 PetscFunctionBeginUser; 8213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8214 PetscValidPointer(label, 2); 8215 PetscValidPointer(val, 3); 8216 PetscCall(DMClone(dm, &rdm)); 8217 PetscCall(DMGetDimension(rdm, &dim)); 8218 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8219 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8220 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8221 PetscCall(PetscFEDestroy(&fe)); 8222 PetscCall(DMCreateDS(rdm)); 8223 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8224 PetscCall(DMCreateGlobalVector(rdm, val)); 8225 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8226 PetscCall(VecGetArray(*val, &v)); 8227 for (c = cStart; c < cEnd; ++c) { 8228 PetscScalar *lv; 8229 PetscInt cval; 8230 8231 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8232 PetscCall(DMLabelGetValue(label, c, &cval)); 8233 *lv = cval; 8234 } 8235 PetscCall(VecRestoreArray(*val, &v)); 8236 PetscCall(DMDestroy(&rdm)); 8237 PetscFunctionReturn(0); 8238 } 8239 8240 /*@ 8241 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8242 8243 Input Parameter: 8244 . dm - The DMPlex object 8245 8246 Notes: 8247 This is a useful diagnostic when creating meshes programmatically. 8248 8249 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8250 8251 Level: developer 8252 8253 .seealso: `DMCreate()`, `DMSetFromOptions()` 8254 @*/ 8255 PetscErrorCode DMPlexCheckSymmetry(DM dm) { 8256 PetscSection coneSection, supportSection; 8257 const PetscInt *cone, *support; 8258 PetscInt coneSize, c, supportSize, s; 8259 PetscInt pStart, pEnd, p, pp, csize, ssize; 8260 PetscBool storagecheck = PETSC_TRUE; 8261 8262 PetscFunctionBegin; 8263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8264 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8265 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8266 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8267 /* Check that point p is found in the support of its cone points, and vice versa */ 8268 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8269 for (p = pStart; p < pEnd; ++p) { 8270 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8271 PetscCall(DMPlexGetCone(dm, p, &cone)); 8272 for (c = 0; c < coneSize; ++c) { 8273 PetscBool dup = PETSC_FALSE; 8274 PetscInt d; 8275 for (d = c - 1; d >= 0; --d) { 8276 if (cone[c] == cone[d]) { 8277 dup = PETSC_TRUE; 8278 break; 8279 } 8280 } 8281 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8282 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8283 for (s = 0; s < supportSize; ++s) { 8284 if (support[s] == p) break; 8285 } 8286 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8287 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8288 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8289 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8290 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8291 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8292 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8293 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]); 8294 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8295 } 8296 } 8297 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8298 if (p != pp) { 8299 storagecheck = PETSC_FALSE; 8300 continue; 8301 } 8302 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8303 PetscCall(DMPlexGetSupport(dm, p, &support)); 8304 for (s = 0; s < supportSize; ++s) { 8305 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8306 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8307 for (c = 0; c < coneSize; ++c) { 8308 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8309 if (cone[c] != pp) { 8310 c = 0; 8311 break; 8312 } 8313 if (cone[c] == p) break; 8314 } 8315 if (c >= coneSize) { 8316 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8317 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8318 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8319 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8320 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8321 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8322 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8323 } 8324 } 8325 } 8326 if (storagecheck) { 8327 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8328 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8329 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8330 } 8331 PetscFunctionReturn(0); 8332 } 8333 8334 /* 8335 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. 8336 */ 8337 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) { 8338 DMPolytopeType cct; 8339 PetscInt ptpoints[4]; 8340 const PetscInt *cone, *ccone, *ptcone; 8341 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8342 8343 PetscFunctionBegin; 8344 *unsplit = 0; 8345 switch (ct) { 8346 case DM_POLYTOPE_POINT_PRISM_TENSOR: ptpoints[npt++] = c; break; 8347 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8348 PetscCall(DMPlexGetCone(dm, c, &cone)); 8349 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8350 for (cp = 0; cp < coneSize; ++cp) { 8351 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8352 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8353 } 8354 break; 8355 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8356 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8357 PetscCall(DMPlexGetCone(dm, c, &cone)); 8358 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8359 for (cp = 0; cp < coneSize; ++cp) { 8360 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8361 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8362 for (ccp = 0; ccp < cconeSize; ++ccp) { 8363 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8364 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8365 PetscInt p; 8366 for (p = 0; p < npt; ++p) 8367 if (ptpoints[p] == ccone[ccp]) break; 8368 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8369 } 8370 } 8371 } 8372 break; 8373 default: break; 8374 } 8375 for (pt = 0; pt < npt; ++pt) { 8376 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8377 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8378 } 8379 PetscFunctionReturn(0); 8380 } 8381 8382 /*@ 8383 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8384 8385 Input Parameters: 8386 + dm - The DMPlex object 8387 - cellHeight - Normally 0 8388 8389 Notes: 8390 This is a useful diagnostic when creating meshes programmatically. 8391 Currently applicable only to homogeneous simplex or tensor meshes. 8392 8393 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8394 8395 Level: developer 8396 8397 .seealso: `DMCreate()`, `DMSetFromOptions()` 8398 @*/ 8399 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) { 8400 DMPlexInterpolatedFlag interp; 8401 DMPolytopeType ct; 8402 PetscInt vStart, vEnd, cStart, cEnd, c; 8403 8404 PetscFunctionBegin; 8405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8406 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8407 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8408 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8409 for (c = cStart; c < cEnd; ++c) { 8410 PetscInt *closure = NULL; 8411 PetscInt coneSize, closureSize, cl, Nv = 0; 8412 8413 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8414 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8415 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8416 if (interp == DMPLEX_INTERPOLATED_FULL) { 8417 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8418 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)); 8419 } 8420 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8421 for (cl = 0; cl < closureSize * 2; cl += 2) { 8422 const PetscInt p = closure[cl]; 8423 if ((p >= vStart) && (p < vEnd)) ++Nv; 8424 } 8425 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8426 /* Special Case: Tensor faces with identified vertices */ 8427 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8428 PetscInt unsplit; 8429 8430 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8431 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8432 } 8433 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)); 8434 } 8435 PetscFunctionReturn(0); 8436 } 8437 8438 /*@ 8439 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8440 8441 Collective 8442 8443 Input Parameters: 8444 + dm - The DMPlex object 8445 - cellHeight - Normally 0 8446 8447 Notes: 8448 This is a useful diagnostic when creating meshes programmatically. 8449 This routine is only relevant for meshes that are fully interpolated across all ranks. 8450 It will error out if a partially interpolated mesh is given on some rank. 8451 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8452 8453 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8454 8455 Level: developer 8456 8457 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8458 @*/ 8459 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) { 8460 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8461 DMPlexInterpolatedFlag interpEnum; 8462 8463 PetscFunctionBegin; 8464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8465 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8466 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8467 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8468 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8469 PetscFunctionReturn(0); 8470 } 8471 8472 PetscCall(DMGetDimension(dm, &dim)); 8473 PetscCall(DMPlexGetDepth(dm, &depth)); 8474 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8475 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8476 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8477 for (c = cStart; c < cEnd; ++c) { 8478 const PetscInt *cone, *ornt, *faceSizes, *faces; 8479 const DMPolytopeType *faceTypes; 8480 DMPolytopeType ct; 8481 PetscInt numFaces, coneSize, f; 8482 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8483 8484 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8485 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8486 if (unsplit) continue; 8487 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8488 PetscCall(DMPlexGetCone(dm, c, &cone)); 8489 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8490 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8491 for (cl = 0; cl < closureSize * 2; cl += 2) { 8492 const PetscInt p = closure[cl]; 8493 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8494 } 8495 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8496 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); 8497 for (f = 0; f < numFaces; ++f) { 8498 DMPolytopeType fct; 8499 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8500 8501 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8502 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8503 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8504 const PetscInt p = fclosure[cl]; 8505 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8506 } 8507 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]); 8508 for (v = 0; v < fnumCorners; ++v) { 8509 if (fclosure[v] != faces[fOff + v]) { 8510 PetscInt v1; 8511 8512 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8513 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8514 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8515 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8516 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8517 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]); 8518 } 8519 } 8520 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8521 fOff += faceSizes[f]; 8522 } 8523 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8524 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8525 } 8526 } 8527 PetscFunctionReturn(0); 8528 } 8529 8530 /*@ 8531 DMPlexCheckGeometry - Check the geometry of mesh cells 8532 8533 Input Parameter: 8534 . dm - The DMPlex object 8535 8536 Notes: 8537 This is a useful diagnostic when creating meshes programmatically. 8538 8539 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8540 8541 Level: developer 8542 8543 .seealso: `DMCreate()`, `DMSetFromOptions()` 8544 @*/ 8545 PetscErrorCode DMPlexCheckGeometry(DM dm) { 8546 Vec coordinates; 8547 PetscReal detJ, J[9], refVol = 1.0; 8548 PetscReal vol; 8549 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8550 8551 PetscFunctionBegin; 8552 PetscCall(DMGetDimension(dm, &dim)); 8553 PetscCall(DMGetCoordinateDim(dm, &dE)); 8554 if (dim != dE) PetscFunctionReturn(0); 8555 PetscCall(DMPlexGetDepth(dm, &depth)); 8556 for (d = 0; d < dim; ++d) refVol *= 2.0; 8557 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8558 /* Make sure local coordinates are created, because that step is collective */ 8559 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8560 for (c = cStart; c < cEnd; ++c) { 8561 DMPolytopeType ct; 8562 PetscInt unsplit; 8563 PetscBool ignoreZeroVol = PETSC_FALSE; 8564 8565 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8566 switch (ct) { 8567 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8568 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8569 case DM_POLYTOPE_QUAD_PRISM_TENSOR: ignoreZeroVol = PETSC_TRUE; break; 8570 default: break; 8571 } 8572 switch (ct) { 8573 case DM_POLYTOPE_TRI_PRISM: 8574 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8575 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8576 case DM_POLYTOPE_PYRAMID: continue; 8577 default: break; 8578 } 8579 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8580 if (unsplit) continue; 8581 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8582 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); 8583 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8584 /* This should work with periodicity since DG coordinates should be used */ 8585 if (depth > 1) { 8586 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8587 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); 8588 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8589 } 8590 } 8591 PetscFunctionReturn(0); 8592 } 8593 8594 /*@ 8595 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8596 8597 Collective 8598 8599 Input Parameters: 8600 + dm - The DMPlex object 8601 - pointSF - The Point SF, or NULL for Point SF attached to DM 8602 8603 Notes: 8604 This is mainly intended for debugging/testing purposes. 8605 8606 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8607 8608 Level: developer 8609 8610 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8611 @*/ 8612 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) { 8613 PetscInt l, nleaves, nroots, overlap; 8614 const PetscInt *locals; 8615 const PetscSFNode *remotes; 8616 PetscBool distributed; 8617 MPI_Comm comm; 8618 PetscMPIInt rank; 8619 8620 PetscFunctionBegin; 8621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8622 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8623 else pointSF = dm->sf; 8624 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8625 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8626 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8627 { 8628 PetscMPIInt mpiFlag; 8629 8630 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8631 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8632 } 8633 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8634 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8635 if (!distributed) { 8636 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); 8637 PetscFunctionReturn(0); 8638 } 8639 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); 8640 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8641 8642 /* Check SF graph is compatible with DMPlex chart */ 8643 { 8644 PetscInt pStart, pEnd, maxLeaf; 8645 8646 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8647 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8648 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8649 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8650 } 8651 8652 /* Check Point SF has no local points referenced */ 8653 for (l = 0; l < nleaves; l++) { 8654 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); 8655 } 8656 8657 /* Check there are no cells in interface */ 8658 if (!overlap) { 8659 PetscInt cellHeight, cStart, cEnd; 8660 8661 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8662 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8663 for (l = 0; l < nleaves; ++l) { 8664 const PetscInt point = locals ? locals[l] : l; 8665 8666 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8667 } 8668 } 8669 8670 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8671 { 8672 const PetscInt *rootdegree; 8673 8674 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8675 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8676 for (l = 0; l < nleaves; ++l) { 8677 const PetscInt point = locals ? locals[l] : l; 8678 const PetscInt *cone; 8679 PetscInt coneSize, c, idx; 8680 8681 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8682 PetscCall(DMPlexGetCone(dm, point, &cone)); 8683 for (c = 0; c < coneSize; ++c) { 8684 if (!rootdegree[cone[c]]) { 8685 if (locals) { 8686 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8687 } else { 8688 idx = (cone[c] < nleaves) ? cone[c] : -1; 8689 } 8690 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8691 } 8692 } 8693 } 8694 } 8695 PetscFunctionReturn(0); 8696 } 8697 8698 /*@ 8699 DMPlexCheck - Perform various checks of Plex sanity 8700 8701 Input Parameter: 8702 . dm - The DMPlex object 8703 8704 Notes: 8705 This is a useful diagnostic when creating meshes programmatically. 8706 8707 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8708 8709 Currently does not include DMPlexCheckCellShape(). 8710 8711 Level: developer 8712 8713 .seealso: DMCreate(), DMSetFromOptions() 8714 @*/ 8715 PetscErrorCode DMPlexCheck(DM dm) { 8716 PetscInt cellHeight; 8717 8718 PetscFunctionBegin; 8719 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8720 PetscCall(DMPlexCheckSymmetry(dm)); 8721 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8722 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8723 PetscCall(DMPlexCheckGeometry(dm)); 8724 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8725 PetscCall(DMPlexCheckInterfaceCones(dm)); 8726 PetscFunctionReturn(0); 8727 } 8728 8729 typedef struct cell_stats { 8730 PetscReal min, max, sum, squaresum; 8731 PetscInt count; 8732 } cell_stats_t; 8733 8734 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) { 8735 PetscInt i, N = *len; 8736 8737 for (i = 0; i < N; i++) { 8738 cell_stats_t *A = (cell_stats_t *)a; 8739 cell_stats_t *B = (cell_stats_t *)b; 8740 8741 B->min = PetscMin(A->min, B->min); 8742 B->max = PetscMax(A->max, B->max); 8743 B->sum += A->sum; 8744 B->squaresum += A->squaresum; 8745 B->count += A->count; 8746 } 8747 } 8748 8749 /*@ 8750 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8751 8752 Collective on dm 8753 8754 Input Parameters: 8755 + dm - The DMPlex object 8756 . output - If true, statistics will be displayed on stdout 8757 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8758 8759 Notes: 8760 This is mainly intended for debugging/testing purposes. 8761 8762 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8763 8764 Level: developer 8765 8766 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8767 @*/ 8768 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) { 8769 DM dmCoarse; 8770 cell_stats_t stats, globalStats; 8771 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8772 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8773 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8774 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8775 PetscMPIInt rank, size; 8776 8777 PetscFunctionBegin; 8778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8779 stats.min = PETSC_MAX_REAL; 8780 stats.max = PETSC_MIN_REAL; 8781 stats.sum = stats.squaresum = 0.; 8782 stats.count = 0; 8783 8784 PetscCallMPI(MPI_Comm_size(comm, &size)); 8785 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8786 PetscCall(DMGetCoordinateDim(dm, &cdim)); 8787 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8788 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 8789 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8790 for (c = cStart; c < cEnd; c++) { 8791 PetscInt i; 8792 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8793 8794 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 8795 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8796 for (i = 0; i < PetscSqr(cdim); ++i) { 8797 frobJ += J[i] * J[i]; 8798 frobInvJ += invJ[i] * invJ[i]; 8799 } 8800 cond2 = frobJ * frobInvJ; 8801 cond = PetscSqrtReal(cond2); 8802 8803 stats.min = PetscMin(stats.min, cond); 8804 stats.max = PetscMax(stats.max, cond); 8805 stats.sum += cond; 8806 stats.squaresum += cond2; 8807 stats.count++; 8808 if (output && cond > limit) { 8809 PetscSection coordSection; 8810 Vec coordsLocal; 8811 PetscScalar *coords = NULL; 8812 PetscInt Nv, d, clSize, cl, *closure = NULL; 8813 8814 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8815 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8816 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8817 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 8818 for (i = 0; i < Nv / cdim; ++i) { 8819 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8820 for (d = 0; d < cdim; ++d) { 8821 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8822 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 8823 } 8824 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8825 } 8826 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8827 for (cl = 0; cl < clSize * 2; cl += 2) { 8828 const PetscInt edge = closure[cl]; 8829 8830 if ((edge >= eStart) && (edge < eEnd)) { 8831 PetscReal len; 8832 8833 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8834 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 8835 } 8836 } 8837 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8838 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8839 } 8840 } 8841 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8842 8843 if (size > 1) { 8844 PetscMPIInt blockLengths[2] = {4, 1}; 8845 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 8846 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 8847 MPI_Op statReduce; 8848 8849 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 8850 PetscCallMPI(MPI_Type_commit(&statType)); 8851 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8852 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 8853 PetscCallMPI(MPI_Op_free(&statReduce)); 8854 PetscCallMPI(MPI_Type_free(&statType)); 8855 } else { 8856 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 8857 } 8858 if (rank == 0) { 8859 count = globalStats.count; 8860 min = globalStats.min; 8861 max = globalStats.max; 8862 mean = globalStats.sum / globalStats.count; 8863 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 8864 } 8865 8866 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)); 8867 PetscCall(PetscFree2(J, invJ)); 8868 8869 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 8870 if (dmCoarse) { 8871 PetscBool isplex; 8872 8873 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 8874 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 8875 } 8876 PetscFunctionReturn(0); 8877 } 8878 8879 /*@ 8880 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8881 orthogonal quality below given tolerance. 8882 8883 Collective on dm 8884 8885 Input Parameters: 8886 + dm - The DMPlex object 8887 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8888 - atol - [0, 1] Absolute tolerance for tagging cells. 8889 8890 Output Parameters: 8891 + OrthQual - Vec containing orthogonal quality per cell 8892 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8893 8894 Options Database Keys: 8895 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8896 supported. 8897 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8898 8899 Notes: 8900 Orthogonal quality is given by the following formula: 8901 8902 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8903 8904 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 8905 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8906 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8907 calculating the cosine of the angle between these vectors. 8908 8909 Orthogonal quality ranges from 1 (best) to 0 (worst). 8910 8911 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8912 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8913 8914 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8915 8916 Level: intermediate 8917 8918 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8919 @*/ 8920 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) { 8921 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8922 PetscInt *idx; 8923 PetscScalar *oqVals; 8924 const PetscScalar *cellGeomArr, *faceGeomArr; 8925 PetscReal *ci, *fi, *Ai; 8926 MPI_Comm comm; 8927 Vec cellgeom, facegeom; 8928 DM dmFace, dmCell; 8929 IS glob; 8930 ISLocalToGlobalMapping ltog; 8931 PetscViewer vwr; 8932 8933 PetscFunctionBegin; 8934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8935 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 8936 PetscValidPointer(OrthQual, 4); 8937 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 8938 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8939 PetscCall(DMGetDimension(dm, &nc)); 8940 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8941 { 8942 DMPlexInterpolatedFlag interpFlag; 8943 8944 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8945 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8946 PetscMPIInt rank; 8947 8948 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8949 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8950 } 8951 } 8952 if (OrthQualLabel) { 8953 PetscValidPointer(OrthQualLabel, 5); 8954 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8955 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8956 } else { 8957 *OrthQualLabel = NULL; 8958 } 8959 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8960 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8961 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8962 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8963 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8964 PetscCall(VecCreate(comm, OrthQual)); 8965 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8966 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 8967 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8968 PetscCall(VecSetUp(*OrthQual)); 8969 PetscCall(ISDestroy(&glob)); 8970 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8971 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8972 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8973 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8974 PetscCall(VecGetDM(cellgeom, &dmCell)); 8975 PetscCall(VecGetDM(facegeom, &dmFace)); 8976 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8977 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 8978 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8979 PetscInt cellarr[2], *adj = NULL; 8980 PetscScalar *cArr, *fArr; 8981 PetscReal minvalc = 1.0, minvalf = 1.0; 8982 PetscFVCellGeom *cg; 8983 8984 idx[cellIter] = cell - cStart; 8985 cellarr[0] = cell; 8986 /* Make indexing into cellGeom easier */ 8987 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8988 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8989 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8990 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8991 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 8992 PetscInt i; 8993 const PetscInt neigh = adj[cellneigh]; 8994 PetscReal normci = 0, normfi = 0, normai = 0; 8995 PetscFVCellGeom *cgneigh; 8996 PetscFVFaceGeom *fg; 8997 8998 /* Don't count ourselves in the neighbor list */ 8999 if (neigh == cell) continue; 9000 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9001 cellarr[1] = neigh; 9002 { 9003 PetscInt numcovpts; 9004 const PetscInt *covpts; 9005 9006 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9007 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9008 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9009 } 9010 9011 /* Compute c_i, f_i and their norms */ 9012 for (i = 0; i < nc; i++) { 9013 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9014 fi[i] = fg->centroid[i] - cg->centroid[i]; 9015 Ai[i] = fg->normal[i]; 9016 normci += PetscPowReal(ci[i], 2); 9017 normfi += PetscPowReal(fi[i], 2); 9018 normai += PetscPowReal(Ai[i], 2); 9019 } 9020 normci = PetscSqrtReal(normci); 9021 normfi = PetscSqrtReal(normfi); 9022 normai = PetscSqrtReal(normai); 9023 9024 /* Normalize and compute for each face-cell-normal pair */ 9025 for (i = 0; i < nc; i++) { 9026 ci[i] = ci[i] / normci; 9027 fi[i] = fi[i] / normfi; 9028 Ai[i] = Ai[i] / normai; 9029 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9030 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9031 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9032 } 9033 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9034 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9035 } 9036 PetscCall(PetscFree(adj)); 9037 PetscCall(PetscFree2(cArr, fArr)); 9038 /* Defer to cell if they're equal */ 9039 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9040 if (OrthQualLabel) { 9041 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9042 } 9043 } 9044 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9045 PetscCall(VecAssemblyBegin(*OrthQual)); 9046 PetscCall(VecAssemblyEnd(*OrthQual)); 9047 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9048 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9049 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9050 if (OrthQualLabel) { 9051 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9052 } 9053 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9054 PetscCall(PetscViewerDestroy(&vwr)); 9055 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9056 PetscFunctionReturn(0); 9057 } 9058 9059 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9060 * interpolator construction */ 9061 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) { 9062 PetscSection section, newSection, gsection; 9063 PetscSF sf; 9064 PetscBool hasConstraints, ghasConstraints; 9065 9066 PetscFunctionBegin; 9067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9068 PetscValidPointer(odm, 2); 9069 PetscCall(DMGetLocalSection(dm, §ion)); 9070 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9071 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9072 if (!ghasConstraints) { 9073 PetscCall(PetscObjectReference((PetscObject)dm)); 9074 *odm = dm; 9075 PetscFunctionReturn(0); 9076 } 9077 PetscCall(DMClone(dm, odm)); 9078 PetscCall(DMCopyFields(dm, *odm)); 9079 PetscCall(DMGetLocalSection(*odm, &newSection)); 9080 PetscCall(DMGetPointSF(*odm, &sf)); 9081 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9082 PetscCall(DMSetGlobalSection(*odm, gsection)); 9083 PetscCall(PetscSectionDestroy(&gsection)); 9084 PetscFunctionReturn(0); 9085 } 9086 9087 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) { 9088 DM dmco, dmfo; 9089 Mat interpo; 9090 Vec rscale; 9091 Vec cglobalo, clocal; 9092 Vec fglobal, fglobalo, flocal; 9093 PetscBool regular; 9094 9095 PetscFunctionBegin; 9096 PetscCall(DMGetFullDM(dmc, &dmco)); 9097 PetscCall(DMGetFullDM(dmf, &dmfo)); 9098 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9099 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9100 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9101 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9102 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9103 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9104 PetscCall(VecSet(cglobalo, 0.)); 9105 PetscCall(VecSet(clocal, 0.)); 9106 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9107 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9108 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9109 PetscCall(VecSet(fglobal, 0.)); 9110 PetscCall(VecSet(fglobalo, 0.)); 9111 PetscCall(VecSet(flocal, 0.)); 9112 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9113 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9114 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9115 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9116 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9117 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9118 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9119 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9120 *shift = fglobal; 9121 PetscCall(VecDestroy(&flocal)); 9122 PetscCall(VecDestroy(&fglobalo)); 9123 PetscCall(VecDestroy(&clocal)); 9124 PetscCall(VecDestroy(&cglobalo)); 9125 PetscCall(VecDestroy(&rscale)); 9126 PetscCall(MatDestroy(&interpo)); 9127 PetscCall(DMDestroy(&dmfo)); 9128 PetscCall(DMDestroy(&dmco)); 9129 PetscFunctionReturn(0); 9130 } 9131 9132 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) { 9133 PetscObject shifto; 9134 Vec shift; 9135 9136 PetscFunctionBegin; 9137 if (!interp) { 9138 Vec rscale; 9139 9140 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9141 PetscCall(VecDestroy(&rscale)); 9142 } else { 9143 PetscCall(PetscObjectReference((PetscObject)interp)); 9144 } 9145 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9146 if (!shifto) { 9147 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9148 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9149 shifto = (PetscObject)shift; 9150 PetscCall(VecDestroy(&shift)); 9151 } 9152 shift = (Vec)shifto; 9153 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9154 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9155 PetscCall(MatDestroy(&interp)); 9156 PetscFunctionReturn(0); 9157 } 9158 9159 /* Pointwise interpolation 9160 Just code FEM for now 9161 u^f = I u^c 9162 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9163 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9164 I_{ij} = psi^f_i phi^c_j 9165 */ 9166 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) { 9167 PetscSection gsc, gsf; 9168 PetscInt m, n; 9169 void *ctx; 9170 DM cdm; 9171 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9172 9173 PetscFunctionBegin; 9174 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9175 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9176 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9177 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9178 9179 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9180 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9181 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9182 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9183 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9184 9185 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9186 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9187 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9188 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9189 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9190 if (scaling) { 9191 /* Use naive scaling */ 9192 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9193 } 9194 PetscFunctionReturn(0); 9195 } 9196 9197 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) { 9198 VecScatter ctx; 9199 9200 PetscFunctionBegin; 9201 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9202 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9203 PetscCall(VecScatterDestroy(&ctx)); 9204 PetscFunctionReturn(0); 9205 } 9206 9207 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[]) { 9208 const PetscInt Nc = uOff[1] - uOff[0]; 9209 PetscInt c; 9210 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9211 } 9212 9213 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) { 9214 DM dmc; 9215 PetscDS ds; 9216 Vec ones, locmass; 9217 IS cellIS; 9218 PetscFormKey key; 9219 PetscInt depth; 9220 9221 PetscFunctionBegin; 9222 PetscCall(DMClone(dm, &dmc)); 9223 PetscCall(DMCopyDisc(dm, dmc)); 9224 PetscCall(DMGetDS(dmc, &ds)); 9225 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9226 PetscCall(DMCreateGlobalVector(dmc, mass)); 9227 PetscCall(DMGetLocalVector(dmc, &ones)); 9228 PetscCall(DMGetLocalVector(dmc, &locmass)); 9229 PetscCall(DMPlexGetDepth(dmc, &depth)); 9230 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9231 PetscCall(VecSet(locmass, 0.0)); 9232 PetscCall(VecSet(ones, 1.0)); 9233 key.label = NULL; 9234 key.value = 0; 9235 key.field = 0; 9236 key.part = 0; 9237 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9238 PetscCall(ISDestroy(&cellIS)); 9239 PetscCall(VecSet(*mass, 0.0)); 9240 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9241 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9242 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9243 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9244 PetscCall(DMDestroy(&dmc)); 9245 PetscFunctionReturn(0); 9246 } 9247 9248 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) { 9249 PetscSection gsc, gsf; 9250 PetscInt m, n; 9251 void *ctx; 9252 DM cdm; 9253 PetscBool regular; 9254 9255 PetscFunctionBegin; 9256 if (dmFine == dmCoarse) { 9257 DM dmc; 9258 PetscDS ds; 9259 PetscWeakForm wf; 9260 Vec u; 9261 IS cellIS; 9262 PetscFormKey key; 9263 PetscInt depth; 9264 9265 PetscCall(DMClone(dmFine, &dmc)); 9266 PetscCall(DMCopyDisc(dmFine, dmc)); 9267 PetscCall(DMGetDS(dmc, &ds)); 9268 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9269 PetscCall(PetscWeakFormClear(wf)); 9270 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9271 PetscCall(DMCreateMatrix(dmc, mass)); 9272 PetscCall(DMGetLocalVector(dmc, &u)); 9273 PetscCall(DMPlexGetDepth(dmc, &depth)); 9274 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9275 PetscCall(MatZeroEntries(*mass)); 9276 key.label = NULL; 9277 key.value = 0; 9278 key.field = 0; 9279 key.part = 0; 9280 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9281 PetscCall(ISDestroy(&cellIS)); 9282 PetscCall(DMRestoreLocalVector(dmc, &u)); 9283 PetscCall(DMDestroy(&dmc)); 9284 } else { 9285 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9286 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9287 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9288 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9289 9290 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9291 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9292 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9293 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9294 9295 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9296 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9297 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9298 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9299 } 9300 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9301 PetscFunctionReturn(0); 9302 } 9303 9304 /*@ 9305 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9306 9307 Input Parameter: 9308 . dm - The DMPlex object 9309 9310 Output Parameter: 9311 . regular - The flag 9312 9313 Level: intermediate 9314 9315 .seealso: `DMPlexSetRegularRefinement()` 9316 @*/ 9317 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) { 9318 PetscFunctionBegin; 9319 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9320 PetscValidBoolPointer(regular, 2); 9321 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9322 PetscFunctionReturn(0); 9323 } 9324 9325 /*@ 9326 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9327 9328 Input Parameters: 9329 + dm - The DMPlex object 9330 - regular - The flag 9331 9332 Level: intermediate 9333 9334 .seealso: `DMPlexGetRegularRefinement()` 9335 @*/ 9336 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) { 9337 PetscFunctionBegin; 9338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9339 ((DM_Plex *)dm->data)->regularRefinement = regular; 9340 PetscFunctionReturn(0); 9341 } 9342 9343 /* anchors */ 9344 /*@ 9345 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9346 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9347 9348 not collective 9349 9350 Input Parameter: 9351 . dm - The DMPlex object 9352 9353 Output Parameters: 9354 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9355 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9356 9357 Level: intermediate 9358 9359 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9360 @*/ 9361 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) { 9362 DM_Plex *plex = (DM_Plex *)dm->data; 9363 9364 PetscFunctionBegin; 9365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9366 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9367 if (anchorSection) *anchorSection = plex->anchorSection; 9368 if (anchorIS) *anchorIS = plex->anchorIS; 9369 PetscFunctionReturn(0); 9370 } 9371 9372 /*@ 9373 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9374 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9375 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9376 9377 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9378 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9379 9380 collective on dm 9381 9382 Input Parameters: 9383 + dm - The DMPlex object 9384 . 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). 9385 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9386 9387 The reference counts of anchorSection and anchorIS are incremented. 9388 9389 Level: intermediate 9390 9391 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9392 @*/ 9393 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) { 9394 DM_Plex *plex = (DM_Plex *)dm->data; 9395 PetscMPIInt result; 9396 9397 PetscFunctionBegin; 9398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9399 if (anchorSection) { 9400 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9401 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9402 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9403 } 9404 if (anchorIS) { 9405 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9406 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9407 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9408 } 9409 9410 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9411 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9412 plex->anchorSection = anchorSection; 9413 9414 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9415 PetscCall(ISDestroy(&plex->anchorIS)); 9416 plex->anchorIS = anchorIS; 9417 9418 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9419 PetscInt size, a, pStart, pEnd; 9420 const PetscInt *anchors; 9421 9422 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9423 PetscCall(ISGetLocalSize(anchorIS, &size)); 9424 PetscCall(ISGetIndices(anchorIS, &anchors)); 9425 for (a = 0; a < size; a++) { 9426 PetscInt p; 9427 9428 p = anchors[a]; 9429 if (p >= pStart && p < pEnd) { 9430 PetscInt dof; 9431 9432 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9433 if (dof) { 9434 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9435 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9436 } 9437 } 9438 } 9439 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9440 } 9441 /* reset the generic constraints */ 9442 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9443 PetscFunctionReturn(0); 9444 } 9445 9446 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) { 9447 PetscSection anchorSection; 9448 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9449 9450 PetscFunctionBegin; 9451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9452 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9453 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9454 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9455 if (numFields) { 9456 PetscInt f; 9457 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9458 9459 for (f = 0; f < numFields; f++) { 9460 PetscInt numComp; 9461 9462 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9463 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9464 } 9465 } 9466 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9467 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9468 pStart = PetscMax(pStart, sStart); 9469 pEnd = PetscMin(pEnd, sEnd); 9470 pEnd = PetscMax(pStart, pEnd); 9471 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9472 for (p = pStart; p < pEnd; p++) { 9473 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9474 if (dof) { 9475 PetscCall(PetscSectionGetDof(section, p, &dof)); 9476 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9477 for (f = 0; f < numFields; f++) { 9478 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9479 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9480 } 9481 } 9482 } 9483 PetscCall(PetscSectionSetUp(*cSec)); 9484 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9485 PetscFunctionReturn(0); 9486 } 9487 9488 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) { 9489 PetscSection aSec; 9490 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9491 const PetscInt *anchors; 9492 PetscInt numFields, f; 9493 IS aIS; 9494 MatType mtype; 9495 PetscBool iscuda, iskokkos; 9496 9497 PetscFunctionBegin; 9498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9499 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9500 PetscCall(PetscSectionGetStorageSize(section, &n)); 9501 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9502 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9503 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9504 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9505 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9506 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9507 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9508 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9509 else mtype = MATSEQAIJ; 9510 PetscCall(MatSetType(*cMat, mtype)); 9511 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9512 PetscCall(ISGetIndices(aIS, &anchors)); 9513 /* cSec will be a subset of aSec and section */ 9514 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9515 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9516 PetscCall(PetscMalloc1(m + 1, &i)); 9517 i[0] = 0; 9518 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9519 for (p = pStart; p < pEnd; p++) { 9520 PetscInt rDof, rOff, r; 9521 9522 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9523 if (!rDof) continue; 9524 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9525 if (numFields) { 9526 for (f = 0; f < numFields; f++) { 9527 annz = 0; 9528 for (r = 0; r < rDof; r++) { 9529 a = anchors[rOff + r]; 9530 if (a < sStart || a >= sEnd) continue; 9531 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9532 annz += aDof; 9533 } 9534 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9535 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9536 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9537 } 9538 } else { 9539 annz = 0; 9540 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9541 for (q = 0; q < dof; q++) { 9542 a = anchors[rOff + q]; 9543 if (a < sStart || a >= sEnd) continue; 9544 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9545 annz += aDof; 9546 } 9547 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9548 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9549 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9550 } 9551 } 9552 nnz = i[m]; 9553 PetscCall(PetscMalloc1(nnz, &j)); 9554 offset = 0; 9555 for (p = pStart; p < pEnd; p++) { 9556 if (numFields) { 9557 for (f = 0; f < numFields; f++) { 9558 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9559 for (q = 0; q < dof; q++) { 9560 PetscInt rDof, rOff, r; 9561 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9562 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9563 for (r = 0; r < rDof; r++) { 9564 PetscInt s; 9565 9566 a = anchors[rOff + r]; 9567 if (a < sStart || a >= sEnd) continue; 9568 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9569 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9570 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9571 } 9572 } 9573 } 9574 } else { 9575 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9576 for (q = 0; q < dof; q++) { 9577 PetscInt rDof, rOff, r; 9578 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9579 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9580 for (r = 0; r < rDof; r++) { 9581 PetscInt s; 9582 9583 a = anchors[rOff + r]; 9584 if (a < sStart || a >= sEnd) continue; 9585 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9586 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9587 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9588 } 9589 } 9590 } 9591 } 9592 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9593 PetscCall(PetscFree(i)); 9594 PetscCall(PetscFree(j)); 9595 PetscCall(ISRestoreIndices(aIS, &anchors)); 9596 PetscFunctionReturn(0); 9597 } 9598 9599 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) { 9600 DM_Plex *plex = (DM_Plex *)dm->data; 9601 PetscSection anchorSection, section, cSec; 9602 Mat cMat; 9603 9604 PetscFunctionBegin; 9605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9606 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9607 if (anchorSection) { 9608 PetscInt Nf; 9609 9610 PetscCall(DMGetLocalSection(dm, §ion)); 9611 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9612 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9613 PetscCall(DMGetNumFields(dm, &Nf)); 9614 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9615 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9616 PetscCall(PetscSectionDestroy(&cSec)); 9617 PetscCall(MatDestroy(&cMat)); 9618 } 9619 PetscFunctionReturn(0); 9620 } 9621 9622 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) { 9623 IS subis; 9624 PetscSection section, subsection; 9625 9626 PetscFunctionBegin; 9627 PetscCall(DMGetLocalSection(dm, §ion)); 9628 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9629 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9630 /* Create subdomain */ 9631 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9632 /* Create submodel */ 9633 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9634 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9635 PetscCall(DMSetLocalSection(*subdm, subsection)); 9636 PetscCall(PetscSectionDestroy(&subsection)); 9637 PetscCall(DMCopyDisc(dm, *subdm)); 9638 /* Create map from submodel to global model */ 9639 if (is) { 9640 PetscSection sectionGlobal, subsectionGlobal; 9641 IS spIS; 9642 const PetscInt *spmap; 9643 PetscInt *subIndices; 9644 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9645 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9646 9647 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9648 PetscCall(ISGetIndices(spIS, &spmap)); 9649 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9650 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9651 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9652 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9653 for (p = pStart; p < pEnd; ++p) { 9654 PetscInt gdof, pSubSize = 0; 9655 9656 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9657 if (gdof > 0) { 9658 for (f = 0; f < Nf; ++f) { 9659 PetscInt fdof, fcdof; 9660 9661 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9662 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9663 pSubSize += fdof - fcdof; 9664 } 9665 subSize += pSubSize; 9666 if (pSubSize) { 9667 if (bs < 0) { 9668 bs = pSubSize; 9669 } else if (bs != pSubSize) { 9670 /* Layout does not admit a pointwise block size */ 9671 bs = 1; 9672 } 9673 } 9674 } 9675 } 9676 /* Must have same blocksize on all procs (some might have no points) */ 9677 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9678 bsLocal[1] = bs; 9679 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9680 if (bsMinMax[0] != bsMinMax[1]) { 9681 bs = 1; 9682 } else { 9683 bs = bsMinMax[0]; 9684 } 9685 PetscCall(PetscMalloc1(subSize, &subIndices)); 9686 for (p = pStart; p < pEnd; ++p) { 9687 PetscInt gdof, goff; 9688 9689 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9690 if (gdof > 0) { 9691 const PetscInt point = spmap[p]; 9692 9693 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9694 for (f = 0; f < Nf; ++f) { 9695 PetscInt fdof, fcdof, fc, f2, poff = 0; 9696 9697 /* Can get rid of this loop by storing field information in the global section */ 9698 for (f2 = 0; f2 < f; ++f2) { 9699 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9700 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9701 poff += fdof - fcdof; 9702 } 9703 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9704 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9705 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 9706 } 9707 } 9708 } 9709 PetscCall(ISRestoreIndices(spIS, &spmap)); 9710 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9711 if (bs > 1) { 9712 /* We need to check that the block size does not come from non-contiguous fields */ 9713 PetscInt i, j, set = 1; 9714 for (i = 0; i < subSize; i += bs) { 9715 for (j = 0; j < bs; ++j) { 9716 if (subIndices[i + j] != subIndices[i] + j) { 9717 set = 0; 9718 break; 9719 } 9720 } 9721 } 9722 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9723 } 9724 /* Attach nullspace */ 9725 for (f = 0; f < Nf; ++f) { 9726 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9727 if ((*subdm)->nullspaceConstructors[f]) break; 9728 } 9729 if (f < Nf) { 9730 MatNullSpace nullSpace; 9731 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9732 9733 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9734 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9735 } 9736 } 9737 PetscFunctionReturn(0); 9738 } 9739 9740 /*@ 9741 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9742 9743 Input Parameter: 9744 - dm - The DM 9745 9746 Level: developer 9747 9748 Options Database Keys: 9749 . -dm_plex_monitor_throughput - Activate the monitor 9750 9751 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9752 @*/ 9753 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) { 9754 #if defined(PETSC_USE_LOG) 9755 PetscStageLog stageLog; 9756 PetscLogEvent event; 9757 PetscLogStage stage; 9758 PetscEventPerfInfo eventInfo; 9759 PetscReal cellRate, flopRate; 9760 PetscInt cStart, cEnd, Nf, N; 9761 const char *name; 9762 #endif 9763 9764 PetscFunctionBegin; 9765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9766 #if defined(PETSC_USE_LOG) 9767 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 9768 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9769 PetscCall(DMGetNumFields(dm, &Nf)); 9770 PetscCall(PetscLogGetStageLog(&stageLog)); 9771 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9772 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9773 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9774 N = (cEnd - cStart) * Nf * eventInfo.count; 9775 flopRate = eventInfo.flops / eventInfo.time; 9776 cellRate = N / eventInfo.time; 9777 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))); 9778 #else 9779 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9780 #endif 9781 PetscFunctionReturn(0); 9782 } 9783