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