1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) { 35 DMPolytopeType ct; 36 PetscInt cStart, cEnd; 37 38 PetscFunctionBegin; 39 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 40 if (cEnd <= cStart) { 41 *simplex = PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 45 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 46 PetscFunctionReturn(0); 47 } 48 49 /*@ 50 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 51 52 Input Parameters: 53 + dm - The DMPlex object 54 - height - The cell height in the Plex, 0 is the default 55 56 Output Parameters: 57 + cStart - The first "normal" cell 58 - cEnd - The upper bound on "normal"" cells 59 60 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 61 62 Level: developer 63 64 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 65 @*/ 66 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) { 67 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 68 PetscInt cS, cE, c; 69 70 PetscFunctionBegin; 71 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 72 for (c = cS; c < cE; ++c) { 73 DMPolytopeType cct; 74 75 PetscCall(DMPlexGetCellType(dm, c, &cct)); 76 if ((PetscInt)cct < 0) break; 77 switch (cct) { 78 case DM_POLYTOPE_POINT: 79 case DM_POLYTOPE_SEGMENT: 80 case DM_POLYTOPE_TRIANGLE: 81 case DM_POLYTOPE_QUADRILATERAL: 82 case DM_POLYTOPE_TETRAHEDRON: 83 case DM_POLYTOPE_HEXAHEDRON: ct = cct; break; 84 default: break; 85 } 86 if (ct != DM_POLYTOPE_UNKNOWN) break; 87 } 88 if (ct != DM_POLYTOPE_UNKNOWN) { 89 DMLabel ctLabel; 90 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 93 // Reset label for fast lookup 94 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 95 } 96 if (cStart) *cStart = cS; 97 if (cEnd) *cEnd = cE; 98 PetscFunctionReturn(0); 99 } 100 101 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) { 102 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 103 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 104 105 PetscFunctionBegin; 106 *ft = PETSC_VTK_INVALID; 107 PetscCall(DMGetCoordinateDim(dm, &cdim)); 108 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 109 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 110 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 111 if (field >= 0) { 112 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 113 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 114 } else { 115 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 116 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 117 } 118 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 119 if (globalvcdof[0]) { 120 *sStart = vStart; 121 *sEnd = vEnd; 122 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 123 else *ft = PETSC_VTK_POINT_FIELD; 124 } else if (globalvcdof[1]) { 125 *sStart = cStart; 126 *sEnd = cEnd; 127 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 128 else *ft = PETSC_VTK_CELL_FIELD; 129 } else { 130 if (field >= 0) { 131 const char *fieldname; 132 133 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 134 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 135 } else { 136 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 137 } 138 } 139 PetscFunctionReturn(0); 140 } 141 142 /*@ 143 DMPlexVecView1D - Plot many 1D solutions on the same line graph 144 145 Collective on dm 146 147 Input Parameters: 148 + dm - The DMPlex 149 . n - The number of vectors 150 . u - The array of local vectors 151 - viewer - The Draw viewer 152 153 Level: advanced 154 155 .seealso: `VecViewFromOptions()`, `VecView()` 156 @*/ 157 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) { 158 PetscDS ds; 159 PetscDraw draw = NULL; 160 PetscDrawLG lg; 161 Vec coordinates; 162 const PetscScalar *coords, **sol; 163 PetscReal *vals; 164 PetscInt *Nc; 165 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 166 char **names; 167 168 PetscFunctionBegin; 169 PetscCall(DMGetDS(dm, &ds)); 170 PetscCall(PetscDSGetNumFields(ds, &Nf)); 171 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 172 PetscCall(PetscDSGetComponents(ds, &Nc)); 173 174 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 175 if (!draw) PetscFunctionReturn(0); 176 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 177 178 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 179 for (i = 0, l = 0; i < n; ++i) { 180 const char *vname; 181 182 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 183 for (f = 0; f < Nf; ++f) { 184 PetscObject disc; 185 const char *fname; 186 char tmpname[PETSC_MAX_PATH_LEN]; 187 188 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 189 /* TODO Create names for components */ 190 for (c = 0; c < Nc[f]; ++c, ++l) { 191 PetscCall(PetscObjectGetName(disc, &fname)); 192 PetscCall(PetscStrcpy(tmpname, vname)); 193 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 195 PetscCall(PetscStrallocpy(tmpname, &names[l])); 196 } 197 } 198 } 199 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 200 /* Just add P_1 support for now */ 201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 202 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 203 PetscCall(VecGetArrayRead(coordinates, &coords)); 204 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 205 for (v = vStart; v < vEnd; ++v) { 206 PetscScalar *x, *svals; 207 208 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 209 for (i = 0; i < n; ++i) { 210 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 211 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 212 } 213 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 214 } 215 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 216 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 217 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 218 PetscCall(PetscFree3(sol, names, vals)); 219 220 PetscCall(PetscDrawLGDraw(lg)); 221 PetscCall(PetscDrawLGDestroy(&lg)); 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) { 235 DM dm; 236 PetscSection s; 237 PetscDraw draw, popup; 238 DM cdm; 239 PetscSection coordSection; 240 Vec coordinates; 241 const PetscScalar *coords, *array; 242 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 243 PetscReal vbound[2], time; 244 PetscBool flg; 245 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 246 const char *name; 247 char title[PETSC_MAX_PATH_LEN]; 248 249 PetscFunctionBegin; 250 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 251 PetscCall(VecGetDM(v, &dm)); 252 PetscCall(DMGetCoordinateDim(dm, &dim)); 253 PetscCall(DMGetLocalSection(dm, &s)); 254 PetscCall(PetscSectionGetNumFields(s, &Nf)); 255 PetscCall(DMGetCoarsenLevel(dm, &level)); 256 PetscCall(DMGetCoordinateDM(dm, &cdm)); 257 PetscCall(DMGetLocalSection(cdm, &coordSection)); 258 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 259 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 260 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 261 262 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 263 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 264 265 PetscCall(VecGetLocalSize(coordinates, &N)); 266 PetscCall(VecGetArrayRead(coordinates, &coords)); 267 for (c = 0; c < N; c += dim) { 268 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 269 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 271 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 272 } 273 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 274 PetscCall(PetscDrawClear(draw)); 275 276 /* Could implement something like DMDASelectFields() */ 277 for (f = 0; f < Nf; ++f) { 278 DM fdm = dm; 279 Vec fv = v; 280 IS fis; 281 char prefix[PETSC_MAX_PATH_LEN]; 282 const char *fname; 283 284 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 285 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 286 287 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 288 else prefix[0] = '\0'; 289 if (Nf > 1) { 290 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 291 PetscCall(VecGetSubVector(v, fis, &fv)); 292 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 293 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 294 } 295 for (comp = 0; comp < Nc; ++comp, ++w) { 296 PetscInt nmax = 2; 297 298 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 299 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 300 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 301 PetscCall(PetscDrawSetTitle(draw, title)); 302 303 /* TODO Get max and min only for this component */ 304 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 305 if (!flg) { 306 PetscCall(VecMin(fv, NULL, &vbound[0])); 307 PetscCall(VecMax(fv, NULL, &vbound[1])); 308 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 309 } 310 PetscCall(PetscDrawGetPopup(draw, &popup)); 311 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 312 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 313 314 PetscCall(VecGetArrayRead(fv, &array)); 315 for (c = cStart; c < cEnd; ++c) { 316 PetscScalar *coords = NULL, *a = NULL; 317 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 318 319 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 320 if (a) { 321 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 322 color[1] = color[2] = color[3] = color[0]; 323 } else { 324 PetscScalar *vals = NULL; 325 PetscInt numVals, va; 326 327 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 328 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 329 switch (numVals / Nc) { 330 case 3: /* P1 Triangle */ 331 case 4: /* P1 Quadrangle */ 332 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 333 break; 334 case 6: /* P2 Triangle */ 335 case 8: /* P2 Quadrangle */ 336 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 337 break; 338 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 339 } 340 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 341 } 342 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 343 switch (numCoords) { 344 case 6: 345 case 12: /* Localized triangle */ 346 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 347 break; 348 case 8: 349 case 16: /* Localized quadrilateral */ 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 351 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 352 break; 353 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 354 } 355 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 356 } 357 PetscCall(VecRestoreArrayRead(fv, &array)); 358 PetscCall(PetscDrawFlush(draw)); 359 PetscCall(PetscDrawPause(draw)); 360 PetscCall(PetscDrawSave(draw)); 361 } 362 if (Nf > 1) { 363 PetscCall(VecRestoreSubVector(v, fis, &fv)); 364 PetscCall(ISDestroy(&fis)); 365 PetscCall(DMDestroy(&fdm)); 366 } 367 } 368 PetscFunctionReturn(0); 369 } 370 371 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); break; 387 default: SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) { 393 DM dm; 394 Vec locv; 395 const char *name; 396 PetscSection section; 397 PetscInt pStart, pEnd; 398 PetscInt numFields; 399 PetscViewerVTKFieldType ft; 400 401 PetscFunctionBegin; 402 PetscCall(VecGetDM(v, &dm)); 403 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 404 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 405 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 406 PetscCall(VecCopy(v, locv)); 407 PetscCall(DMGetLocalSection(dm, §ion)); 408 PetscCall(PetscSectionGetNumFields(section, &numFields)); 409 if (!numFields) { 410 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 411 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 412 } else { 413 PetscInt f; 414 415 for (f = 0; f < numFields; f++) { 416 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 417 if (ft == PETSC_VTK_INVALID) continue; 418 PetscCall(PetscObjectReference((PetscObject)locv)); 419 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 420 } 421 PetscCall(VecDestroy(&locv)); 422 } 423 PetscFunctionReturn(0); 424 } 425 426 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) { 427 DM dm; 428 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 429 430 PetscFunctionBegin; 431 PetscCall(VecGetDM(v, &dm)); 432 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 433 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 434 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 437 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 438 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 439 PetscInt i, numFields; 440 PetscObject fe; 441 PetscBool fem = PETSC_FALSE; 442 Vec locv = v; 443 const char *name; 444 PetscInt step; 445 PetscReal time; 446 447 PetscCall(DMGetNumFields(dm, &numFields)); 448 for (i = 0; i < numFields; i++) { 449 PetscCall(DMGetField(dm, i, NULL, &fe)); 450 if (fe->classid == PETSCFE_CLASSID) { 451 fem = PETSC_TRUE; 452 break; 453 } 454 } 455 if (fem) { 456 PetscObject isZero; 457 458 PetscCall(DMGetLocalVector(dm, &locv)); 459 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 460 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 461 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 462 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 463 PetscCall(VecCopy(v, locv)); 464 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 465 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 466 } 467 if (isvtk) { 468 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 469 } else if (ishdf5) { 470 #if defined(PETSC_HAVE_HDF5) 471 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 472 #else 473 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 474 #endif 475 } else if (isdraw) { 476 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 477 } else if (isglvis) { 478 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 479 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 480 PetscCall(VecView_GLVis(locv, viewer)); 481 } else if (iscgns) { 482 #if defined(PETSC_HAVE_CGNS) 483 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 484 #else 485 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 486 #endif 487 } 488 if (fem) { 489 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 490 PetscCall(DMRestoreLocalVector(dm, &locv)); 491 } 492 } else { 493 PetscBool isseq; 494 495 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 496 if (isseq) PetscCall(VecView_Seq(v, viewer)); 497 else PetscCall(VecView_MPI(v, viewer)); 498 } 499 PetscFunctionReturn(0); 500 } 501 502 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) { 503 DM dm; 504 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 505 506 PetscFunctionBegin; 507 PetscCall(VecGetDM(v, &dm)); 508 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 509 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 510 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 511 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 512 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 513 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 514 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 515 if (isvtk || isdraw || isglvis || iscgns) { 516 Vec locv; 517 PetscObject isZero; 518 const char *name; 519 520 PetscCall(DMGetLocalVector(dm, &locv)); 521 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 522 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 523 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 524 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 525 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 526 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 527 PetscCall(VecView_Plex_Local(locv, viewer)); 528 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 529 PetscCall(DMRestoreLocalVector(dm, &locv)); 530 } else if (ishdf5) { 531 #if defined(PETSC_HAVE_HDF5) 532 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 533 #else 534 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 535 #endif 536 } else if (isexodusii) { 537 #if defined(PETSC_HAVE_EXODUSII) 538 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 539 #else 540 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 541 #endif 542 } else { 543 PetscBool isseq; 544 545 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 546 if (isseq) PetscCall(VecView_Seq(v, viewer)); 547 else PetscCall(VecView_MPI(v, viewer)); 548 } 549 PetscFunctionReturn(0); 550 } 551 552 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) { 553 DM dm; 554 MPI_Comm comm; 555 PetscViewerFormat format; 556 Vec v; 557 PetscBool isvtk, ishdf5; 558 559 PetscFunctionBegin; 560 PetscCall(VecGetDM(originalv, &dm)); 561 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 562 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 563 PetscCall(PetscViewerGetFormat(viewer, &format)); 564 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 565 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 566 if (format == PETSC_VIEWER_NATIVE) { 567 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 568 /* this need a better fix */ 569 if (dm->useNatural) { 570 if (dm->sfNatural) { 571 const char *vecname; 572 PetscInt n, nroots; 573 574 PetscCall(VecGetLocalSize(originalv, &n)); 575 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 576 if (n == nroots) { 577 PetscCall(DMGetGlobalVector(dm, &v)); 578 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 579 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 580 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 581 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 582 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 583 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 584 } else v = originalv; 585 } else v = originalv; 586 587 if (ishdf5) { 588 #if defined(PETSC_HAVE_HDF5) 589 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 590 #else 591 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 592 #endif 593 } else if (isvtk) { 594 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 595 } else { 596 PetscBool isseq; 597 598 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 599 if (isseq) PetscCall(VecView_Seq(v, viewer)); 600 else PetscCall(VecView_MPI(v, viewer)); 601 } 602 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 603 PetscFunctionReturn(0); 604 } 605 606 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) { 607 DM dm; 608 PetscBool ishdf5; 609 610 PetscFunctionBegin; 611 PetscCall(VecGetDM(v, &dm)); 612 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 613 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 614 if (ishdf5) { 615 DM dmBC; 616 Vec gv; 617 const char *name; 618 619 PetscCall(DMGetOutputDM(dm, &dmBC)); 620 PetscCall(DMGetGlobalVector(dmBC, &gv)); 621 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 622 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 623 PetscCall(VecLoad_Default(gv, viewer)); 624 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 625 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 626 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 627 } else PetscCall(VecLoad_Default(v, viewer)); 628 PetscFunctionReturn(0); 629 } 630 631 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) { 632 DM dm; 633 PetscBool ishdf5, isexodusii; 634 635 PetscFunctionBegin; 636 PetscCall(VecGetDM(v, &dm)); 637 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (ishdf5) { 641 #if defined(PETSC_HAVE_HDF5) 642 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 643 #else 644 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 645 #endif 646 } else if (isexodusii) { 647 #if defined(PETSC_HAVE_EXODUSII) 648 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 649 #else 650 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 651 #endif 652 } else PetscCall(VecLoad_Default(v, viewer)); 653 PetscFunctionReturn(0); 654 } 655 656 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else PetscCall(VecLoad_Default(originalv, viewer)); 687 } 688 PetscFunctionReturn(0); 689 } 690 691 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) { 692 PetscSection coordSection; 693 Vec coordinates; 694 DMLabel depthLabel, celltypeLabel; 695 const char *name[4]; 696 const PetscScalar *a; 697 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 698 699 PetscFunctionBegin; 700 PetscCall(DMGetDimension(dm, &dim)); 701 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 702 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 703 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 704 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 705 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 706 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 707 PetscCall(VecGetArrayRead(coordinates, &a)); 708 name[0] = "vertex"; 709 name[1] = "edge"; 710 name[dim - 1] = "face"; 711 name[dim] = "cell"; 712 for (c = cStart; c < cEnd; ++c) { 713 PetscInt *closure = NULL; 714 PetscInt closureSize, cl, ct; 715 716 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 717 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 718 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 719 PetscCall(PetscViewerASCIIPushTab(viewer)); 720 for (cl = 0; cl < closureSize * 2; cl += 2) { 721 PetscInt point = closure[cl], depth, dof, off, d, p; 722 723 if ((point < pStart) || (point >= pEnd)) continue; 724 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 725 if (!dof) continue; 726 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 727 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 728 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 729 for (p = 0; p < dof / dim; ++p) { 730 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 731 for (d = 0; d < dim; ++d) { 732 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 733 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 734 } 735 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 736 } 737 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 738 } 739 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 740 PetscCall(PetscViewerASCIIPopTab(viewer)); 741 } 742 PetscCall(VecRestoreArrayRead(coordinates, &a)); 743 PetscFunctionReturn(0); 744 } 745 746 typedef enum { 747 CS_CARTESIAN, 748 CS_POLAR, 749 CS_CYLINDRICAL, 750 CS_SPHERICAL 751 } CoordSystem; 752 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 753 754 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) { 755 PetscInt i; 756 757 PetscFunctionBegin; 758 if (dim > 3) { 759 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 760 } else { 761 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 762 763 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 764 switch (cs) { 765 case CS_CARTESIAN: 766 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 767 break; 768 case CS_POLAR: 769 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 770 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 771 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 772 break; 773 case CS_CYLINDRICAL: 774 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 775 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 776 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 777 trcoords[2] = coords[2]; 778 break; 779 case CS_SPHERICAL: 780 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 781 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 782 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 783 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 784 break; 785 } 786 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 787 } 788 PetscFunctionReturn(0); 789 } 790 791 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) { 792 DM_Plex *mesh = (DM_Plex *)dm->data; 793 DM cdm, cdmCell; 794 PetscSection coordSection, coordSectionCell; 795 Vec coordinates, coordinatesCell; 796 PetscViewerFormat format; 797 798 PetscFunctionBegin; 799 PetscCall(DMGetCoordinateDM(dm, &cdm)); 800 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 801 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 802 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 803 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 804 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 805 PetscCall(PetscViewerGetFormat(viewer, &format)); 806 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 807 const char *name; 808 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 809 PetscInt pStart, pEnd, p, numLabels, l; 810 PetscMPIInt rank, size; 811 812 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 813 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 814 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 815 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 816 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 817 PetscCall(DMGetDimension(dm, &dim)); 818 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 819 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 820 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 821 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 822 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 823 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 824 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 825 for (p = pStart; p < pEnd; ++p) { 826 PetscInt dof, off, s; 827 828 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 829 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 830 for (s = off; s < off + dof; ++s) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 831 } 832 PetscCall(PetscViewerFlush(viewer)); 833 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 834 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 835 for (p = pStart; p < pEnd; ++p) { 836 PetscInt dof, off, c; 837 838 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 839 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 840 for (c = off; c < off + dof; ++c) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 841 } 842 PetscCall(PetscViewerFlush(viewer)); 843 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 844 if (coordSection && coordinates) { 845 CoordSystem cs = CS_CARTESIAN; 846 const PetscScalar *array, *arrayCell = NULL; 847 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 848 PetscMPIInt rank; 849 const char *name; 850 851 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 852 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 853 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 854 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 855 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 856 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 857 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 858 pStart = PetscMin(pvStart, pcStart); 859 pEnd = PetscMax(pvEnd, pcEnd); 860 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 863 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 864 865 PetscCall(VecGetArrayRead(coordinates, &array)); 866 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 867 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 868 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 869 for (p = pStart; p < pEnd; ++p) { 870 PetscInt dof, off; 871 872 if (p >= pvStart && p < pvEnd) { 873 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 874 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 875 if (dof) { 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 877 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 878 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 879 } 880 } 881 if (cdmCell && p >= pcStart && p < pcEnd) { 882 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 883 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 884 if (dof) { 885 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 886 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 887 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 888 } 889 } 890 } 891 PetscCall(PetscViewerFlush(viewer)); 892 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 893 PetscCall(VecRestoreArrayRead(coordinates, &array)); 894 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 895 } 896 PetscCall(DMGetNumLabels(dm, &numLabels)); 897 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 898 for (l = 0; l < numLabels; ++l) { 899 DMLabel label; 900 PetscBool isdepth; 901 const char *name; 902 903 PetscCall(DMGetLabelName(dm, l, &name)); 904 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 905 if (isdepth) continue; 906 PetscCall(DMGetLabel(dm, name, &label)); 907 PetscCall(DMLabelView(label, viewer)); 908 } 909 if (size > 1) { 910 PetscSF sf; 911 912 PetscCall(DMGetPointSF(dm, &sf)); 913 PetscCall(PetscSFView(sf, viewer)); 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 917 const char *name, *color; 918 const char *defcolors[3] = {"gray", "orange", "green"}; 919 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 920 char lname[PETSC_MAX_PATH_LEN]; 921 PetscReal scale = 2.0; 922 PetscReal tikzscale = 1.0; 923 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 924 double tcoords[3]; 925 PetscScalar *coords; 926 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 927 PetscMPIInt rank, size; 928 char **names, **colors, **lcolors; 929 PetscBool flg, lflg; 930 PetscBT wp = NULL; 931 PetscInt pEnd, pStart; 932 933 PetscCall(DMGetDimension(dm, &dim)); 934 PetscCall(DMPlexGetDepth(dm, &depth)); 935 PetscCall(DMGetNumLabels(dm, &numLabels)); 936 numLabels = PetscMax(numLabels, 10); 937 numColors = 10; 938 numLColors = 10; 939 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 940 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 941 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 942 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 943 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 944 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 945 n = 4; 946 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 947 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 948 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 949 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 950 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 951 if (!useLabels) numLabels = 0; 952 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 953 if (!useColors) { 954 numColors = 3; 955 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 956 } 957 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 958 if (!useColors) { 959 numLColors = 4; 960 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 961 } 962 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 963 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 964 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 965 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 966 if (depth < dim) plotEdges = PETSC_FALSE; 967 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 968 969 /* filter points with labelvalue != labeldefaultvalue */ 970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 971 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 972 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 973 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 974 if (lflg) { 975 DMLabel lbl; 976 977 PetscCall(DMGetLabel(dm, lname, &lbl)); 978 if (lbl) { 979 PetscInt val, defval; 980 981 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 982 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 983 for (c = pStart; c < pEnd; c++) { 984 PetscInt *closure = NULL; 985 PetscInt closureSize; 986 987 PetscCall(DMLabelGetValue(lbl, c, &val)); 988 if (val == defval) continue; 989 990 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 for (p = 0; p < closureSize * 2; p += 2) PetscCall(PetscBTSet(wp, closure[p] - pStart)); 992 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 993 } 994 } 995 } 996 997 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 998 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 999 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1001 \\documentclass[tikz]{standalone}\n\n\ 1002 \\usepackage{pgflibraryshapes}\n\ 1003 \\usetikzlibrary{backgrounds}\n\ 1004 \\usetikzlibrary{arrows}\n\ 1005 \\begin{document}\n")); 1006 if (size > 1) { 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1008 for (p = 0; p < size; ++p) { 1009 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1011 } 1012 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1013 } 1014 if (drawHasse) { 1015 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1016 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1018 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1029 } 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1031 1032 /* Plot vertices */ 1033 PetscCall(VecGetArray(coordinates, &coords)); 1034 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1035 for (v = vStart; v < vEnd; ++v) { 1036 PetscInt off, dof, d; 1037 PetscBool isLabeled = PETSC_FALSE; 1038 1039 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1040 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1041 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1042 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1043 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1044 for (d = 0; d < dof; ++d) { 1045 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1046 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1047 } 1048 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1049 if (dim == 3) { 1050 PetscReal tmp = tcoords[1]; 1051 tcoords[1] = tcoords[2]; 1052 tcoords[2] = -tmp; 1053 } 1054 for (d = 0; d < dof; ++d) { 1055 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1056 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1057 } 1058 if (drawHasse) color = colors[0 % numColors]; 1059 else color = colors[rank % numColors]; 1060 for (l = 0; l < numLabels; ++l) { 1061 PetscInt val; 1062 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1063 if (val >= 0) { 1064 color = lcolors[l % numLColors]; 1065 isLabeled = PETSC_TRUE; 1066 break; 1067 } 1068 } 1069 if (drawNumbers[0]) { 1070 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1071 } else if (drawColors[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1073 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1074 } 1075 PetscCall(VecRestoreArray(coordinates, &coords)); 1076 PetscCall(PetscViewerFlush(viewer)); 1077 /* Plot edges */ 1078 if (plotEdges) { 1079 PetscCall(VecGetArray(coordinates, &coords)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1081 for (e = eStart; e < eEnd; ++e) { 1082 const PetscInt *cone; 1083 PetscInt coneSize, offA, offB, dof, d; 1084 1085 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1086 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1087 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1088 PetscCall(DMPlexGetCone(dm, e, &cone)); 1089 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1090 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1091 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1093 for (d = 0; d < dof; ++d) { 1094 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1095 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1096 } 1097 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1098 if (dim == 3) { 1099 PetscReal tmp = tcoords[1]; 1100 tcoords[1] = tcoords[2]; 1101 tcoords[2] = -tmp; 1102 } 1103 for (d = 0; d < dof; ++d) { 1104 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1106 } 1107 if (drawHasse) color = colors[1 % numColors]; 1108 else color = colors[rank % numColors]; 1109 for (l = 0; l < numLabels; ++l) { 1110 PetscInt val; 1111 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1112 if (val >= 0) { 1113 color = lcolors[l % numLColors]; 1114 break; 1115 } 1116 } 1117 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1118 } 1119 PetscCall(VecRestoreArray(coordinates, &coords)); 1120 PetscCall(PetscViewerFlush(viewer)); 1121 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1122 } 1123 /* Plot cells */ 1124 if (dim == 3 || !drawNumbers[1]) { 1125 for (e = eStart; e < eEnd; ++e) { 1126 const PetscInt *cone; 1127 1128 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1129 color = colors[rank % numColors]; 1130 for (l = 0; l < numLabels; ++l) { 1131 PetscInt val; 1132 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1133 if (val >= 0) { 1134 color = lcolors[l % numLColors]; 1135 break; 1136 } 1137 } 1138 PetscCall(DMPlexGetCone(dm, e, &cone)); 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1140 } 1141 } else { 1142 DMPolytopeType ct; 1143 1144 /* Drawing a 2D polygon */ 1145 for (c = cStart; c < cEnd; ++c) { 1146 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1147 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1148 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1149 const PetscInt *cone; 1150 PetscInt coneSize, e; 1151 1152 PetscCall(DMPlexGetCone(dm, c, &cone)); 1153 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1154 for (e = 0; e < coneSize; ++e) { 1155 const PetscInt *econe; 1156 1157 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1158 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1159 } 1160 } else { 1161 PetscInt *closure = NULL; 1162 PetscInt closureSize, Nv = 0, v; 1163 1164 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1165 for (p = 0; p < closureSize * 2; p += 2) { 1166 const PetscInt point = closure[p]; 1167 1168 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1169 } 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1171 for (v = 0; v <= Nv; ++v) { 1172 const PetscInt vertex = closure[v % Nv]; 1173 1174 if (v > 0) { 1175 if (plotEdges) { 1176 const PetscInt *edge; 1177 PetscInt endpoints[2], ne; 1178 1179 endpoints[0] = closure[v - 1]; 1180 endpoints[1] = vertex; 1181 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1182 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1183 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1184 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1185 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1186 } 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1188 } 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1190 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1191 } 1192 } 1193 } 1194 for (c = cStart; c < cEnd; ++c) { 1195 double ccoords[3] = {0.0, 0.0, 0.0}; 1196 PetscBool isLabeled = PETSC_FALSE; 1197 PetscScalar *cellCoords = NULL; 1198 const PetscScalar *array; 1199 PetscInt numCoords, cdim, d; 1200 PetscBool isDG; 1201 1202 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1203 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1204 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1205 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1207 for (p = 0; p < numCoords / cdim; ++p) { 1208 for (d = 0; d < cdim; ++d) { 1209 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1210 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1211 } 1212 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1213 if (cdim == 3) { 1214 PetscReal tmp = tcoords[1]; 1215 tcoords[1] = tcoords[2]; 1216 tcoords[2] = -tmp; 1217 } 1218 for (d = 0; d < dim; ++d) ccoords[d] += tcoords[d]; 1219 } 1220 for (d = 0; d < cdim; ++d) ccoords[d] /= (numCoords / cdim); 1221 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1222 for (d = 0; d < cdim; ++d) { 1223 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1224 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1225 } 1226 if (drawHasse) color = colors[depth % numColors]; 1227 else color = colors[rank % numColors]; 1228 for (l = 0; l < numLabels; ++l) { 1229 PetscInt val; 1230 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1231 if (val >= 0) { 1232 color = lcolors[l % numLColors]; 1233 isLabeled = PETSC_TRUE; 1234 break; 1235 } 1236 } 1237 if (drawNumbers[dim]) { 1238 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1239 } else if (drawColors[dim]) { 1240 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1241 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1242 } 1243 if (drawHasse) { 1244 color = colors[depth % numColors]; 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1250 1251 color = colors[1 % numColors]; 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1257 1258 color = colors[0 % numColors]; 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1264 1265 for (p = pStart; p < pEnd; ++p) { 1266 const PetscInt *cone; 1267 PetscInt coneSize, cp; 1268 1269 PetscCall(DMPlexGetCone(dm, p, &cone)); 1270 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1271 for (cp = 0; cp < coneSize; ++cp) PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1272 } 1273 } 1274 PetscCall(PetscViewerFlush(viewer)); 1275 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1278 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1279 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1280 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1281 PetscCall(PetscFree3(names, colors, lcolors)); 1282 PetscCall(PetscBTDestroy(&wp)); 1283 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1284 Vec cown, acown; 1285 VecScatter sct; 1286 ISLocalToGlobalMapping g2l; 1287 IS gid, acis; 1288 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1289 MPI_Group ggroup, ngroup; 1290 PetscScalar *array, nid; 1291 const PetscInt *idxs; 1292 PetscInt *idxs2, *start, *adjacency, *work; 1293 PetscInt64 lm[3], gm[3]; 1294 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1295 PetscMPIInt d1, d2, rank; 1296 1297 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1298 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1299 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1300 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1301 #endif 1302 if (ncomm != MPI_COMM_NULL) { 1303 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1304 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1305 d1 = 0; 1306 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1307 nid = d2; 1308 PetscCallMPI(MPI_Group_free(&ggroup)); 1309 PetscCallMPI(MPI_Group_free(&ngroup)); 1310 PetscCallMPI(MPI_Comm_free(&ncomm)); 1311 } else nid = 0.0; 1312 1313 /* Get connectivity */ 1314 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1315 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1316 1317 /* filter overlapped local cells */ 1318 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1319 PetscCall(ISGetIndices(gid, &idxs)); 1320 PetscCall(ISGetLocalSize(gid, &cum)); 1321 PetscCall(PetscMalloc1(cum, &idxs2)); 1322 for (c = cStart, cum = 0; c < cEnd; c++) { 1323 if (idxs[c - cStart] < 0) continue; 1324 idxs2[cum++] = idxs[c - cStart]; 1325 } 1326 PetscCall(ISRestoreIndices(gid, &idxs)); 1327 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1328 PetscCall(ISDestroy(&gid)); 1329 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1330 1331 /* support for node-aware cell locality */ 1332 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1333 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1334 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1335 PetscCall(VecGetArray(cown, &array)); 1336 for (c = 0; c < numVertices; c++) array[c] = nid; 1337 PetscCall(VecRestoreArray(cown, &array)); 1338 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1339 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1340 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1341 PetscCall(ISDestroy(&acis)); 1342 PetscCall(VecScatterDestroy(&sct)); 1343 PetscCall(VecDestroy(&cown)); 1344 1345 /* compute edgeCut */ 1346 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1347 PetscCall(PetscMalloc1(cum, &work)); 1348 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1349 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1350 PetscCall(ISDestroy(&gid)); 1351 PetscCall(VecGetArray(acown, &array)); 1352 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1353 PetscInt totl; 1354 1355 totl = start[c + 1] - start[c]; 1356 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1357 for (i = 0; i < totl; i++) { 1358 if (work[i] < 0) { 1359 ect += 1; 1360 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1361 } 1362 } 1363 } 1364 PetscCall(PetscFree(work)); 1365 PetscCall(VecRestoreArray(acown, &array)); 1366 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1367 lm[1] = -numVertices; 1368 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1369 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1370 lm[0] = ect; /* edgeCut */ 1371 lm[1] = ectn; /* node-aware edgeCut */ 1372 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1373 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1374 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1375 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1376 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1377 #else 1378 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1379 #endif 1380 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1381 PetscCall(PetscFree(start)); 1382 PetscCall(PetscFree(adjacency)); 1383 PetscCall(VecDestroy(&acown)); 1384 } else { 1385 const char *name; 1386 PetscInt *sizes, *hybsizes, *ghostsizes; 1387 PetscInt locDepth, depth, cellHeight, dim, d; 1388 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1389 PetscInt numLabels, l, maxSize = 17; 1390 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1391 MPI_Comm comm; 1392 PetscMPIInt size, rank; 1393 1394 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1395 PetscCallMPI(MPI_Comm_size(comm, &size)); 1396 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1397 PetscCall(DMGetDimension(dm, &dim)); 1398 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1399 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1400 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1401 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1402 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1403 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1404 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1405 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1406 gcNum = gcEnd - gcStart; 1407 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1408 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1409 for (d = 0; d <= depth; d++) { 1410 PetscInt Nc[2] = {0, 0}, ict; 1411 1412 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1413 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1414 ict = ct0; 1415 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1416 ct0 = (DMPolytopeType)ict; 1417 for (p = pStart; p < pEnd; ++p) { 1418 DMPolytopeType ct; 1419 1420 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1421 if (ct == ct0) ++Nc[0]; 1422 else ++Nc[1]; 1423 } 1424 if (size < maxSize) { 1425 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1426 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1427 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1429 for (p = 0; p < size; ++p) { 1430 if (rank == 0) { 1431 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1432 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1433 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1434 } 1435 } 1436 } else { 1437 PetscInt locMinMax[2]; 1438 1439 locMinMax[0] = Nc[0] + Nc[1]; 1440 locMinMax[1] = Nc[0] + Nc[1]; 1441 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1442 locMinMax[0] = Nc[1]; 1443 locMinMax[1] = Nc[1]; 1444 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1445 if (d == depth) { 1446 locMinMax[0] = gcNum; 1447 locMinMax[1] = gcNum; 1448 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1449 } 1450 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1451 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1452 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1453 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1454 } 1455 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1456 } 1457 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1458 { 1459 const PetscReal *maxCell; 1460 const PetscReal *L; 1461 PetscBool localized; 1462 1463 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1464 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1465 if (L || localized) { 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1467 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1468 if (L) { 1469 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1470 for (d = 0; d < dim; ++d) { 1471 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1473 } 1474 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1475 } 1476 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1477 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1478 } 1479 } 1480 PetscCall(DMGetNumLabels(dm, &numLabels)); 1481 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1482 for (l = 0; l < numLabels; ++l) { 1483 DMLabel label; 1484 const char *name; 1485 IS valueIS; 1486 const PetscInt *values; 1487 PetscInt numValues, v; 1488 1489 PetscCall(DMGetLabelName(dm, l, &name)); 1490 PetscCall(DMGetLabel(dm, name, &label)); 1491 PetscCall(DMLabelGetNumValues(label, &numValues)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1493 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1494 PetscCall(ISGetIndices(valueIS, &values)); 1495 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1496 for (v = 0; v < numValues; ++v) { 1497 PetscInt size; 1498 1499 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1500 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1502 } 1503 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1504 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1505 PetscCall(ISRestoreIndices(valueIS, &values)); 1506 PetscCall(ISDestroy(&valueIS)); 1507 } 1508 { 1509 char **labelNames; 1510 PetscInt Nl = numLabels; 1511 PetscBool flg; 1512 1513 PetscCall(PetscMalloc1(Nl, &labelNames)); 1514 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1515 for (l = 0; l < Nl; ++l) { 1516 DMLabel label; 1517 1518 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1519 if (flg) { 1520 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1521 PetscCall(DMLabelView(label, viewer)); 1522 } 1523 PetscCall(PetscFree(labelNames[l])); 1524 } 1525 PetscCall(PetscFree(labelNames)); 1526 } 1527 /* If no fields are specified, people do not want to see adjacency */ 1528 if (dm->Nf) { 1529 PetscInt f; 1530 1531 for (f = 0; f < dm->Nf; ++f) { 1532 const char *name; 1533 1534 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1535 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1536 PetscCall(PetscViewerASCIIPushTab(viewer)); 1537 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1538 if (dm->fields[f].adjacency[0]) { 1539 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1541 } else { 1542 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1543 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1544 } 1545 PetscCall(PetscViewerASCIIPopTab(viewer)); 1546 } 1547 } 1548 PetscCall(DMGetCoarseDM(dm, &cdm)); 1549 if (cdm) { 1550 PetscCall(PetscViewerASCIIPushTab(viewer)); 1551 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1552 PetscCall(PetscViewerASCIIPopTab(viewer)); 1553 } 1554 } 1555 PetscFunctionReturn(0); 1556 } 1557 1558 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) { 1559 DMPolytopeType ct; 1560 PetscMPIInt rank; 1561 PetscInt cdim; 1562 1563 PetscFunctionBegin; 1564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1565 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1566 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1567 switch (ct) { 1568 case DM_POLYTOPE_SEGMENT: 1569 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1570 switch (cdim) { 1571 case 1: { 1572 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1573 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1574 1575 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1576 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1577 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1578 } break; 1579 case 2: { 1580 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1581 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1582 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1583 1584 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1585 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1586 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1587 } break; 1588 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1589 } 1590 break; 1591 case DM_POLYTOPE_TRIANGLE: 1592 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1594 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1595 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1596 break; 1597 case DM_POLYTOPE_QUADRILATERAL: 1598 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1599 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1600 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1601 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1602 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1603 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1604 break; 1605 case DM_POLYTOPE_FV_GHOST: break; 1606 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1607 } 1608 PetscFunctionReturn(0); 1609 } 1610 1611 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) { 1612 DMPolytopeType ct; 1613 PetscReal centroid[2] = {0., 0.}; 1614 PetscMPIInt rank; 1615 PetscInt fillColor, v, e, d; 1616 1617 PetscFunctionBegin; 1618 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1619 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1620 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1621 switch (ct) { 1622 case DM_POLYTOPE_TRIANGLE: { 1623 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1624 1625 for (v = 0; v < 3; ++v) { 1626 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1627 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1628 } 1629 for (e = 0; e < 3; ++e) { 1630 refCoords[0] = refVertices[e * 2 + 0]; 1631 refCoords[1] = refVertices[e * 2 + 1]; 1632 for (d = 1; d <= edgeDiv; ++d) { 1633 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1634 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1635 } 1636 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1637 for (d = 0; d < edgeDiv; ++d) { 1638 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1639 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1640 } 1641 } 1642 } break; 1643 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1644 } 1645 PetscFunctionReturn(0); 1646 } 1647 1648 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) { 1649 PetscDraw draw; 1650 DM cdm; 1651 PetscSection coordSection; 1652 Vec coordinates; 1653 const PetscScalar *coords; 1654 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1655 PetscReal *refCoords, *edgeCoords; 1656 PetscBool isnull, drawAffine = PETSC_TRUE; 1657 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1658 1659 PetscFunctionBegin; 1660 PetscCall(DMGetCoordinateDim(dm, &dim)); 1661 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1662 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1663 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1664 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1665 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1666 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1667 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1668 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1669 1670 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1671 PetscCall(PetscDrawIsNull(draw, &isnull)); 1672 if (isnull) PetscFunctionReturn(0); 1673 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1674 1675 PetscCall(VecGetLocalSize(coordinates, &N)); 1676 PetscCall(VecGetArrayRead(coordinates, &coords)); 1677 for (c = 0; c < N; c += dim) { 1678 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1679 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1680 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1681 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1682 } 1683 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1684 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1685 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1686 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1687 PetscCall(PetscDrawClear(draw)); 1688 1689 for (c = cStart; c < cEnd; ++c) { 1690 PetscScalar *coords = NULL; 1691 PetscInt numCoords; 1692 1693 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1694 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1695 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1696 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1697 } 1698 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1699 PetscCall(PetscDrawFlush(draw)); 1700 PetscCall(PetscDrawPause(draw)); 1701 PetscCall(PetscDrawSave(draw)); 1702 PetscFunctionReturn(0); 1703 } 1704 1705 #if defined(PETSC_HAVE_EXODUSII) 1706 #include <exodusII.h> 1707 #include <petscviewerexodusii.h> 1708 #endif 1709 1710 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) { 1711 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1712 char name[PETSC_MAX_PATH_LEN]; 1713 1714 PetscFunctionBegin; 1715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1716 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1723 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1724 if (iascii) { 1725 PetscViewerFormat format; 1726 PetscCall(PetscViewerGetFormat(viewer, &format)); 1727 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1728 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1729 } else if (ishdf5) { 1730 #if defined(PETSC_HAVE_HDF5) 1731 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1732 #else 1733 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1734 #endif 1735 } else if (isvtk) { 1736 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1737 } else if (isdraw) { 1738 PetscCall(DMPlexView_Draw(dm, viewer)); 1739 } else if (isglvis) { 1740 PetscCall(DMPlexView_GLVis(dm, viewer)); 1741 #if defined(PETSC_HAVE_EXODUSII) 1742 } else if (isexodus) { 1743 /* 1744 exodusII requires that all sets be part of exactly one cell set. 1745 If the dm does not have a "Cell Sets" label defined, we create one 1746 with ID 1, containig all cells. 1747 Note that if the Cell Sets label is defined but does not cover all cells, 1748 we may still have a problem. This should probably be checked here or in the viewer; 1749 */ 1750 PetscInt numCS; 1751 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1752 if (!numCS) { 1753 PetscInt cStart, cEnd, c; 1754 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1755 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1756 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1757 } 1758 PetscCall(DMView_PlexExodusII(dm, viewer)); 1759 #endif 1760 #if defined(PETSC_HAVE_CGNS) 1761 } else if (iscgns) { 1762 PetscCall(DMView_PlexCGNS(dm, viewer)); 1763 #endif 1764 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1765 /* Optionally view the partition */ 1766 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1767 if (flg) { 1768 Vec ranks; 1769 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1770 PetscCall(VecView(ranks, viewer)); 1771 PetscCall(VecDestroy(&ranks)); 1772 } 1773 /* Optionally view a label */ 1774 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1775 if (flg) { 1776 DMLabel label; 1777 Vec val; 1778 1779 PetscCall(DMGetLabel(dm, name, &label)); 1780 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1781 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1782 PetscCall(VecView(val, viewer)); 1783 PetscCall(VecDestroy(&val)); 1784 } 1785 PetscFunctionReturn(0); 1786 } 1787 1788 /*@ 1789 DMPlexTopologyView - Saves a DMPlex topology into a file 1790 1791 Collective on DM 1792 1793 Input Parameters: 1794 + dm - The DM whose topology is to be saved 1795 - viewer - The PetscViewer for saving 1796 1797 Level: advanced 1798 1799 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1800 @*/ 1801 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) { 1802 PetscBool ishdf5; 1803 1804 PetscFunctionBegin; 1805 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1806 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1807 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1808 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1809 if (ishdf5) { 1810 #if defined(PETSC_HAVE_HDF5) 1811 PetscViewerFormat format; 1812 PetscCall(PetscViewerGetFormat(viewer, &format)); 1813 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1814 IS globalPointNumbering; 1815 1816 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1817 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1818 PetscCall(ISDestroy(&globalPointNumbering)); 1819 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1820 #else 1821 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1822 #endif 1823 } 1824 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1825 PetscFunctionReturn(0); 1826 } 1827 1828 /*@ 1829 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1830 1831 Collective on DM 1832 1833 Input Parameters: 1834 + dm - The DM whose coordinates are to be saved 1835 - viewer - The PetscViewer for saving 1836 1837 Level: advanced 1838 1839 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1840 @*/ 1841 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) { 1842 PetscBool ishdf5; 1843 1844 PetscFunctionBegin; 1845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1846 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1847 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1848 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1849 if (ishdf5) { 1850 #if defined(PETSC_HAVE_HDF5) 1851 PetscViewerFormat format; 1852 PetscCall(PetscViewerGetFormat(viewer, &format)); 1853 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1854 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1855 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1856 #else 1857 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1858 #endif 1859 } 1860 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1861 PetscFunctionReturn(0); 1862 } 1863 1864 /*@ 1865 DMPlexLabelsView - Saves DMPlex labels into a file 1866 1867 Collective on DM 1868 1869 Input Parameters: 1870 + dm - The DM whose labels are to be saved 1871 - viewer - The PetscViewer for saving 1872 1873 Level: advanced 1874 1875 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1876 @*/ 1877 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) { 1878 PetscBool ishdf5; 1879 1880 PetscFunctionBegin; 1881 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1882 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1883 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1884 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1885 if (ishdf5) { 1886 #if defined(PETSC_HAVE_HDF5) 1887 IS globalPointNumbering; 1888 PetscViewerFormat format; 1889 1890 PetscCall(PetscViewerGetFormat(viewer, &format)); 1891 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1892 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1893 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1894 PetscCall(ISDestroy(&globalPointNumbering)); 1895 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1896 #else 1897 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1898 #endif 1899 } 1900 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1901 PetscFunctionReturn(0); 1902 } 1903 1904 /*@ 1905 DMPlexSectionView - Saves a section associated with a DMPlex 1906 1907 Collective on DM 1908 1909 Input Parameters: 1910 + dm - The DM that contains the topology on which the section to be saved is defined 1911 . viewer - The PetscViewer for saving 1912 - sectiondm - The DM that contains the section to be saved 1913 1914 Level: advanced 1915 1916 Notes: 1917 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1918 1919 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1920 1921 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1922 @*/ 1923 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) { 1924 PetscBool ishdf5; 1925 1926 PetscFunctionBegin; 1927 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1928 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1929 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1930 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1931 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1932 if (ishdf5) { 1933 #if defined(PETSC_HAVE_HDF5) 1934 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1935 #else 1936 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1937 #endif 1938 } 1939 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1940 PetscFunctionReturn(0); 1941 } 1942 1943 /*@ 1944 DMPlexGlobalVectorView - Saves a global vector 1945 1946 Collective on DM 1947 1948 Input Parameters: 1949 + dm - The DM that represents the topology 1950 . viewer - The PetscViewer to save data with 1951 . sectiondm - The DM that contains the global section on which vec is defined 1952 - vec - The global vector to be saved 1953 1954 Level: advanced 1955 1956 Notes: 1957 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1958 1959 Typical calling sequence 1960 $ DMCreate(PETSC_COMM_WORLD, &dm); 1961 $ DMSetType(dm, DMPLEX); 1962 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1963 $ DMClone(dm, §iondm); 1964 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1965 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1966 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1967 $ PetscSectionSetChart(section, pStart, pEnd); 1968 $ PetscSectionSetUp(section); 1969 $ DMSetLocalSection(sectiondm, section); 1970 $ PetscSectionDestroy(§ion); 1971 $ DMGetGlobalVector(sectiondm, &vec); 1972 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1973 $ DMPlexTopologyView(dm, viewer); 1974 $ DMPlexSectionView(dm, viewer, sectiondm); 1975 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1976 $ DMRestoreGlobalVector(sectiondm, &vec); 1977 $ DMDestroy(§iondm); 1978 $ DMDestroy(&dm); 1979 1980 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1981 @*/ 1982 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 1983 PetscBool ishdf5; 1984 1985 PetscFunctionBegin; 1986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1987 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1988 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1989 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1990 /* Check consistency */ 1991 { 1992 PetscSection section; 1993 PetscBool includesConstraints; 1994 PetscInt m, m1; 1995 1996 PetscCall(VecGetLocalSize(vec, &m1)); 1997 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1998 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1999 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2000 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2001 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2002 } 2003 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2004 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2005 if (ishdf5) { 2006 #if defined(PETSC_HAVE_HDF5) 2007 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2008 #else 2009 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2010 #endif 2011 } 2012 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2013 PetscFunctionReturn(0); 2014 } 2015 2016 /*@ 2017 DMPlexLocalVectorView - Saves a local vector 2018 2019 Collective on DM 2020 2021 Input Parameters: 2022 + dm - The DM that represents the topology 2023 . viewer - The PetscViewer to save data with 2024 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2025 - vec - The local vector to be saved 2026 2027 Level: advanced 2028 2029 Notes: 2030 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2031 2032 Typical calling sequence 2033 $ DMCreate(PETSC_COMM_WORLD, &dm); 2034 $ DMSetType(dm, DMPLEX); 2035 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2036 $ DMClone(dm, §iondm); 2037 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2038 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2039 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2040 $ PetscSectionSetChart(section, pStart, pEnd); 2041 $ PetscSectionSetUp(section); 2042 $ DMSetLocalSection(sectiondm, section); 2043 $ DMGetLocalVector(sectiondm, &vec); 2044 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2045 $ DMPlexTopologyView(dm, viewer); 2046 $ DMPlexSectionView(dm, viewer, sectiondm); 2047 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2048 $ DMRestoreLocalVector(sectiondm, &vec); 2049 $ DMDestroy(§iondm); 2050 $ DMDestroy(&dm); 2051 2052 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2053 @*/ 2054 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 2055 PetscBool ishdf5; 2056 2057 PetscFunctionBegin; 2058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2059 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2060 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2061 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2062 /* Check consistency */ 2063 { 2064 PetscSection section; 2065 PetscBool includesConstraints; 2066 PetscInt m, m1; 2067 2068 PetscCall(VecGetLocalSize(vec, &m1)); 2069 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2070 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2071 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2072 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2073 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2074 } 2075 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2076 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2077 if (ishdf5) { 2078 #if defined(PETSC_HAVE_HDF5) 2079 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2080 #else 2081 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2082 #endif 2083 } 2084 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2085 PetscFunctionReturn(0); 2086 } 2087 2088 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) { 2089 PetscBool ishdf5; 2090 2091 PetscFunctionBegin; 2092 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2093 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2094 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2095 if (ishdf5) { 2096 #if defined(PETSC_HAVE_HDF5) 2097 PetscViewerFormat format; 2098 PetscCall(PetscViewerGetFormat(viewer, &format)); 2099 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2100 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2101 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2102 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2103 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2104 PetscFunctionReturn(0); 2105 #else 2106 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2107 #endif 2108 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2109 } 2110 2111 /*@ 2112 DMPlexTopologyLoad - Loads a topology into a DMPlex 2113 2114 Collective on DM 2115 2116 Input Parameters: 2117 + dm - The DM into which the topology is loaded 2118 - viewer - The PetscViewer for the saved topology 2119 2120 Output Parameters: 2121 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2122 2123 Level: advanced 2124 2125 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2126 @*/ 2127 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) { 2128 PetscBool ishdf5; 2129 2130 PetscFunctionBegin; 2131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2132 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2133 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2134 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2135 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2136 if (ishdf5) { 2137 #if defined(PETSC_HAVE_HDF5) 2138 PetscViewerFormat format; 2139 PetscCall(PetscViewerGetFormat(viewer, &format)); 2140 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2141 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2142 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2143 #else 2144 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2145 #endif 2146 } 2147 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2148 PetscFunctionReturn(0); 2149 } 2150 2151 /*@ 2152 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2153 2154 Collective on DM 2155 2156 Input Parameters: 2157 + dm - The DM into which the coordinates are loaded 2158 . viewer - The PetscViewer for the saved coordinates 2159 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2160 2161 Level: advanced 2162 2163 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2164 @*/ 2165 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2166 PetscBool ishdf5; 2167 2168 PetscFunctionBegin; 2169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2170 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2171 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2172 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2173 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2174 if (ishdf5) { 2175 #if defined(PETSC_HAVE_HDF5) 2176 PetscViewerFormat format; 2177 PetscCall(PetscViewerGetFormat(viewer, &format)); 2178 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2179 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2180 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2181 #else 2182 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2183 #endif 2184 } 2185 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2186 PetscFunctionReturn(0); 2187 } 2188 2189 /*@ 2190 DMPlexLabelsLoad - Loads labels into a DMPlex 2191 2192 Collective on DM 2193 2194 Input Parameters: 2195 + dm - The DM into which the labels are loaded 2196 . viewer - The PetscViewer for the saved labels 2197 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2198 2199 Level: advanced 2200 2201 Notes: 2202 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2203 2204 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2205 @*/ 2206 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2207 PetscBool ishdf5; 2208 2209 PetscFunctionBegin; 2210 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2211 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2212 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2213 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2214 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2215 if (ishdf5) { 2216 #if defined(PETSC_HAVE_HDF5) 2217 PetscViewerFormat format; 2218 2219 PetscCall(PetscViewerGetFormat(viewer, &format)); 2220 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2221 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2222 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2223 #else 2224 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2225 #endif 2226 } 2227 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2228 PetscFunctionReturn(0); 2229 } 2230 2231 /*@ 2232 DMPlexSectionLoad - Loads section into a DMPlex 2233 2234 Collective on DM 2235 2236 Input Parameters: 2237 + dm - The DM that represents the topology 2238 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2239 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2240 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2241 2242 Output Parameters 2243 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2244 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2245 2246 Level: advanced 2247 2248 Notes: 2249 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2250 2251 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2252 2253 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2254 2255 Example using 2 processes: 2256 $ NX (number of points on dm): 4 2257 $ sectionA : the on-disk section 2258 $ vecA : a vector associated with sectionA 2259 $ sectionB : sectiondm's local section constructed in this function 2260 $ vecB (local) : a vector associated with sectiondm's local section 2261 $ vecB (global) : a vector associated with sectiondm's global section 2262 $ 2263 $ rank 0 rank 1 2264 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2265 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2266 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2267 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2268 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2269 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2270 $ sectionB->atlasDof : 1 0 1 | 1 3 2271 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2272 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2273 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2274 $ 2275 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2276 2277 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2278 @*/ 2279 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) { 2280 PetscBool ishdf5; 2281 2282 PetscFunctionBegin; 2283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2284 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2285 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2286 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2287 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2288 if (localDofSF) PetscValidPointer(localDofSF, 6); 2289 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2290 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2291 if (ishdf5) { 2292 #if defined(PETSC_HAVE_HDF5) 2293 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2294 #else 2295 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2296 #endif 2297 } 2298 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2299 PetscFunctionReturn(0); 2300 } 2301 2302 /*@ 2303 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2304 2305 Collective on DM 2306 2307 Input Parameters: 2308 + dm - The DM that represents the topology 2309 . viewer - The PetscViewer that represents the on-disk vector data 2310 . sectiondm - The DM that contains the global section on which vec is defined 2311 . sf - The SF that migrates the on-disk vector data into vec 2312 - vec - The global vector to set values of 2313 2314 Level: advanced 2315 2316 Notes: 2317 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2318 2319 Typical calling sequence 2320 $ DMCreate(PETSC_COMM_WORLD, &dm); 2321 $ DMSetType(dm, DMPLEX); 2322 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2323 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2324 $ DMClone(dm, §iondm); 2325 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2326 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2327 $ DMGetGlobalVector(sectiondm, &vec); 2328 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2329 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2330 $ DMRestoreGlobalVector(sectiondm, &vec); 2331 $ PetscSFDestroy(&gsf); 2332 $ PetscSFDestroy(&sfX); 2333 $ DMDestroy(§iondm); 2334 $ DMDestroy(&dm); 2335 2336 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2337 @*/ 2338 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2339 PetscBool ishdf5; 2340 2341 PetscFunctionBegin; 2342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2344 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2345 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2346 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2347 /* Check consistency */ 2348 { 2349 PetscSection section; 2350 PetscBool includesConstraints; 2351 PetscInt m, m1; 2352 2353 PetscCall(VecGetLocalSize(vec, &m1)); 2354 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2355 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2356 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2357 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2358 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2359 } 2360 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2361 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2362 if (ishdf5) { 2363 #if defined(PETSC_HAVE_HDF5) 2364 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2365 #else 2366 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2367 #endif 2368 } 2369 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2370 PetscFunctionReturn(0); 2371 } 2372 2373 /*@ 2374 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2375 2376 Collective on DM 2377 2378 Input Parameters: 2379 + dm - The DM that represents the topology 2380 . viewer - The PetscViewer that represents the on-disk vector data 2381 . sectiondm - The DM that contains the local section on which vec is defined 2382 . sf - The SF that migrates the on-disk vector data into vec 2383 - vec - The local vector to set values of 2384 2385 Level: advanced 2386 2387 Notes: 2388 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2389 2390 Typical calling sequence 2391 $ DMCreate(PETSC_COMM_WORLD, &dm); 2392 $ DMSetType(dm, DMPLEX); 2393 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2394 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2395 $ DMClone(dm, §iondm); 2396 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2397 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2398 $ DMGetLocalVector(sectiondm, &vec); 2399 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2400 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2401 $ DMRestoreLocalVector(sectiondm, &vec); 2402 $ PetscSFDestroy(&lsf); 2403 $ PetscSFDestroy(&sfX); 2404 $ DMDestroy(§iondm); 2405 $ DMDestroy(&dm); 2406 2407 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2408 @*/ 2409 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2410 PetscBool ishdf5; 2411 2412 PetscFunctionBegin; 2413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2414 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2415 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2416 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2417 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2418 /* Check consistency */ 2419 { 2420 PetscSection section; 2421 PetscBool includesConstraints; 2422 PetscInt m, m1; 2423 2424 PetscCall(VecGetLocalSize(vec, &m1)); 2425 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2426 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2427 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2428 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2429 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2430 } 2431 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2432 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2433 if (ishdf5) { 2434 #if defined(PETSC_HAVE_HDF5) 2435 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2436 #else 2437 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2438 #endif 2439 } 2440 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2441 PetscFunctionReturn(0); 2442 } 2443 2444 PetscErrorCode DMDestroy_Plex(DM dm) { 2445 DM_Plex *mesh = (DM_Plex *)dm->data; 2446 2447 PetscFunctionBegin; 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2460 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2461 if (--mesh->refct > 0) PetscFunctionReturn(0); 2462 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2463 PetscCall(PetscFree(mesh->cones)); 2464 PetscCall(PetscFree(mesh->coneOrientations)); 2465 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2466 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2467 PetscCall(PetscFree(mesh->supports)); 2468 PetscCall(PetscFree(mesh->facesTmp)); 2469 PetscCall(PetscFree(mesh->tetgenOpts)); 2470 PetscCall(PetscFree(mesh->triangleOpts)); 2471 PetscCall(PetscFree(mesh->transformType)); 2472 PetscCall(PetscFree(mesh->distributionName)); 2473 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2474 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2475 PetscCall(ISDestroy(&mesh->subpointIS)); 2476 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2477 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2478 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2479 PetscCall(ISDestroy(&mesh->anchorIS)); 2480 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2481 PetscCall(PetscFree(mesh->parents)); 2482 PetscCall(PetscFree(mesh->childIDs)); 2483 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2484 PetscCall(PetscFree(mesh->children)); 2485 PetscCall(DMDestroy(&mesh->referenceTree)); 2486 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2487 PetscCall(PetscFree(mesh->neighbors)); 2488 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2489 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2490 PetscCall(PetscFree(mesh)); 2491 PetscFunctionReturn(0); 2492 } 2493 2494 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) { 2495 PetscSection sectionGlobal; 2496 PetscInt bs = -1, mbs; 2497 PetscInt localSize, localStart = 0; 2498 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2499 MatType mtype; 2500 ISLocalToGlobalMapping ltog; 2501 2502 PetscFunctionBegin; 2503 PetscCall(MatInitializePackage()); 2504 mtype = dm->mattype; 2505 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2506 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2507 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2508 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2509 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2510 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2511 PetscCall(MatSetType(*J, mtype)); 2512 PetscCall(MatSetFromOptions(*J)); 2513 PetscCall(MatGetBlockSize(*J, &mbs)); 2514 if (mbs > 1) bs = mbs; 2515 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2516 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2517 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2521 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2522 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2523 if (!isShell) { 2524 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2525 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2526 PetscInt pStart, pEnd, p, dof, cdof; 2527 2528 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2529 2530 PetscCall(PetscCalloc1(localSize, &pblocks)); 2531 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2532 for (p = pStart; p < pEnd; ++p) { 2533 PetscInt bdof, offset; 2534 2535 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2536 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2537 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2538 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2539 dof = dof < 0 ? -(dof + 1) : dof; 2540 bdof = cdof && (dof - cdof) ? 1 : dof; 2541 if (dof) { 2542 if (bs < 0) { 2543 bs = bdof; 2544 } else if (bs != bdof) { 2545 bs = 1; 2546 } 2547 } 2548 } 2549 /* Must have same blocksize on all procs (some might have no points) */ 2550 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2551 bsLocal[1] = bs; 2552 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2553 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2554 else bs = bsMinMax[0]; 2555 bs = PetscMax(1, bs); 2556 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2557 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2558 PetscCall(MatSetBlockSize(*J, bs)); 2559 PetscCall(MatSetUp(*J)); 2560 } else { 2561 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2562 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2563 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2564 } 2565 { // Consolidate blocks 2566 PetscInt nblocks = 0; 2567 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2568 if (pblocks[i] == 0) continue; 2569 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2570 for (PetscInt j = 1; j < pblocks[i]; j++) PetscCheck(pblocks[i + j] == pblocks[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Block of size %" PetscInt_FMT " mismatches entry %" PetscInt_FMT, pblocks[i], pblocks[i + j]); 2571 } 2572 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2573 } 2574 PetscCall(PetscFree(pblocks)); 2575 } 2576 PetscCall(MatSetDM(*J, dm)); 2577 PetscFunctionReturn(0); 2578 } 2579 2580 /*@ 2581 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2582 2583 Not collective 2584 2585 Input Parameter: 2586 . mesh - The DMPlex 2587 2588 Output Parameters: 2589 . subsection - The subdomain section 2590 2591 Level: developer 2592 2593 .seealso: 2594 @*/ 2595 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) { 2596 DM_Plex *mesh = (DM_Plex *)dm->data; 2597 2598 PetscFunctionBegin; 2599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2600 if (!mesh->subdomainSection) { 2601 PetscSection section; 2602 PetscSF sf; 2603 2604 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2605 PetscCall(DMGetLocalSection(dm, §ion)); 2606 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2607 PetscCall(PetscSFDestroy(&sf)); 2608 } 2609 *subsection = mesh->subdomainSection; 2610 PetscFunctionReturn(0); 2611 } 2612 2613 /*@ 2614 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2615 2616 Not collective 2617 2618 Input Parameter: 2619 . mesh - The DMPlex 2620 2621 Output Parameters: 2622 + pStart - The first mesh point 2623 - pEnd - The upper bound for mesh points 2624 2625 Level: beginner 2626 2627 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2628 @*/ 2629 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) { 2630 DM_Plex *mesh = (DM_Plex *)dm->data; 2631 2632 PetscFunctionBegin; 2633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2634 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2635 PetscFunctionReturn(0); 2636 } 2637 2638 /*@ 2639 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2640 2641 Not collective 2642 2643 Input Parameters: 2644 + mesh - The DMPlex 2645 . pStart - The first mesh point 2646 - pEnd - The upper bound for mesh points 2647 2648 Output Parameters: 2649 2650 Level: beginner 2651 2652 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2653 @*/ 2654 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) { 2655 DM_Plex *mesh = (DM_Plex *)dm->data; 2656 2657 PetscFunctionBegin; 2658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2659 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2660 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2661 PetscFunctionReturn(0); 2662 } 2663 2664 /*@ 2665 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2666 2667 Not collective 2668 2669 Input Parameters: 2670 + mesh - The DMPlex 2671 - p - The point, which must lie in the chart set with DMPlexSetChart() 2672 2673 Output Parameter: 2674 . size - The cone size for point p 2675 2676 Level: beginner 2677 2678 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2679 @*/ 2680 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) { 2681 DM_Plex *mesh = (DM_Plex *)dm->data; 2682 2683 PetscFunctionBegin; 2684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2685 PetscValidIntPointer(size, 3); 2686 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2687 PetscFunctionReturn(0); 2688 } 2689 2690 /*@ 2691 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2692 2693 Not collective 2694 2695 Input Parameters: 2696 + mesh - The DMPlex 2697 . p - The point, which must lie in the chart set with DMPlexSetChart() 2698 - size - The cone size for point p 2699 2700 Output Parameter: 2701 2702 Note: 2703 This should be called after DMPlexSetChart(). 2704 2705 Level: beginner 2706 2707 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2708 @*/ 2709 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) { 2710 DM_Plex *mesh = (DM_Plex *)dm->data; 2711 2712 PetscFunctionBegin; 2713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2714 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2715 PetscFunctionReturn(0); 2716 } 2717 2718 /*@ 2719 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2720 2721 Not collective 2722 2723 Input Parameters: 2724 + mesh - The DMPlex 2725 . p - The point, which must lie in the chart set with DMPlexSetChart() 2726 - size - The additional cone size for point p 2727 2728 Output Parameter: 2729 2730 Note: 2731 This should be called after DMPlexSetChart(). 2732 2733 Level: beginner 2734 2735 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2736 @*/ 2737 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) { 2738 DM_Plex *mesh = (DM_Plex *)dm->data; 2739 PetscFunctionBegin; 2740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2741 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2742 PetscFunctionReturn(0); 2743 } 2744 2745 /*@C 2746 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2747 2748 Not collective 2749 2750 Input Parameters: 2751 + dm - The DMPlex 2752 - p - The point, which must lie in the chart set with DMPlexSetChart() 2753 2754 Output Parameter: 2755 . cone - An array of points which are on the in-edges for point p 2756 2757 Level: beginner 2758 2759 Fortran Notes: 2760 Since it returns an array, this routine is only available in Fortran 90, and you must 2761 include petsc.h90 in your code. 2762 You must also call DMPlexRestoreCone() after you finish using the returned array. 2763 DMPlexRestoreCone() is not needed/available in C. 2764 2765 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2766 @*/ 2767 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) { 2768 DM_Plex *mesh = (DM_Plex *)dm->data; 2769 PetscInt off; 2770 2771 PetscFunctionBegin; 2772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2773 PetscValidPointer(cone, 3); 2774 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2775 *cone = &mesh->cones[off]; 2776 PetscFunctionReturn(0); 2777 } 2778 2779 /*@C 2780 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2781 2782 Not collective 2783 2784 Input Parameters: 2785 + dm - The DMPlex 2786 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2787 2788 Output Parameters: 2789 + pConesSection - PetscSection describing the layout of pCones 2790 - pCones - An array of points which are on the in-edges for the point set p 2791 2792 Level: intermediate 2793 2794 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2795 @*/ 2796 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) { 2797 PetscSection cs, newcs; 2798 PetscInt *cones; 2799 PetscInt *newarr = NULL; 2800 PetscInt n; 2801 2802 PetscFunctionBegin; 2803 PetscCall(DMPlexGetCones(dm, &cones)); 2804 PetscCall(DMPlexGetConeSection(dm, &cs)); 2805 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2806 if (pConesSection) *pConesSection = newcs; 2807 if (pCones) { 2808 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2809 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2810 } 2811 PetscFunctionReturn(0); 2812 } 2813 2814 /*@ 2815 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2816 2817 Not collective 2818 2819 Input Parameters: 2820 + dm - The DMPlex 2821 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2822 2823 Output Parameter: 2824 . expandedPoints - An array of vertices recursively expanded from input points 2825 2826 Level: advanced 2827 2828 Notes: 2829 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2830 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2831 2832 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2833 @*/ 2834 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) { 2835 IS *expandedPointsAll; 2836 PetscInt depth; 2837 2838 PetscFunctionBegin; 2839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2840 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2841 PetscValidPointer(expandedPoints, 3); 2842 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2843 *expandedPoints = expandedPointsAll[0]; 2844 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2845 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2846 PetscFunctionReturn(0); 2847 } 2848 2849 /*@ 2850 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 2851 2852 Not collective 2853 2854 Input Parameters: 2855 + dm - The DMPlex 2856 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2857 2858 Output Parameters: 2859 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2860 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2861 - sections - (optional) An array of sections which describe mappings from points to their cone points 2862 2863 Level: advanced 2864 2865 Notes: 2866 Like DMPlexGetConeTuple() but recursive. 2867 2868 Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 2869 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2870 2871 Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows: 2872 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2873 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2874 2875 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2876 @*/ 2877 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2878 const PetscInt *arr0 = NULL, *cone = NULL; 2879 PetscInt *arr = NULL, *newarr = NULL; 2880 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2881 IS *expandedPoints_; 2882 PetscSection *sections_; 2883 2884 PetscFunctionBegin; 2885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2886 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2887 if (depth) PetscValidIntPointer(depth, 3); 2888 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2889 if (sections) PetscValidPointer(sections, 5); 2890 PetscCall(ISGetLocalSize(points, &n)); 2891 PetscCall(ISGetIndices(points, &arr0)); 2892 PetscCall(DMPlexGetDepth(dm, &depth_)); 2893 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2894 PetscCall(PetscCalloc1(depth_, §ions_)); 2895 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2896 for (d = depth_ - 1; d >= 0; d--) { 2897 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2898 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2899 for (i = 0; i < n; i++) { 2900 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2901 if (arr[i] >= start && arr[i] < end) { 2902 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2903 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2904 } else { 2905 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2906 } 2907 } 2908 PetscCall(PetscSectionSetUp(sections_[d])); 2909 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2910 PetscCall(PetscMalloc1(newn, &newarr)); 2911 for (i = 0; i < n; i++) { 2912 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2913 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2914 if (cn > 1) { 2915 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2916 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2917 } else { 2918 newarr[co] = arr[i]; 2919 } 2920 } 2921 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2922 arr = newarr; 2923 n = newn; 2924 } 2925 PetscCall(ISRestoreIndices(points, &arr0)); 2926 *depth = depth_; 2927 if (expandedPoints) *expandedPoints = expandedPoints_; 2928 else { 2929 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2930 PetscCall(PetscFree(expandedPoints_)); 2931 } 2932 if (sections) *sections = sections_; 2933 else { 2934 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2935 PetscCall(PetscFree(sections_)); 2936 } 2937 PetscFunctionReturn(0); 2938 } 2939 2940 /*@ 2941 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2942 2943 Not collective 2944 2945 Input Parameters: 2946 + dm - The DMPlex 2947 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2948 2949 Output Parameters: 2950 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2951 . expandedPoints - (optional) An array of recursively expanded cones 2952 - sections - (optional) An array of sections which describe mappings from points to their cone points 2953 2954 Level: advanced 2955 2956 Notes: 2957 See DMPlexGetConeRecursive() for details. 2958 2959 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2960 @*/ 2961 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2962 PetscInt d, depth_; 2963 2964 PetscFunctionBegin; 2965 PetscCall(DMPlexGetDepth(dm, &depth_)); 2966 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2967 if (depth) *depth = 0; 2968 if (expandedPoints) { 2969 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2970 PetscCall(PetscFree(*expandedPoints)); 2971 } 2972 if (sections) { 2973 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2974 PetscCall(PetscFree(*sections)); 2975 } 2976 PetscFunctionReturn(0); 2977 } 2978 2979 /*@ 2980 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 2981 2982 Not collective 2983 2984 Input Parameters: 2985 + mesh - The DMPlex 2986 . p - The point, which must lie in the chart set with DMPlexSetChart() 2987 - cone - An array of points which are on the in-edges for point p 2988 2989 Output Parameter: 2990 2991 Note: 2992 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2993 2994 Level: beginner 2995 2996 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2997 @*/ 2998 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) { 2999 DM_Plex *mesh = (DM_Plex *)dm->data; 3000 PetscInt pStart, pEnd; 3001 PetscInt dof, off, c; 3002 3003 PetscFunctionBegin; 3004 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3005 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3006 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3007 if (dof) PetscValidIntPointer(cone, 3); 3008 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3009 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3010 for (c = 0; c < dof; ++c) { 3011 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 3012 mesh->cones[off + c] = cone[c]; 3013 } 3014 PetscFunctionReturn(0); 3015 } 3016 3017 /*@C 3018 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3019 3020 Not collective 3021 3022 Input Parameters: 3023 + mesh - The DMPlex 3024 - p - The point, which must lie in the chart set with DMPlexSetChart() 3025 3026 Output Parameter: 3027 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3028 integer giving the prescription for cone traversal. 3029 3030 Level: beginner 3031 3032 Notes: 3033 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3034 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3035 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3036 with the identity. 3037 3038 Fortran Notes: 3039 Since it returns an array, this routine is only available in Fortran 90, and you must 3040 include petsc.h90 in your code. 3041 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3042 DMPlexRestoreConeOrientation() is not needed/available in C. 3043 3044 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3045 @*/ 3046 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) { 3047 DM_Plex *mesh = (DM_Plex *)dm->data; 3048 PetscInt off; 3049 3050 PetscFunctionBegin; 3051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3052 if (PetscDefined(USE_DEBUG)) { 3053 PetscInt dof; 3054 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3055 if (dof) PetscValidPointer(coneOrientation, 3); 3056 } 3057 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3058 3059 *coneOrientation = &mesh->coneOrientations[off]; 3060 PetscFunctionReturn(0); 3061 } 3062 3063 /*@ 3064 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3065 3066 Not collective 3067 3068 Input Parameters: 3069 + mesh - The DMPlex 3070 . p - The point, which must lie in the chart set with DMPlexSetChart() 3071 - coneOrientation - An array of orientations 3072 Output Parameter: 3073 3074 Notes: 3075 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3076 3077 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3078 3079 Level: beginner 3080 3081 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3082 @*/ 3083 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) { 3084 DM_Plex *mesh = (DM_Plex *)dm->data; 3085 PetscInt pStart, pEnd; 3086 PetscInt dof, off, c; 3087 3088 PetscFunctionBegin; 3089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3090 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3091 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3092 if (dof) PetscValidIntPointer(coneOrientation, 3); 3093 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3094 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3095 for (c = 0; c < dof; ++c) { 3096 PetscInt cdof, o = coneOrientation[c]; 3097 3098 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3099 PetscCheck(!o || (o >= -(cdof + 1) && o < cdof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof + 1), cdof); 3100 mesh->coneOrientations[off + c] = o; 3101 } 3102 PetscFunctionReturn(0); 3103 } 3104 3105 /*@ 3106 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3107 3108 Not collective 3109 3110 Input Parameters: 3111 + mesh - The DMPlex 3112 . p - The point, which must lie in the chart set with DMPlexSetChart() 3113 . conePos - The local index in the cone where the point should be put 3114 - conePoint - The mesh point to insert 3115 3116 Level: beginner 3117 3118 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3119 @*/ 3120 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) { 3121 DM_Plex *mesh = (DM_Plex *)dm->data; 3122 PetscInt pStart, pEnd; 3123 PetscInt dof, off; 3124 3125 PetscFunctionBegin; 3126 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3127 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3128 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3129 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3130 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3131 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3132 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3133 mesh->cones[off + conePos] = conePoint; 3134 PetscFunctionReturn(0); 3135 } 3136 3137 /*@ 3138 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3139 3140 Not collective 3141 3142 Input Parameters: 3143 + mesh - The DMPlex 3144 . p - The point, which must lie in the chart set with DMPlexSetChart() 3145 . conePos - The local index in the cone where the point should be put 3146 - coneOrientation - The point orientation to insert 3147 3148 Level: beginner 3149 3150 Notes: 3151 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3152 3153 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3154 @*/ 3155 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) { 3156 DM_Plex *mesh = (DM_Plex *)dm->data; 3157 PetscInt pStart, pEnd; 3158 PetscInt dof, off; 3159 3160 PetscFunctionBegin; 3161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3162 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3163 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3164 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3165 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3166 PetscCheck(!(conePos < 0) && !(conePos >= dof), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3167 mesh->coneOrientations[off + conePos] = coneOrientation; 3168 PetscFunctionReturn(0); 3169 } 3170 3171 /*@ 3172 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3173 3174 Not collective 3175 3176 Input Parameters: 3177 + mesh - The DMPlex 3178 - p - The point, which must lie in the chart set with DMPlexSetChart() 3179 3180 Output Parameter: 3181 . size - The support size for point p 3182 3183 Level: beginner 3184 3185 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3186 @*/ 3187 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) { 3188 DM_Plex *mesh = (DM_Plex *)dm->data; 3189 3190 PetscFunctionBegin; 3191 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3192 PetscValidIntPointer(size, 3); 3193 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3194 PetscFunctionReturn(0); 3195 } 3196 3197 /*@ 3198 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3199 3200 Not collective 3201 3202 Input Parameters: 3203 + mesh - The DMPlex 3204 . p - The point, which must lie in the chart set with DMPlexSetChart() 3205 - size - The support size for point p 3206 3207 Output Parameter: 3208 3209 Note: 3210 This should be called after DMPlexSetChart(). 3211 3212 Level: beginner 3213 3214 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3215 @*/ 3216 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) { 3217 DM_Plex *mesh = (DM_Plex *)dm->data; 3218 3219 PetscFunctionBegin; 3220 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3221 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3222 PetscFunctionReturn(0); 3223 } 3224 3225 /*@C 3226 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3227 3228 Not collective 3229 3230 Input Parameters: 3231 + mesh - The DMPlex 3232 - p - The point, which must lie in the chart set with DMPlexSetChart() 3233 3234 Output Parameter: 3235 . support - An array of points which are on the out-edges for point p 3236 3237 Level: beginner 3238 3239 Fortran Notes: 3240 Since it returns an array, this routine is only available in Fortran 90, and you must 3241 include petsc.h90 in your code. 3242 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3243 DMPlexRestoreSupport() is not needed/available in C. 3244 3245 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3246 @*/ 3247 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) { 3248 DM_Plex *mesh = (DM_Plex *)dm->data; 3249 PetscInt off; 3250 3251 PetscFunctionBegin; 3252 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3253 PetscValidPointer(support, 3); 3254 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3255 *support = &mesh->supports[off]; 3256 PetscFunctionReturn(0); 3257 } 3258 3259 /*@ 3260 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3261 3262 Not collective 3263 3264 Input Parameters: 3265 + mesh - The DMPlex 3266 . p - The point, which must lie in the chart set with DMPlexSetChart() 3267 - support - An array of points which are on the out-edges for point p 3268 3269 Output Parameter: 3270 3271 Note: 3272 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3273 3274 Level: beginner 3275 3276 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3277 @*/ 3278 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) { 3279 DM_Plex *mesh = (DM_Plex *)dm->data; 3280 PetscInt pStart, pEnd; 3281 PetscInt dof, off, c; 3282 3283 PetscFunctionBegin; 3284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3285 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3286 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3287 if (dof) PetscValidIntPointer(support, 3); 3288 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3289 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3290 for (c = 0; c < dof; ++c) { 3291 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3292 mesh->supports[off + c] = support[c]; 3293 } 3294 PetscFunctionReturn(0); 3295 } 3296 3297 /*@ 3298 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3299 3300 Not collective 3301 3302 Input Parameters: 3303 + mesh - The DMPlex 3304 . p - The point, which must lie in the chart set with DMPlexSetChart() 3305 . supportPos - The local index in the cone where the point should be put 3306 - supportPoint - The mesh point to insert 3307 3308 Level: beginner 3309 3310 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3311 @*/ 3312 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) { 3313 DM_Plex *mesh = (DM_Plex *)dm->data; 3314 PetscInt pStart, pEnd; 3315 PetscInt dof, off; 3316 3317 PetscFunctionBegin; 3318 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3319 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3320 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3321 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3322 PetscCheck(!(p < pStart) && !(p >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3323 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3324 PetscCheck(supportPos < dof, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3325 mesh->supports[off + supportPos] = supportPoint; 3326 PetscFunctionReturn(0); 3327 } 3328 3329 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3330 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3331 switch (ct) { 3332 case DM_POLYTOPE_SEGMENT: 3333 if (o == -1) return -2; 3334 break; 3335 case DM_POLYTOPE_TRIANGLE: 3336 if (o == -3) return -1; 3337 if (o == -2) return -3; 3338 if (o == -1) return -2; 3339 break; 3340 case DM_POLYTOPE_QUADRILATERAL: 3341 if (o == -4) return -2; 3342 if (o == -3) return -1; 3343 if (o == -2) return -4; 3344 if (o == -1) return -3; 3345 break; 3346 default: return o; 3347 } 3348 return o; 3349 } 3350 3351 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3352 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3353 switch (ct) { 3354 case DM_POLYTOPE_SEGMENT: 3355 if ((o == -2) || (o == 1)) return -1; 3356 if (o == -1) return 0; 3357 break; 3358 case DM_POLYTOPE_TRIANGLE: 3359 if (o == -3) return -2; 3360 if (o == -2) return -1; 3361 if (o == -1) return -3; 3362 break; 3363 case DM_POLYTOPE_QUADRILATERAL: 3364 if (o == -4) return -2; 3365 if (o == -3) return -1; 3366 if (o == -2) return -4; 3367 if (o == -1) return -3; 3368 break; 3369 default: return o; 3370 } 3371 return o; 3372 } 3373 3374 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3375 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) { 3376 PetscInt pStart, pEnd, p; 3377 3378 PetscFunctionBegin; 3379 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3380 for (p = pStart; p < pEnd; ++p) { 3381 const PetscInt *cone, *ornt; 3382 PetscInt coneSize, c; 3383 3384 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3385 PetscCall(DMPlexGetCone(dm, p, &cone)); 3386 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3387 for (c = 0; c < coneSize; ++c) { 3388 DMPolytopeType ct; 3389 const PetscInt o = ornt[c]; 3390 3391 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3392 switch (ct) { 3393 case DM_POLYTOPE_SEGMENT: 3394 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3395 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3396 break; 3397 case DM_POLYTOPE_TRIANGLE: 3398 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3399 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3400 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3401 break; 3402 case DM_POLYTOPE_QUADRILATERAL: 3403 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3404 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3405 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3406 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3407 break; 3408 default: break; 3409 } 3410 } 3411 } 3412 PetscFunctionReturn(0); 3413 } 3414 3415 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3416 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3417 PetscInt *closure; 3418 const PetscInt *tmp = NULL, *tmpO = NULL; 3419 PetscInt off = 0, tmpSize, t; 3420 3421 PetscFunctionBeginHot; 3422 if (ornt) { 3423 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3424 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3425 } 3426 if (*points) { 3427 closure = *points; 3428 } else { 3429 PetscInt maxConeSize, maxSupportSize; 3430 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3431 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3432 } 3433 if (useCone) { 3434 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3435 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3436 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3437 } else { 3438 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3439 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3440 } 3441 if (ct == DM_POLYTOPE_UNKNOWN) { 3442 closure[off++] = p; 3443 closure[off++] = 0; 3444 for (t = 0; t < tmpSize; ++t) { 3445 closure[off++] = tmp[t]; 3446 closure[off++] = tmpO ? tmpO[t] : 0; 3447 } 3448 } else { 3449 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3450 3451 /* We assume that cells with a valid type have faces with a valid type */ 3452 closure[off++] = p; 3453 closure[off++] = ornt; 3454 for (t = 0; t < tmpSize; ++t) { 3455 DMPolytopeType ft; 3456 3457 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3458 closure[off++] = tmp[arr[t]]; 3459 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3460 } 3461 } 3462 if (numPoints) *numPoints = tmpSize + 1; 3463 if (points) *points = closure; 3464 PetscFunctionReturn(0); 3465 } 3466 3467 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3468 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) { 3469 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3470 const PetscInt *cone, *ornt; 3471 PetscInt *pts, *closure = NULL; 3472 DMPolytopeType ft; 3473 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3474 PetscInt dim, coneSize, c, d, clSize, cl; 3475 3476 PetscFunctionBeginHot; 3477 PetscCall(DMGetDimension(dm, &dim)); 3478 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3479 PetscCall(DMPlexGetCone(dm, point, &cone)); 3480 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3481 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3482 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3483 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3484 maxSize = PetscMax(coneSeries, supportSeries); 3485 if (*points) { 3486 pts = *points; 3487 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3488 c = 0; 3489 pts[c++] = point; 3490 pts[c++] = o; 3491 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3492 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3493 for (cl = 0; cl < clSize * 2; cl += 2) { 3494 pts[c++] = closure[cl]; 3495 pts[c++] = closure[cl + 1]; 3496 } 3497 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3498 for (cl = 0; cl < clSize * 2; cl += 2) { 3499 pts[c++] = closure[cl]; 3500 pts[c++] = closure[cl + 1]; 3501 } 3502 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3503 for (d = 2; d < coneSize; ++d) { 3504 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3505 pts[c++] = cone[arr[d * 2 + 0]]; 3506 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3507 } 3508 if (dim >= 3) { 3509 for (d = 2; d < coneSize; ++d) { 3510 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3511 const PetscInt *fcone, *fornt; 3512 PetscInt fconeSize, fc, i; 3513 3514 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3515 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3516 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3517 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3518 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3519 for (fc = 0; fc < fconeSize; ++fc) { 3520 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3521 const PetscInt co = farr[fc * 2 + 1]; 3522 3523 for (i = 0; i < c; i += 2) 3524 if (pts[i] == cp) break; 3525 if (i == c) { 3526 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3527 pts[c++] = cp; 3528 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3529 } 3530 } 3531 } 3532 } 3533 *numPoints = c / 2; 3534 *points = pts; 3535 PetscFunctionReturn(0); 3536 } 3537 3538 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3539 DMPolytopeType ct; 3540 PetscInt *closure, *fifo; 3541 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3542 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3543 PetscInt depth, maxSize; 3544 3545 PetscFunctionBeginHot; 3546 PetscCall(DMPlexGetDepth(dm, &depth)); 3547 if (depth == 1) { 3548 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3549 PetscFunctionReturn(0); 3550 } 3551 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3552 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3553 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3554 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3555 PetscFunctionReturn(0); 3556 } 3557 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3558 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3559 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3560 maxSize = PetscMax(coneSeries, supportSeries); 3561 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3562 if (*points) { 3563 closure = *points; 3564 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3565 closure[closureSize++] = p; 3566 closure[closureSize++] = ornt; 3567 fifo[fifoSize++] = p; 3568 fifo[fifoSize++] = ornt; 3569 fifo[fifoSize++] = ct; 3570 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3571 while (fifoSize - fifoStart) { 3572 const PetscInt q = fifo[fifoStart++]; 3573 const PetscInt o = fifo[fifoStart++]; 3574 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3575 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3576 const PetscInt *tmp, *tmpO; 3577 PetscInt tmpSize, t; 3578 3579 if (PetscDefined(USE_DEBUG)) { 3580 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3581 PetscCheck(!o || !(o >= nO || o < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3582 } 3583 if (useCone) { 3584 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3585 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3586 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3587 } else { 3588 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3589 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3590 tmpO = NULL; 3591 } 3592 for (t = 0; t < tmpSize; ++t) { 3593 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3594 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3595 const PetscInt cp = tmp[ip]; 3596 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3597 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3598 PetscInt c; 3599 3600 /* Check for duplicate */ 3601 for (c = 0; c < closureSize; c += 2) { 3602 if (closure[c] == cp) break; 3603 } 3604 if (c == closureSize) { 3605 closure[closureSize++] = cp; 3606 closure[closureSize++] = co; 3607 fifo[fifoSize++] = cp; 3608 fifo[fifoSize++] = co; 3609 fifo[fifoSize++] = ct; 3610 } 3611 } 3612 } 3613 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3614 if (numPoints) *numPoints = closureSize / 2; 3615 if (points) *points = closure; 3616 PetscFunctionReturn(0); 3617 } 3618 3619 /*@C 3620 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3621 3622 Not collective 3623 3624 Input Parameters: 3625 + dm - The DMPlex 3626 . p - The mesh point 3627 - useCone - PETSC_TRUE for the closure, otherwise return the star 3628 3629 Input/Output Parameter: 3630 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3631 if NULL on input, internal storage will be returned, otherwise the provided array is used 3632 3633 Output Parameter: 3634 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3635 3636 Note: 3637 If using internal storage (points is NULL on input), each call overwrites the last output. 3638 3639 Fortran Note: 3640 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3641 3642 Level: beginner 3643 3644 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3645 @*/ 3646 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3647 PetscFunctionBeginHot; 3648 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3649 if (numPoints) PetscValidIntPointer(numPoints, 4); 3650 if (points) PetscValidPointer(points, 5); 3651 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3652 PetscFunctionReturn(0); 3653 } 3654 3655 /*@C 3656 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3657 3658 Not collective 3659 3660 Input Parameters: 3661 + dm - The DMPlex 3662 . p - The mesh point 3663 . useCone - PETSC_TRUE for the closure, otherwise return the star 3664 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3665 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3666 3667 Note: 3668 If not using internal storage (points is not NULL on input), this call is unnecessary 3669 3670 Level: beginner 3671 3672 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3673 @*/ 3674 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3675 PetscFunctionBeginHot; 3676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3677 if (numPoints) *numPoints = 0; 3678 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3679 PetscFunctionReturn(0); 3680 } 3681 3682 /*@ 3683 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3684 3685 Not collective 3686 3687 Input Parameter: 3688 . mesh - The DMPlex 3689 3690 Output Parameters: 3691 + maxConeSize - The maximum number of in-edges 3692 - maxSupportSize - The maximum number of out-edges 3693 3694 Level: beginner 3695 3696 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3697 @*/ 3698 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) { 3699 DM_Plex *mesh = (DM_Plex *)dm->data; 3700 3701 PetscFunctionBegin; 3702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3703 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3704 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3705 PetscFunctionReturn(0); 3706 } 3707 3708 PetscErrorCode DMSetUp_Plex(DM dm) { 3709 DM_Plex *mesh = (DM_Plex *)dm->data; 3710 PetscInt size, maxSupportSize; 3711 3712 PetscFunctionBegin; 3713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3714 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3715 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3716 PetscCall(PetscMalloc1(size, &mesh->cones)); 3717 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3718 PetscCall(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 } 3724 PetscFunctionReturn(0); 3725 } 3726 3727 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) { 3728 PetscFunctionBegin; 3729 if (subdm) PetscCall(DMClone(dm, subdm)); 3730 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3731 if (subdm) (*subdm)->useNatural = dm->useNatural; 3732 if (dm->useNatural && dm->sfMigration) { 3733 PetscSF sfNatural; 3734 3735 (*subdm)->sfMigration = dm->sfMigration; 3736 PetscCall(PetscObjectReference((PetscObject)dm->sfMigration)); 3737 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, NULL, (*subdm)->sfMigration, &sfNatural)); 3738 (*subdm)->sfNatural = sfNatural; 3739 } 3740 PetscFunctionReturn(0); 3741 } 3742 3743 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) { 3744 PetscInt i = 0; 3745 3746 PetscFunctionBegin; 3747 PetscCall(DMClone(dms[0], superdm)); 3748 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3749 (*superdm)->useNatural = PETSC_FALSE; 3750 for (i = 0; i < len; i++) { 3751 if (dms[i]->useNatural && dms[i]->sfMigration) { 3752 PetscSF sfNatural; 3753 3754 (*superdm)->sfMigration = dms[i]->sfMigration; 3755 PetscCall(PetscObjectReference((PetscObject)dms[i]->sfMigration)); 3756 (*superdm)->useNatural = PETSC_TRUE; 3757 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, NULL, (*superdm)->sfMigration, &sfNatural)); 3758 (*superdm)->sfNatural = sfNatural; 3759 break; 3760 } 3761 } 3762 PetscFunctionReturn(0); 3763 } 3764 3765 /*@ 3766 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3767 3768 Not collective 3769 3770 Input Parameter: 3771 . mesh - The DMPlex 3772 3773 Output Parameter: 3774 3775 Note: 3776 This should be called after all calls to DMPlexSetCone() 3777 3778 Level: beginner 3779 3780 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3781 @*/ 3782 PetscErrorCode DMPlexSymmetrize(DM dm) { 3783 DM_Plex *mesh = (DM_Plex *)dm->data; 3784 PetscInt *offsets; 3785 PetscInt supportSize; 3786 PetscInt pStart, pEnd, p; 3787 3788 PetscFunctionBegin; 3789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3790 PetscCheck(!mesh->supports, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3791 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3792 /* Calculate support sizes */ 3793 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3794 for (p = pStart; p < pEnd; ++p) { 3795 PetscInt dof, off, c; 3796 3797 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3798 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3799 for (c = off; c < off + dof; ++c) PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3800 } 3801 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3802 /* Calculate supports */ 3803 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3804 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3805 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3806 for (p = pStart; p < pEnd; ++p) { 3807 PetscInt dof, off, c; 3808 3809 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3810 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3811 for (c = off; c < off + dof; ++c) { 3812 const PetscInt q = mesh->cones[c]; 3813 PetscInt offS; 3814 3815 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3816 3817 mesh->supports[offS + offsets[q]] = p; 3818 ++offsets[q]; 3819 } 3820 } 3821 PetscCall(PetscFree(offsets)); 3822 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize, dm, 0, 0, 0)); 3823 PetscFunctionReturn(0); 3824 } 3825 3826 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) { 3827 IS stratumIS; 3828 3829 PetscFunctionBegin; 3830 if (pStart >= pEnd) PetscFunctionReturn(0); 3831 if (PetscDefined(USE_DEBUG)) { 3832 PetscInt qStart, qEnd, numLevels, level; 3833 PetscBool overlap = PETSC_FALSE; 3834 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3835 for (level = 0; level < numLevels; level++) { 3836 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3837 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) { 3838 overlap = PETSC_TRUE; 3839 break; 3840 } 3841 } 3842 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); 3843 } 3844 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &stratumIS)); 3845 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3846 PetscCall(ISDestroy(&stratumIS)); 3847 PetscFunctionReturn(0); 3848 } 3849 3850 /*@ 3851 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3852 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3853 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3854 the DAG. 3855 3856 Collective on dm 3857 3858 Input Parameter: 3859 . mesh - The DMPlex 3860 3861 Output Parameter: 3862 3863 Notes: 3864 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3865 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3866 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3867 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3868 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3869 3870 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3871 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3872 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 3873 to interpolate only that one (e0), so that 3874 $ cone(c0) = {e0, v2} 3875 $ cone(e0) = {v0, v1} 3876 If DMPlexStratify() is run on this mesh, it will give depths 3877 $ depth 0 = {v0, v1, v2} 3878 $ depth 1 = {e0, c0} 3879 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3880 3881 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3882 3883 Level: beginner 3884 3885 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3886 @*/ 3887 PetscErrorCode DMPlexStratify(DM dm) { 3888 DM_Plex *mesh = (DM_Plex *)dm->data; 3889 DMLabel label; 3890 PetscInt pStart, pEnd, p; 3891 PetscInt numRoots = 0, numLeaves = 0; 3892 3893 PetscFunctionBegin; 3894 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3895 PetscCall(PetscLogEventBegin(DMPLEX_Stratify, dm, 0, 0, 0)); 3896 3897 /* Create depth label */ 3898 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3899 PetscCall(DMCreateLabel(dm, "depth")); 3900 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3901 3902 { 3903 /* Initialize roots and count leaves */ 3904 PetscInt sMin = PETSC_MAX_INT; 3905 PetscInt sMax = PETSC_MIN_INT; 3906 PetscInt coneSize, supportSize; 3907 3908 for (p = pStart; p < pEnd; ++p) { 3909 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3910 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3911 if (!coneSize && supportSize) { 3912 sMin = PetscMin(p, sMin); 3913 sMax = PetscMax(p, sMax); 3914 ++numRoots; 3915 } else if (!supportSize && coneSize) { 3916 ++numLeaves; 3917 } else if (!supportSize && !coneSize) { 3918 /* Isolated points */ 3919 sMin = PetscMin(p, sMin); 3920 sMax = PetscMax(p, sMax); 3921 } 3922 } 3923 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax + 1)); 3924 } 3925 3926 if (numRoots + numLeaves == (pEnd - pStart)) { 3927 PetscInt sMin = PETSC_MAX_INT; 3928 PetscInt sMax = PETSC_MIN_INT; 3929 PetscInt coneSize, supportSize; 3930 3931 for (p = pStart; p < pEnd; ++p) { 3932 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3933 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3934 if (!supportSize && coneSize) { 3935 sMin = PetscMin(p, sMin); 3936 sMax = PetscMax(p, sMax); 3937 } 3938 } 3939 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax + 1)); 3940 } else { 3941 PetscInt level = 0; 3942 PetscInt qStart, qEnd, q; 3943 3944 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3945 while (qEnd > qStart) { 3946 PetscInt sMin = PETSC_MAX_INT; 3947 PetscInt sMax = PETSC_MIN_INT; 3948 3949 for (q = qStart; q < qEnd; ++q) { 3950 const PetscInt *support; 3951 PetscInt supportSize, s; 3952 3953 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3954 PetscCall(DMPlexGetSupport(dm, q, &support)); 3955 for (s = 0; s < supportSize; ++s) { 3956 sMin = PetscMin(support[s], sMin); 3957 sMax = PetscMax(support[s], sMax); 3958 } 3959 } 3960 PetscCall(DMLabelGetNumValues(label, &level)); 3961 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax + 1)); 3962 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3963 } 3964 } 3965 { /* just in case there is an empty process */ 3966 PetscInt numValues, maxValues = 0, v; 3967 3968 PetscCall(DMLabelGetNumValues(label, &numValues)); 3969 PetscCallMPI(MPI_Allreduce(&numValues, &maxValues, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 3970 for (v = numValues; v < maxValues; v++) PetscCall(DMLabelAddStratum(label, v)); 3971 } 3972 PetscCall(PetscObjectStateGet((PetscObject)label, &mesh->depthState)); 3973 PetscCall(PetscLogEventEnd(DMPLEX_Stratify, dm, 0, 0, 0)); 3974 PetscFunctionReturn(0); 3975 } 3976 3977 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) { 3978 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3979 PetscInt dim, depth, pheight, coneSize; 3980 3981 PetscFunctionBeginHot; 3982 PetscCall(DMGetDimension(dm, &dim)); 3983 PetscCall(DMPlexGetDepth(dm, &depth)); 3984 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3985 pheight = depth - pdepth; 3986 if (depth <= 1) { 3987 switch (pdepth) { 3988 case 0: ct = DM_POLYTOPE_POINT; break; 3989 case 1: 3990 switch (coneSize) { 3991 case 2: ct = DM_POLYTOPE_SEGMENT; break; 3992 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 3993 case 4: 3994 switch (dim) { 3995 case 2: ct = DM_POLYTOPE_QUADRILATERAL; break; 3996 case 3: ct = DM_POLYTOPE_TETRAHEDRON; break; 3997 default: break; 3998 } 3999 break; 4000 case 5: ct = DM_POLYTOPE_PYRAMID; break; 4001 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4002 case 8: ct = DM_POLYTOPE_HEXAHEDRON; break; 4003 default: break; 4004 } 4005 } 4006 } else { 4007 if (pdepth == 0) { 4008 ct = DM_POLYTOPE_POINT; 4009 } else if (pheight == 0) { 4010 switch (dim) { 4011 case 1: 4012 switch (coneSize) { 4013 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4014 default: break; 4015 } 4016 break; 4017 case 2: 4018 switch (coneSize) { 4019 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4020 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4021 default: break; 4022 } 4023 break; 4024 case 3: 4025 switch (coneSize) { 4026 case 4: ct = DM_POLYTOPE_TETRAHEDRON; break; 4027 case 5: { 4028 const PetscInt *cone; 4029 PetscInt faceConeSize; 4030 4031 PetscCall(DMPlexGetCone(dm, p, &cone)); 4032 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4033 switch (faceConeSize) { 4034 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR; break; 4035 case 4: ct = DM_POLYTOPE_PYRAMID; break; 4036 } 4037 } break; 4038 case 6: ct = DM_POLYTOPE_HEXAHEDRON; break; 4039 default: break; 4040 } 4041 break; 4042 default: break; 4043 } 4044 } else if (pheight > 0) { 4045 switch (coneSize) { 4046 case 2: ct = DM_POLYTOPE_SEGMENT; break; 4047 case 3: ct = DM_POLYTOPE_TRIANGLE; break; 4048 case 4: ct = DM_POLYTOPE_QUADRILATERAL; break; 4049 default: break; 4050 } 4051 } 4052 } 4053 *pt = ct; 4054 PetscFunctionReturn(0); 4055 } 4056 4057 /*@ 4058 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4059 4060 Collective on dm 4061 4062 Input Parameter: 4063 . mesh - The DMPlex 4064 4065 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4066 4067 Level: developer 4068 4069 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4070 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4071 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4072 4073 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4074 @*/ 4075 PetscErrorCode DMPlexComputeCellTypes(DM dm) { 4076 DM_Plex *mesh; 4077 DMLabel ctLabel; 4078 PetscInt pStart, pEnd, p; 4079 4080 PetscFunctionBegin; 4081 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4082 mesh = (DM_Plex *)dm->data; 4083 PetscCall(DMCreateLabel(dm, "celltype")); 4084 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4085 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4086 for (p = pStart; p < pEnd; ++p) { 4087 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4088 PetscInt pdepth; 4089 4090 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4091 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4092 PetscCheck(ct != DM_POLYTOPE_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4093 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4094 } 4095 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &mesh->celltypeState)); 4096 PetscCall(PetscObjectViewFromOptions((PetscObject)ctLabel, NULL, "-dm_plex_celltypes_view")); 4097 PetscFunctionReturn(0); 4098 } 4099 4100 /*@C 4101 DMPlexGetJoin - Get an array for the join of the set of points 4102 4103 Not Collective 4104 4105 Input Parameters: 4106 + dm - The DMPlex object 4107 . numPoints - The number of input points for the join 4108 - points - The input points 4109 4110 Output Parameters: 4111 + numCoveredPoints - The number of points in the join 4112 - coveredPoints - The points in the join 4113 4114 Level: intermediate 4115 4116 Note: Currently, this is restricted to a single level join 4117 4118 Fortran Notes: 4119 Since it returns an array, this routine is only available in Fortran 90, and you must 4120 include petsc.h90 in your code. 4121 4122 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4123 4124 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4125 @*/ 4126 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4127 DM_Plex *mesh = (DM_Plex *)dm->data; 4128 PetscInt *join[2]; 4129 PetscInt joinSize, i = 0; 4130 PetscInt dof, off, p, c, m; 4131 PetscInt maxSupportSize; 4132 4133 PetscFunctionBegin; 4134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4135 PetscValidIntPointer(points, 3); 4136 PetscValidIntPointer(numCoveredPoints, 4); 4137 PetscValidPointer(coveredPoints, 5); 4138 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4139 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4140 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4141 /* Copy in support of first point */ 4142 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4143 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4144 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = mesh->supports[off + joinSize]; 4145 /* Check each successive support */ 4146 for (p = 1; p < numPoints; ++p) { 4147 PetscInt newJoinSize = 0; 4148 4149 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4150 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4151 for (c = 0; c < dof; ++c) { 4152 const PetscInt point = mesh->supports[off + c]; 4153 4154 for (m = 0; m < joinSize; ++m) { 4155 if (point == join[i][m]) { 4156 join[1 - i][newJoinSize++] = point; 4157 break; 4158 } 4159 } 4160 } 4161 joinSize = newJoinSize; 4162 i = 1 - i; 4163 } 4164 *numCoveredPoints = joinSize; 4165 *coveredPoints = join[i]; 4166 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1 - i])); 4167 PetscFunctionReturn(0); 4168 } 4169 4170 /*@C 4171 DMPlexRestoreJoin - Restore an array for the join of the set of points 4172 4173 Not Collective 4174 4175 Input Parameters: 4176 + dm - The DMPlex object 4177 . numPoints - The number of input points for the join 4178 - points - The input points 4179 4180 Output Parameters: 4181 + numCoveredPoints - The number of points in the join 4182 - coveredPoints - The points in the join 4183 4184 Fortran Notes: 4185 Since it returns an array, this routine is only available in Fortran 90, and you must 4186 include petsc.h90 in your code. 4187 4188 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4189 4190 Level: intermediate 4191 4192 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4193 @*/ 4194 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4195 PetscFunctionBegin; 4196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4197 if (points) PetscValidIntPointer(points, 3); 4198 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4199 PetscValidPointer(coveredPoints, 5); 4200 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4201 if (numCoveredPoints) *numCoveredPoints = 0; 4202 PetscFunctionReturn(0); 4203 } 4204 4205 /*@C 4206 DMPlexGetFullJoin - Get an array for the join of the set of points 4207 4208 Not Collective 4209 4210 Input Parameters: 4211 + dm - The DMPlex object 4212 . numPoints - The number of input points for the join 4213 - points - The input points 4214 4215 Output Parameters: 4216 + numCoveredPoints - The number of points in the join 4217 - coveredPoints - The points in the join 4218 4219 Fortran Notes: 4220 Since it returns an array, this routine is only available in Fortran 90, and you must 4221 include petsc.h90 in your code. 4222 4223 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4224 4225 Level: intermediate 4226 4227 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4228 @*/ 4229 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4230 PetscInt *offsets, **closures; 4231 PetscInt *join[2]; 4232 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4233 PetscInt p, d, c, m, ms; 4234 4235 PetscFunctionBegin; 4236 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4237 PetscValidIntPointer(points, 3); 4238 PetscValidIntPointer(numCoveredPoints, 4); 4239 PetscValidPointer(coveredPoints, 5); 4240 4241 PetscCall(DMPlexGetDepth(dm, &depth)); 4242 PetscCall(PetscCalloc1(numPoints, &closures)); 4243 PetscCall(DMGetWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4244 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4245 maxSize = (ms > 1) ? ((PetscPowInt(ms, depth + 1) - 1) / (ms - 1)) : depth + 1; 4246 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4247 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4248 4249 for (p = 0; p < numPoints; ++p) { 4250 PetscInt closureSize; 4251 4252 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4253 4254 offsets[p * (depth + 2) + 0] = 0; 4255 for (d = 0; d < depth + 1; ++d) { 4256 PetscInt pStart, pEnd, i; 4257 4258 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4259 for (i = offsets[p * (depth + 2) + d]; i < closureSize; ++i) { 4260 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4261 offsets[p * (depth + 2) + d + 1] = i; 4262 break; 4263 } 4264 } 4265 if (i == closureSize) offsets[p * (depth + 2) + d + 1] = i; 4266 } 4267 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); 4268 } 4269 for (d = 0; d < depth + 1; ++d) { 4270 PetscInt dof; 4271 4272 /* Copy in support of first point */ 4273 dof = offsets[d + 1] - offsets[d]; 4274 for (joinSize = 0; joinSize < dof; ++joinSize) join[i][joinSize] = closures[0][(offsets[d] + joinSize) * 2]; 4275 /* Check each successive cone */ 4276 for (p = 1; p < numPoints && joinSize; ++p) { 4277 PetscInt newJoinSize = 0; 4278 4279 dof = offsets[p * (depth + 2) + d + 1] - offsets[p * (depth + 2) + d]; 4280 for (c = 0; c < dof; ++c) { 4281 const PetscInt point = closures[p][(offsets[p * (depth + 2) + d] + c) * 2]; 4282 4283 for (m = 0; m < joinSize; ++m) { 4284 if (point == join[i][m]) { 4285 join[1 - i][newJoinSize++] = point; 4286 break; 4287 } 4288 } 4289 } 4290 joinSize = newJoinSize; 4291 i = 1 - i; 4292 } 4293 if (joinSize) break; 4294 } 4295 *numCoveredPoints = joinSize; 4296 *coveredPoints = join[i]; 4297 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4298 PetscCall(PetscFree(closures)); 4299 PetscCall(DMRestoreWorkArray(dm, numPoints * (depth + 2), MPIU_INT, &offsets)); 4300 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1 - i])); 4301 PetscFunctionReturn(0); 4302 } 4303 4304 /*@C 4305 DMPlexGetMeet - Get an array for the meet of the set of points 4306 4307 Not Collective 4308 4309 Input Parameters: 4310 + dm - The DMPlex object 4311 . numPoints - The number of input points for the meet 4312 - points - The input points 4313 4314 Output Parameters: 4315 + numCoveredPoints - The number of points in the meet 4316 - coveredPoints - The points in the meet 4317 4318 Level: intermediate 4319 4320 Note: Currently, this is restricted to a single level meet 4321 4322 Fortran Notes: 4323 Since it returns an array, this routine is only available in Fortran 90, and you must 4324 include petsc.h90 in your code. 4325 4326 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4327 4328 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4329 @*/ 4330 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) { 4331 DM_Plex *mesh = (DM_Plex *)dm->data; 4332 PetscInt *meet[2]; 4333 PetscInt meetSize, i = 0; 4334 PetscInt dof, off, p, c, m; 4335 PetscInt maxConeSize; 4336 4337 PetscFunctionBegin; 4338 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4339 PetscValidIntPointer(points, 3); 4340 PetscValidIntPointer(numCoveringPoints, 4); 4341 PetscValidPointer(coveringPoints, 5); 4342 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4343 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4344 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4345 /* Copy in cone of first point */ 4346 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4347 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4348 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = mesh->cones[off + meetSize]; 4349 /* Check each successive cone */ 4350 for (p = 1; p < numPoints; ++p) { 4351 PetscInt newMeetSize = 0; 4352 4353 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4354 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4355 for (c = 0; c < dof; ++c) { 4356 const PetscInt point = mesh->cones[off + c]; 4357 4358 for (m = 0; m < meetSize; ++m) { 4359 if (point == meet[i][m]) { 4360 meet[1 - i][newMeetSize++] = point; 4361 break; 4362 } 4363 } 4364 } 4365 meetSize = newMeetSize; 4366 i = 1 - i; 4367 } 4368 *numCoveringPoints = meetSize; 4369 *coveringPoints = meet[i]; 4370 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1 - i])); 4371 PetscFunctionReturn(0); 4372 } 4373 4374 /*@C 4375 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4376 4377 Not Collective 4378 4379 Input Parameters: 4380 + dm - The DMPlex object 4381 . numPoints - The number of input points for the meet 4382 - points - The input points 4383 4384 Output Parameters: 4385 + numCoveredPoints - The number of points in the meet 4386 - coveredPoints - The points in the meet 4387 4388 Level: intermediate 4389 4390 Fortran Notes: 4391 Since it returns an array, this routine is only available in Fortran 90, and you must 4392 include petsc.h90 in your code. 4393 4394 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4395 4396 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4397 @*/ 4398 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4399 PetscFunctionBegin; 4400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4401 if (points) PetscValidIntPointer(points, 3); 4402 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints, 4); 4403 PetscValidPointer(coveredPoints, 5); 4404 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *)coveredPoints)); 4405 if (numCoveredPoints) *numCoveredPoints = 0; 4406 PetscFunctionReturn(0); 4407 } 4408 4409 /*@C 4410 DMPlexGetFullMeet - Get an array for the meet of the set of points 4411 4412 Not Collective 4413 4414 Input Parameters: 4415 + dm - The DMPlex object 4416 . numPoints - The number of input points for the meet 4417 - points - The input points 4418 4419 Output Parameters: 4420 + numCoveredPoints - The number of points in the meet 4421 - coveredPoints - The points in the meet 4422 4423 Level: intermediate 4424 4425 Fortran Notes: 4426 Since it returns an array, this routine is only available in Fortran 90, and you must 4427 include petsc.h90 in your code. 4428 4429 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4430 4431 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4432 @*/ 4433 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) { 4434 PetscInt *offsets, **closures; 4435 PetscInt *meet[2]; 4436 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4437 PetscInt p, h, c, m, mc; 4438 4439 PetscFunctionBegin; 4440 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4441 PetscValidIntPointer(points, 3); 4442 PetscValidIntPointer(numCoveredPoints, 4); 4443 PetscValidPointer(coveredPoints, 5); 4444 4445 PetscCall(DMPlexGetDepth(dm, &height)); 4446 PetscCall(PetscMalloc1(numPoints, &closures)); 4447 PetscCall(DMGetWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4448 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4449 maxSize = (mc > 1) ? ((PetscPowInt(mc, height + 1) - 1) / (mc - 1)) : height + 1; 4450 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4451 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4452 4453 for (p = 0; p < numPoints; ++p) { 4454 PetscInt closureSize; 4455 4456 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4457 4458 offsets[p * (height + 2) + 0] = 0; 4459 for (h = 0; h < height + 1; ++h) { 4460 PetscInt pStart, pEnd, i; 4461 4462 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4463 for (i = offsets[p * (height + 2) + h]; i < closureSize; ++i) { 4464 if ((pStart > closures[p][i * 2]) || (pEnd <= closures[p][i * 2])) { 4465 offsets[p * (height + 2) + h + 1] = i; 4466 break; 4467 } 4468 } 4469 if (i == closureSize) offsets[p * (height + 2) + h + 1] = i; 4470 } 4471 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); 4472 } 4473 for (h = 0; h < height + 1; ++h) { 4474 PetscInt dof; 4475 4476 /* Copy in cone of first point */ 4477 dof = offsets[h + 1] - offsets[h]; 4478 for (meetSize = 0; meetSize < dof; ++meetSize) meet[i][meetSize] = closures[0][(offsets[h] + meetSize) * 2]; 4479 /* Check each successive cone */ 4480 for (p = 1; p < numPoints && meetSize; ++p) { 4481 PetscInt newMeetSize = 0; 4482 4483 dof = offsets[p * (height + 2) + h + 1] - offsets[p * (height + 2) + h]; 4484 for (c = 0; c < dof; ++c) { 4485 const PetscInt point = closures[p][(offsets[p * (height + 2) + h] + c) * 2]; 4486 4487 for (m = 0; m < meetSize; ++m) { 4488 if (point == meet[i][m]) { 4489 meet[1 - i][newMeetSize++] = point; 4490 break; 4491 } 4492 } 4493 } 4494 meetSize = newMeetSize; 4495 i = 1 - i; 4496 } 4497 if (meetSize) break; 4498 } 4499 *numCoveredPoints = meetSize; 4500 *coveredPoints = meet[i]; 4501 for (p = 0; p < numPoints; ++p) PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4502 PetscCall(PetscFree(closures)); 4503 PetscCall(DMRestoreWorkArray(dm, numPoints * (height + 2), MPIU_INT, &offsets)); 4504 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1 - i])); 4505 PetscFunctionReturn(0); 4506 } 4507 4508 /*@C 4509 DMPlexEqual - Determine if two DMs have the same topology 4510 4511 Not Collective 4512 4513 Input Parameters: 4514 + dmA - A DMPlex object 4515 - dmB - A DMPlex object 4516 4517 Output Parameters: 4518 . equal - PETSC_TRUE if the topologies are identical 4519 4520 Level: intermediate 4521 4522 Notes: 4523 We are not solving graph isomorphism, so we do not permutation. 4524 4525 .seealso: `DMPlexGetCone()` 4526 @*/ 4527 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) { 4528 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4529 4530 PetscFunctionBegin; 4531 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4532 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4533 PetscValidBoolPointer(equal, 3); 4534 4535 *equal = PETSC_FALSE; 4536 PetscCall(DMPlexGetDepth(dmA, &depth)); 4537 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4538 if (depth != depthB) PetscFunctionReturn(0); 4539 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4540 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4541 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4542 for (p = pStart; p < pEnd; ++p) { 4543 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4544 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4545 4546 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4547 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4548 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4549 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4550 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4551 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4552 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4553 for (c = 0; c < coneSize; ++c) { 4554 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4555 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4556 } 4557 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4558 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4559 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4560 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4561 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4562 for (s = 0; s < supportSize; ++s) { 4563 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4564 } 4565 } 4566 *equal = PETSC_TRUE; 4567 PetscFunctionReturn(0); 4568 } 4569 4570 /*@C 4571 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4572 4573 Not Collective 4574 4575 Input Parameters: 4576 + dm - The DMPlex 4577 . cellDim - The cell dimension 4578 - numCorners - The number of vertices on a cell 4579 4580 Output Parameters: 4581 . numFaceVertices - The number of vertices on a face 4582 4583 Level: developer 4584 4585 Notes: 4586 Of course this can only work for a restricted set of symmetric shapes 4587 4588 .seealso: `DMPlexGetCone()` 4589 @*/ 4590 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) { 4591 MPI_Comm comm; 4592 4593 PetscFunctionBegin; 4594 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4595 PetscValidIntPointer(numFaceVertices, 4); 4596 switch (cellDim) { 4597 case 0: *numFaceVertices = 0; break; 4598 case 1: *numFaceVertices = 1; break; 4599 case 2: 4600 switch (numCorners) { 4601 case 3: /* triangle */ 4602 *numFaceVertices = 2; /* Edge has 2 vertices */ 4603 break; 4604 case 4: /* quadrilateral */ 4605 *numFaceVertices = 2; /* Edge has 2 vertices */ 4606 break; 4607 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4608 *numFaceVertices = 3; /* Edge has 3 vertices */ 4609 break; 4610 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4611 *numFaceVertices = 3; /* Edge has 3 vertices */ 4612 break; 4613 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4614 } 4615 break; 4616 case 3: 4617 switch (numCorners) { 4618 case 4: /* tetradehdron */ 4619 *numFaceVertices = 3; /* Face has 3 vertices */ 4620 break; 4621 case 6: /* tet cohesive cells */ 4622 *numFaceVertices = 4; /* Face has 4 vertices */ 4623 break; 4624 case 8: /* hexahedron */ 4625 *numFaceVertices = 4; /* Face has 4 vertices */ 4626 break; 4627 case 9: /* tet cohesive Lagrange cells */ 4628 *numFaceVertices = 6; /* Face has 6 vertices */ 4629 break; 4630 case 10: /* quadratic tetrahedron */ 4631 *numFaceVertices = 6; /* Face has 6 vertices */ 4632 break; 4633 case 12: /* hex cohesive Lagrange cells */ 4634 *numFaceVertices = 6; /* Face has 6 vertices */ 4635 break; 4636 case 18: /* quadratic tet cohesive Lagrange cells */ 4637 *numFaceVertices = 6; /* Face has 6 vertices */ 4638 break; 4639 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4640 *numFaceVertices = 9; /* Face has 9 vertices */ 4641 break; 4642 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4643 } 4644 break; 4645 default: SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4646 } 4647 PetscFunctionReturn(0); 4648 } 4649 4650 /*@ 4651 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4652 4653 Not Collective 4654 4655 Input Parameter: 4656 . dm - The DMPlex object 4657 4658 Output Parameter: 4659 . depthLabel - The DMLabel recording point depth 4660 4661 Level: developer 4662 4663 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4664 @*/ 4665 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) { 4666 PetscFunctionBegin; 4667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4668 PetscValidPointer(depthLabel, 2); 4669 *depthLabel = dm->depthLabel; 4670 PetscFunctionReturn(0); 4671 } 4672 4673 /*@ 4674 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4675 4676 Not Collective 4677 4678 Input Parameter: 4679 . dm - The DMPlex object 4680 4681 Output Parameter: 4682 . depth - The number of strata (breadth first levels) in the DAG 4683 4684 Level: developer 4685 4686 Notes: 4687 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4688 The point depth is described more in detail in DMPlexGetDepthStratum(). 4689 An empty mesh gives -1. 4690 4691 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4692 @*/ 4693 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) { 4694 DMLabel label; 4695 PetscInt d = 0; 4696 4697 PetscFunctionBegin; 4698 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4699 PetscValidIntPointer(depth, 2); 4700 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4701 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4702 *depth = d - 1; 4703 PetscFunctionReturn(0); 4704 } 4705 4706 /*@ 4707 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4708 4709 Not Collective 4710 4711 Input Parameters: 4712 + dm - The DMPlex object 4713 - depth - The requested depth 4714 4715 Output Parameters: 4716 + start - The first point at this depth 4717 - end - One beyond the last point at this depth 4718 4719 Notes: 4720 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4721 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4722 higher dimension, e.g., "edges". 4723 4724 Level: developer 4725 4726 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4727 @*/ 4728 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) { 4729 DMLabel label; 4730 PetscInt pStart, pEnd; 4731 4732 PetscFunctionBegin; 4733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4734 if (start) { 4735 PetscValidIntPointer(start, 3); 4736 *start = 0; 4737 } 4738 if (end) { 4739 PetscValidIntPointer(end, 4); 4740 *end = 0; 4741 } 4742 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4743 if (pStart == pEnd) PetscFunctionReturn(0); 4744 if (depth < 0) { 4745 if (start) *start = pStart; 4746 if (end) *end = pEnd; 4747 PetscFunctionReturn(0); 4748 } 4749 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4750 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4751 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4752 PetscFunctionReturn(0); 4753 } 4754 4755 /*@ 4756 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4757 4758 Not Collective 4759 4760 Input Parameters: 4761 + dm - The DMPlex object 4762 - height - The requested height 4763 4764 Output Parameters: 4765 + start - The first point at this height 4766 - end - One beyond the last point at this height 4767 4768 Notes: 4769 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4770 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4771 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4772 4773 Level: developer 4774 4775 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4776 @*/ 4777 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) { 4778 DMLabel label; 4779 PetscInt depth, pStart, pEnd; 4780 4781 PetscFunctionBegin; 4782 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4783 if (start) { 4784 PetscValidIntPointer(start, 3); 4785 *start = 0; 4786 } 4787 if (end) { 4788 PetscValidIntPointer(end, 4); 4789 *end = 0; 4790 } 4791 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4792 if (pStart == pEnd) PetscFunctionReturn(0); 4793 if (height < 0) { 4794 if (start) *start = pStart; 4795 if (end) *end = pEnd; 4796 PetscFunctionReturn(0); 4797 } 4798 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4799 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4800 PetscCall(DMLabelGetNumValues(label, &depth)); 4801 PetscCall(DMLabelGetStratumBounds(label, depth - 1 - height, start, end)); 4802 PetscFunctionReturn(0); 4803 } 4804 4805 /*@ 4806 DMPlexGetPointDepth - Get the depth of a given point 4807 4808 Not Collective 4809 4810 Input Parameters: 4811 + dm - The DMPlex object 4812 - point - The point 4813 4814 Output Parameter: 4815 . depth - The depth of the point 4816 4817 Level: intermediate 4818 4819 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4820 @*/ 4821 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) { 4822 PetscFunctionBegin; 4823 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4824 PetscValidIntPointer(depth, 3); 4825 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4826 PetscFunctionReturn(0); 4827 } 4828 4829 /*@ 4830 DMPlexGetPointHeight - Get the height of a given point 4831 4832 Not Collective 4833 4834 Input Parameters: 4835 + dm - The DMPlex object 4836 - point - The point 4837 4838 Output Parameter: 4839 . height - The height of the point 4840 4841 Level: intermediate 4842 4843 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4844 @*/ 4845 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) { 4846 PetscInt n, pDepth; 4847 4848 PetscFunctionBegin; 4849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4850 PetscValidIntPointer(height, 3); 4851 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4852 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4853 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4854 PetscFunctionReturn(0); 4855 } 4856 4857 /*@ 4858 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4859 4860 Not Collective 4861 4862 Input Parameter: 4863 . dm - The DMPlex object 4864 4865 Output Parameter: 4866 . celltypeLabel - The DMLabel recording cell polytope type 4867 4868 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4869 DMCreateLabel(dm, "celltype") beforehand. 4870 4871 Level: developer 4872 4873 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4874 @*/ 4875 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) { 4876 PetscFunctionBegin; 4877 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4878 PetscValidPointer(celltypeLabel, 2); 4879 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4880 *celltypeLabel = dm->celltypeLabel; 4881 PetscFunctionReturn(0); 4882 } 4883 4884 /*@ 4885 DMPlexGetCellType - Get the polytope type of a given cell 4886 4887 Not Collective 4888 4889 Input Parameters: 4890 + dm - The DMPlex object 4891 - cell - The cell 4892 4893 Output Parameter: 4894 . celltype - The polytope type of the cell 4895 4896 Level: intermediate 4897 4898 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4899 @*/ 4900 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) { 4901 DMLabel label; 4902 PetscInt ct; 4903 4904 PetscFunctionBegin; 4905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4906 PetscValidPointer(celltype, 3); 4907 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4908 PetscCall(DMLabelGetValue(label, cell, &ct)); 4909 PetscCheck(ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4910 *celltype = (DMPolytopeType)ct; 4911 PetscFunctionReturn(0); 4912 } 4913 4914 /*@ 4915 DMPlexSetCellType - Set the polytope type of a given cell 4916 4917 Not Collective 4918 4919 Input Parameters: 4920 + dm - The DMPlex object 4921 . cell - The cell 4922 - celltype - The polytope type of the cell 4923 4924 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4925 is executed. This function will override the computed type. However, if automatic classification will not succeed 4926 and a user wants to manually specify all types, the classification must be disabled by calling 4927 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4928 4929 Level: advanced 4930 4931 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 4932 @*/ 4933 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) { 4934 DMLabel label; 4935 4936 PetscFunctionBegin; 4937 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4938 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4939 PetscCall(DMLabelSetValue(label, cell, celltype)); 4940 PetscFunctionReturn(0); 4941 } 4942 4943 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) { 4944 PetscSection section, s; 4945 Mat m; 4946 PetscInt maxHeight; 4947 4948 PetscFunctionBegin; 4949 PetscCall(DMClone(dm, cdm)); 4950 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 4951 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 4952 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 4953 PetscCall(DMSetLocalSection(*cdm, section)); 4954 PetscCall(PetscSectionDestroy(§ion)); 4955 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 4956 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 4957 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 4958 PetscCall(PetscSectionDestroy(&s)); 4959 PetscCall(MatDestroy(&m)); 4960 4961 PetscCall(DMSetNumFields(*cdm, 1)); 4962 PetscCall(DMCreateDS(*cdm)); 4963 PetscFunctionReturn(0); 4964 } 4965 4966 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) { 4967 Vec coordsLocal, cellCoordsLocal; 4968 DM coordsDM, cellCoordsDM; 4969 4970 PetscFunctionBegin; 4971 *field = NULL; 4972 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 4973 PetscCall(DMGetCoordinateDM(dm, &coordsDM)); 4974 PetscCall(DMGetCellCoordinatesLocal(dm, &cellCoordsLocal)); 4975 PetscCall(DMGetCellCoordinateDM(dm, &cellCoordsDM)); 4976 if (coordsLocal && coordsDM) { 4977 if (cellCoordsLocal && cellCoordsDM) PetscCall(DMFieldCreateDSWithDG(coordsDM, cellCoordsDM, 0, coordsLocal, cellCoordsLocal, field)); 4978 else PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 4979 } 4980 PetscFunctionReturn(0); 4981 } 4982 4983 /*@C 4984 DMPlexGetConeSection - Return a section which describes the layout of cone data 4985 4986 Not Collective 4987 4988 Input Parameters: 4989 . dm - The DMPlex object 4990 4991 Output Parameter: 4992 . section - The PetscSection object 4993 4994 Level: developer 4995 4996 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 4997 @*/ 4998 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) { 4999 DM_Plex *mesh = (DM_Plex *)dm->data; 5000 5001 PetscFunctionBegin; 5002 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5003 if (section) *section = mesh->coneSection; 5004 PetscFunctionReturn(0); 5005 } 5006 5007 /*@C 5008 DMPlexGetSupportSection - Return a section which describes the layout of support data 5009 5010 Not Collective 5011 5012 Input Parameters: 5013 . dm - The DMPlex object 5014 5015 Output Parameter: 5016 . section - The PetscSection object 5017 5018 Level: developer 5019 5020 .seealso: `DMPlexGetConeSection()` 5021 @*/ 5022 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) { 5023 DM_Plex *mesh = (DM_Plex *)dm->data; 5024 5025 PetscFunctionBegin; 5026 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5027 if (section) *section = mesh->supportSection; 5028 PetscFunctionReturn(0); 5029 } 5030 5031 /*@C 5032 DMPlexGetCones - Return cone data 5033 5034 Not Collective 5035 5036 Input Parameters: 5037 . dm - The DMPlex object 5038 5039 Output Parameter: 5040 . cones - The cone for each point 5041 5042 Level: developer 5043 5044 .seealso: `DMPlexGetConeSection()` 5045 @*/ 5046 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) { 5047 DM_Plex *mesh = (DM_Plex *)dm->data; 5048 5049 PetscFunctionBegin; 5050 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5051 if (cones) *cones = mesh->cones; 5052 PetscFunctionReturn(0); 5053 } 5054 5055 /*@C 5056 DMPlexGetConeOrientations - Return cone orientation data 5057 5058 Not Collective 5059 5060 Input Parameters: 5061 . dm - The DMPlex object 5062 5063 Output Parameter: 5064 . coneOrientations - The array of cone orientations for all points 5065 5066 Level: developer 5067 5068 Notes: 5069 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5070 5071 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5072 5073 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5074 @*/ 5075 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) { 5076 DM_Plex *mesh = (DM_Plex *)dm->data; 5077 5078 PetscFunctionBegin; 5079 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5080 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5081 PetscFunctionReturn(0); 5082 } 5083 5084 /******************************** FEM Support **********************************/ 5085 5086 /* 5087 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5088 representing a line in the section. 5089 */ 5090 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section, PetscInt field, PetscInt line, PetscBool vertexchart, PetscInt *Nc, PetscInt *k) { 5091 PetscFunctionBeginHot; 5092 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5093 if (line < 0) { 5094 *k = 0; 5095 *Nc = 0; 5096 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5097 *k = 1; 5098 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5099 /* An order k SEM disc has k-1 dofs on an edge */ 5100 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5101 *k = *k / *Nc + 1; 5102 } 5103 PetscFunctionReturn(0); 5104 } 5105 5106 /*@ 5107 5108 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5109 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5110 section provided (or the section of the DM). 5111 5112 Input Parameters: 5113 + dm - The DM 5114 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5115 - section - The PetscSection to reorder, or NULL for the default section 5116 5117 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5118 degree of the basis. 5119 5120 Example: 5121 A typical interpolated single-quad mesh might order points as 5122 .vb 5123 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5124 5125 v4 -- e6 -- v3 5126 | | 5127 e7 c0 e8 5128 | | 5129 v1 -- e5 -- v2 5130 .ve 5131 5132 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5133 dofs in the order of points, e.g., 5134 .vb 5135 c0 -> [0,1,2,3] 5136 v1 -> [4] 5137 ... 5138 e5 -> [8, 9] 5139 .ve 5140 5141 which corresponds to the dofs 5142 .vb 5143 6 10 11 7 5144 13 2 3 15 5145 12 0 1 14 5146 4 8 9 5 5147 .ve 5148 5149 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5150 .vb 5151 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5152 .ve 5153 5154 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5155 .vb 5156 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5157 .ve 5158 5159 Level: developer 5160 5161 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5162 @*/ 5163 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) { 5164 DMLabel label; 5165 PetscInt dim, depth = -1, eStart = -1, Nf; 5166 PetscBool vertexchart; 5167 5168 PetscFunctionBegin; 5169 PetscCall(DMGetDimension(dm, &dim)); 5170 if (dim < 1) PetscFunctionReturn(0); 5171 if (point < 0) { 5172 PetscInt sStart, sEnd; 5173 5174 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5175 point = sEnd - sStart ? sStart : point; 5176 } 5177 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5178 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5179 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5180 if (depth == 1) { 5181 eStart = point; 5182 } else if (depth == dim) { 5183 const PetscInt *cone; 5184 5185 PetscCall(DMPlexGetCone(dm, point, &cone)); 5186 if (dim == 2) eStart = cone[0]; 5187 else if (dim == 3) { 5188 const PetscInt *cone2; 5189 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5190 eStart = cone2[0]; 5191 } 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); 5192 } 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); 5193 { /* Determine whether the chart covers all points or just vertices. */ 5194 PetscInt pStart, pEnd, cStart, cEnd; 5195 PetscCall(DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd)); 5196 PetscCall(PetscSectionGetChart(section, &cStart, &cEnd)); 5197 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5198 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5199 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5200 } 5201 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5202 for (PetscInt d = 1; d <= dim; d++) { 5203 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5204 PetscInt *perm; 5205 5206 for (f = 0; f < Nf; ++f) { 5207 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5208 size += PetscPowInt(k + 1, d) * Nc; 5209 } 5210 PetscCall(PetscMalloc1(size, &perm)); 5211 for (f = 0; f < Nf; ++f) { 5212 switch (d) { 5213 case 1: 5214 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5215 /* 5216 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5217 We want [ vtx0; edge of length k-1; vtx1 ] 5218 */ 5219 for (c = 0; c < Nc; c++, offset++) perm[offset] = (k - 1) * Nc + c + foffset; 5220 for (i = 0; i < k - 1; i++) 5221 for (c = 0; c < Nc; c++, offset++) perm[offset] = i * Nc + c + foffset; 5222 for (c = 0; c < Nc; c++, offset++) perm[offset] = k * Nc + c + foffset; 5223 foffset = offset; 5224 break; 5225 case 2: 5226 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5227 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5228 /* The SEM order is 5229 5230 v_lb, {e_b}, v_rb, 5231 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5232 v_lt, reverse {e_t}, v_rt 5233 */ 5234 { 5235 const PetscInt of = 0; 5236 const PetscInt oeb = of + PetscSqr(k - 1); 5237 const PetscInt oer = oeb + (k - 1); 5238 const PetscInt oet = oer + (k - 1); 5239 const PetscInt oel = oet + (k - 1); 5240 const PetscInt ovlb = oel + (k - 1); 5241 const PetscInt ovrb = ovlb + 1; 5242 const PetscInt ovrt = ovrb + 1; 5243 const PetscInt ovlt = ovrt + 1; 5244 PetscInt o; 5245 5246 /* bottom */ 5247 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb * Nc + c + foffset; 5248 for (o = oeb; o < oer; ++o) 5249 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5250 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb * Nc + c + foffset; 5251 /* middle */ 5252 for (i = 0; i < k - 1; ++i) { 5253 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel + (k - 2) - i) * Nc + c + foffset; 5254 for (o = of + (k - 1) * i; o < of + (k - 1) * (i + 1); ++o) 5255 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5256 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer + i) * Nc + c + foffset; 5257 } 5258 /* top */ 5259 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt * Nc + c + foffset; 5260 for (o = oel - 1; o >= oet; --o) 5261 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5262 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt * Nc + c + foffset; 5263 foffset = offset; 5264 } 5265 break; 5266 case 3: 5267 /* The original hex closure is 5268 5269 {c, 5270 f_b, f_t, f_f, f_b, f_r, f_l, 5271 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5272 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5273 */ 5274 PetscCall(PetscSectionFieldGetTensorDegree_Private(section, f, eStart, vertexchart, &Nc, &k)); 5275 /* The SEM order is 5276 Bottom Slice 5277 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5278 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5279 v_blb, {e_bb}, v_brb, 5280 5281 Middle Slice (j) 5282 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5283 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5284 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5285 5286 Top Slice 5287 v_tlf, {e_tf}, v_trf, 5288 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5289 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5290 */ 5291 { 5292 const PetscInt oc = 0; 5293 const PetscInt ofb = oc + PetscSqr(k - 1) * (k - 1); 5294 const PetscInt oft = ofb + PetscSqr(k - 1); 5295 const PetscInt off = oft + PetscSqr(k - 1); 5296 const PetscInt ofk = off + PetscSqr(k - 1); 5297 const PetscInt ofr = ofk + PetscSqr(k - 1); 5298 const PetscInt ofl = ofr + PetscSqr(k - 1); 5299 const PetscInt oebl = ofl + PetscSqr(k - 1); 5300 const PetscInt oebb = oebl + (k - 1); 5301 const PetscInt oebr = oebb + (k - 1); 5302 const PetscInt oebf = oebr + (k - 1); 5303 const PetscInt oetf = oebf + (k - 1); 5304 const PetscInt oetr = oetf + (k - 1); 5305 const PetscInt oetb = oetr + (k - 1); 5306 const PetscInt oetl = oetb + (k - 1); 5307 const PetscInt oerf = oetl + (k - 1); 5308 const PetscInt oelf = oerf + (k - 1); 5309 const PetscInt oelb = oelf + (k - 1); 5310 const PetscInt oerb = oelb + (k - 1); 5311 const PetscInt ovblf = oerb + (k - 1); 5312 const PetscInt ovblb = ovblf + 1; 5313 const PetscInt ovbrb = ovblb + 1; 5314 const PetscInt ovbrf = ovbrb + 1; 5315 const PetscInt ovtlf = ovbrf + 1; 5316 const PetscInt ovtrf = ovtlf + 1; 5317 const PetscInt ovtrb = ovtrf + 1; 5318 const PetscInt ovtlb = ovtrb + 1; 5319 PetscInt o, n; 5320 5321 /* Bottom Slice */ 5322 /* bottom */ 5323 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf * Nc + c + foffset; 5324 for (o = oetf - 1; o >= oebf; --o) 5325 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5326 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf * Nc + c + foffset; 5327 /* middle */ 5328 for (i = 0; i < k - 1; ++i) { 5329 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl + i) * Nc + c + foffset; 5330 for (n = 0; n < k - 1; ++n) { 5331 o = ofb + n * (k - 1) + i; 5332 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5333 } 5334 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr + (k - 2) - i) * Nc + c + foffset; 5335 } 5336 /* top */ 5337 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb * Nc + c + foffset; 5338 for (o = oebb; o < oebr; ++o) 5339 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5340 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb * Nc + c + foffset; 5341 5342 /* Middle Slice */ 5343 for (j = 0; j < k - 1; ++j) { 5344 /* bottom */ 5345 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf + (k - 2) - j) * Nc + c + foffset; 5346 for (o = off + j * (k - 1); o < off + (j + 1) * (k - 1); ++o) 5347 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5348 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf + j) * Nc + c + foffset; 5349 /* middle */ 5350 for (i = 0; i < k - 1; ++i) { 5351 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl + i * (k - 1) + j) * Nc + c + foffset; 5352 for (n = 0; n < k - 1; ++n) 5353 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc + (j * (k - 1) + i) * (k - 1) + n) * Nc + c + foffset; 5354 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr + j * (k - 1) + i) * Nc + c + foffset; 5355 } 5356 /* top */ 5357 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb + j) * Nc + c + foffset; 5358 for (o = ofk + j * (k - 1) + (k - 2); o >= ofk + j * (k - 1); --o) 5359 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5360 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb + (k - 2) - j) * Nc + c + foffset; 5361 } 5362 5363 /* Top Slice */ 5364 /* bottom */ 5365 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf * Nc + c + foffset; 5366 for (o = oetf; o < oetr; ++o) 5367 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5368 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf * Nc + c + foffset; 5369 /* middle */ 5370 for (i = 0; i < k - 1; ++i) { 5371 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl + (k - 2) - i) * Nc + c + foffset; 5372 for (n = 0; n < k - 1; ++n) 5373 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft + i * (k - 1) + n) * Nc + c + foffset; 5374 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr + i) * Nc + c + foffset; 5375 } 5376 /* top */ 5377 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb * Nc + c + foffset; 5378 for (o = oetl - 1; o >= oetb; --o) 5379 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o * Nc + c + foffset; 5380 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb * Nc + c + foffset; 5381 5382 foffset = offset; 5383 } 5384 break; 5385 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5386 } 5387 } 5388 PetscCheck(offset == size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5389 /* Check permutation */ 5390 { 5391 PetscInt *check; 5392 5393 PetscCall(PetscMalloc1(size, &check)); 5394 for (i = 0; i < size; ++i) { 5395 check[i] = -1; 5396 PetscCheck(perm[i] >= 0 && perm[i] < size, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5397 } 5398 for (i = 0; i < size; ++i) check[perm[i]] = i; 5399 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5400 PetscCall(PetscFree(check)); 5401 } 5402 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size, PETSC_OWN_POINTER, perm)); 5403 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5404 PetscInt *loc_perm; 5405 PetscCall(PetscMalloc1(size * 2, &loc_perm)); 5406 for (PetscInt i = 0; i < size; i++) { 5407 loc_perm[i] = perm[i]; 5408 loc_perm[size + i] = size + perm[i]; 5409 } 5410 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject)dm, d, size * 2, PETSC_OWN_POINTER, loc_perm)); 5411 } 5412 } 5413 PetscFunctionReturn(0); 5414 } 5415 5416 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) { 5417 PetscDS prob; 5418 PetscInt depth, Nf, h; 5419 DMLabel label; 5420 5421 PetscFunctionBeginHot; 5422 PetscCall(DMGetDS(dm, &prob)); 5423 Nf = prob->Nf; 5424 label = dm->depthLabel; 5425 *dspace = NULL; 5426 if (field < Nf) { 5427 PetscObject disc = prob->disc[field]; 5428 5429 if (disc->classid == PETSCFE_CLASSID) { 5430 PetscDualSpace dsp; 5431 5432 PetscCall(PetscFEGetDualSpace((PetscFE)disc, &dsp)); 5433 PetscCall(DMLabelGetNumValues(label, &depth)); 5434 PetscCall(DMLabelGetValue(label, point, &h)); 5435 h = depth - 1 - h; 5436 if (h) { 5437 PetscCall(PetscDualSpaceGetHeightSubspace(dsp, h, dspace)); 5438 } else { 5439 *dspace = dsp; 5440 } 5441 } 5442 } 5443 PetscFunctionReturn(0); 5444 } 5445 5446 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5447 PetscScalar *array; 5448 const PetscScalar *vArray; 5449 const PetscInt *cone, *coneO; 5450 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5451 5452 PetscFunctionBeginHot; 5453 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5454 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5455 PetscCall(DMPlexGetCone(dm, point, &cone)); 5456 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5457 if (!values || !*values) { 5458 if ((point >= pStart) && (point < pEnd)) { 5459 PetscInt dof; 5460 5461 PetscCall(PetscSectionGetDof(section, point, &dof)); 5462 size += dof; 5463 } 5464 for (p = 0; p < numPoints; ++p) { 5465 const PetscInt cp = cone[p]; 5466 PetscInt dof; 5467 5468 if ((cp < pStart) || (cp >= pEnd)) continue; 5469 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5470 size += dof; 5471 } 5472 if (!values) { 5473 if (csize) *csize = size; 5474 PetscFunctionReturn(0); 5475 } 5476 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5477 } else { 5478 array = *values; 5479 } 5480 size = 0; 5481 PetscCall(VecGetArrayRead(v, &vArray)); 5482 if ((point >= pStart) && (point < pEnd)) { 5483 PetscInt dof, off, d; 5484 const PetscScalar *varr; 5485 5486 PetscCall(PetscSectionGetDof(section, point, &dof)); 5487 PetscCall(PetscSectionGetOffset(section, point, &off)); 5488 varr = &vArray[off]; 5489 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5490 size += dof; 5491 } 5492 for (p = 0; p < numPoints; ++p) { 5493 const PetscInt cp = cone[p]; 5494 PetscInt o = coneO[p]; 5495 PetscInt dof, off, d; 5496 const PetscScalar *varr; 5497 5498 if ((cp < pStart) || (cp >= pEnd)) continue; 5499 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5500 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5501 varr = &vArray[off]; 5502 if (o >= 0) { 5503 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 5504 } else { 5505 for (d = dof - 1; d >= 0; --d, ++offset) array[offset] = varr[d]; 5506 } 5507 size += dof; 5508 } 5509 PetscCall(VecRestoreArrayRead(v, &vArray)); 5510 if (!*values) { 5511 if (csize) *csize = size; 5512 *values = array; 5513 } else { 5514 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5515 *csize = size; 5516 } 5517 PetscFunctionReturn(0); 5518 } 5519 5520 /* Compress out points not in the section */ 5521 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) { 5522 const PetscInt np = *numPoints; 5523 PetscInt pStart, pEnd, p, q; 5524 5525 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5526 for (p = 0, q = 0; p < np; ++p) { 5527 const PetscInt r = points[p * 2]; 5528 if ((r >= pStart) && (r < pEnd)) { 5529 points[q * 2] = r; 5530 points[q * 2 + 1] = points[p * 2 + 1]; 5531 ++q; 5532 } 5533 } 5534 *numPoints = q; 5535 return 0; 5536 } 5537 5538 /* Compressed closure does not apply closure permutation */ 5539 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5540 const PetscInt *cla = NULL; 5541 PetscInt np, *pts = NULL; 5542 5543 PetscFunctionBeginHot; 5544 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject)dm, clSec, clPoints)); 5545 if (*clPoints) { 5546 PetscInt dof, off; 5547 5548 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5549 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5550 PetscCall(ISGetIndices(*clPoints, &cla)); 5551 np = dof / 2; 5552 pts = (PetscInt *)&cla[off]; 5553 } else { 5554 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5555 PetscCall(CompressPoints_Private(section, &np, pts)); 5556 } 5557 *numPoints = np; 5558 *points = pts; 5559 *clp = cla; 5560 PetscFunctionReturn(0); 5561 } 5562 5563 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) { 5564 PetscFunctionBeginHot; 5565 if (!*clPoints) { 5566 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5567 } else { 5568 PetscCall(ISRestoreIndices(*clPoints, clp)); 5569 } 5570 *numPoints = 0; 5571 *points = NULL; 5572 *clSec = NULL; 5573 *clPoints = NULL; 5574 *clp = NULL; 5575 PetscFunctionReturn(0); 5576 } 5577 5578 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) { 5579 PetscInt offset = 0, p; 5580 const PetscInt **perms = NULL; 5581 const PetscScalar **flips = NULL; 5582 5583 PetscFunctionBeginHot; 5584 *size = 0; 5585 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 5586 for (p = 0; p < numPoints; p++) { 5587 const PetscInt point = points[2 * p]; 5588 const PetscInt *perm = perms ? perms[p] : NULL; 5589 const PetscScalar *flip = flips ? flips[p] : NULL; 5590 PetscInt dof, off, d; 5591 const PetscScalar *varr; 5592 5593 PetscCall(PetscSectionGetDof(section, point, &dof)); 5594 PetscCall(PetscSectionGetOffset(section, point, &off)); 5595 varr = &vArray[off]; 5596 if (clperm) { 5597 if (perm) { 5598 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5599 } else { 5600 for (d = 0; d < dof; d++) array[clperm[offset + d]] = varr[d]; 5601 } 5602 if (flip) { 5603 for (d = 0; d < dof; d++) array[clperm[offset + d]] *= flip[d]; 5604 } 5605 } else { 5606 if (perm) { 5607 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5608 } else { 5609 for (d = 0; d < dof; d++) array[offset + d] = varr[d]; 5610 } 5611 if (flip) { 5612 for (d = 0; d < dof; d++) array[offset + d] *= flip[d]; 5613 } 5614 } 5615 offset += dof; 5616 } 5617 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 5618 *size = offset; 5619 PetscFunctionReturn(0); 5620 } 5621 5622 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[]) { 5623 PetscInt offset = 0, f; 5624 5625 PetscFunctionBeginHot; 5626 *size = 0; 5627 for (f = 0; f < numFields; ++f) { 5628 PetscInt p; 5629 const PetscInt **perms = NULL; 5630 const PetscScalar **flips = NULL; 5631 5632 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5633 for (p = 0; p < numPoints; p++) { 5634 const PetscInt point = points[2 * p]; 5635 PetscInt fdof, foff, b; 5636 const PetscScalar *varr; 5637 const PetscInt *perm = perms ? perms[p] : NULL; 5638 const PetscScalar *flip = flips ? flips[p] : NULL; 5639 5640 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5641 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5642 varr = &vArray[foff]; 5643 if (clperm) { 5644 if (perm) { 5645 for (b = 0; b < fdof; b++) array[clperm[offset + perm[b]]] = varr[b]; 5646 } else { 5647 for (b = 0; b < fdof; b++) array[clperm[offset + b]] = varr[b]; 5648 } 5649 if (flip) { 5650 for (b = 0; b < fdof; b++) array[clperm[offset + b]] *= flip[b]; 5651 } 5652 } else { 5653 if (perm) { 5654 for (b = 0; b < fdof; b++) array[offset + perm[b]] = varr[b]; 5655 } else { 5656 for (b = 0; b < fdof; b++) array[offset + b] = varr[b]; 5657 } 5658 if (flip) { 5659 for (b = 0; b < fdof; b++) array[offset + b] *= flip[b]; 5660 } 5661 } 5662 offset += fdof; 5663 } 5664 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 5665 } 5666 *size = offset; 5667 PetscFunctionReturn(0); 5668 } 5669 5670 /*@C 5671 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5672 5673 Not collective 5674 5675 Input Parameters: 5676 + dm - The DM 5677 . section - The section describing the layout in v, or NULL to use the default section 5678 . v - The local vector 5679 - point - The point in the DM 5680 5681 Input/Output Parameters: 5682 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5683 - values - An array to use for the values, or NULL to have it allocated automatically; 5684 if the user provided NULL, it is a borrowed array and should not be freed 5685 5686 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5687 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5688 $ assembly function, and a user may already have allocated storage for this operation. 5689 $ 5690 $ A typical use could be 5691 $ 5692 $ values = NULL; 5693 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5694 $ for (cl = 0; cl < clSize; ++cl) { 5695 $ <Compute on closure> 5696 $ } 5697 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5698 $ 5699 $ or 5700 $ 5701 $ PetscMalloc1(clMaxSize, &values); 5702 $ for (p = pStart; p < pEnd; ++p) { 5703 $ clSize = clMaxSize; 5704 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5705 $ for (cl = 0; cl < clSize; ++cl) { 5706 $ <Compute on closure> 5707 $ } 5708 $ } 5709 $ PetscFree(values); 5710 5711 Fortran Notes: 5712 Since it returns an array, this routine is only available in Fortran 90, and you must 5713 include petsc.h90 in your code. 5714 5715 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5716 5717 Level: intermediate 5718 5719 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5720 @*/ 5721 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5722 PetscSection clSection; 5723 IS clPoints; 5724 PetscInt *points = NULL; 5725 const PetscInt *clp, *perm; 5726 PetscInt depth, numFields, numPoints, asize; 5727 5728 PetscFunctionBeginHot; 5729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5730 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5731 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5732 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5733 PetscCall(DMPlexGetDepth(dm, &depth)); 5734 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5735 if (depth == 1 && numFields < 2) { 5736 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5737 PetscFunctionReturn(0); 5738 } 5739 /* Get points */ 5740 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5741 /* Get sizes */ 5742 asize = 0; 5743 for (PetscInt p = 0; p < numPoints * 2; p += 2) { 5744 PetscInt dof; 5745 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5746 asize += dof; 5747 } 5748 if (values) { 5749 const PetscScalar *vArray; 5750 PetscInt size; 5751 5752 if (*values) { 5753 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); 5754 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5755 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, asize, &perm)); 5756 PetscCall(VecGetArrayRead(v, &vArray)); 5757 /* Get values */ 5758 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5759 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5760 PetscCheck(asize == size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5761 /* Cleanup array */ 5762 PetscCall(VecRestoreArrayRead(v, &vArray)); 5763 } 5764 if (csize) *csize = asize; 5765 /* Cleanup points */ 5766 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5767 PetscFunctionReturn(0); 5768 } 5769 5770 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) { 5771 DMLabel depthLabel; 5772 PetscSection clSection; 5773 IS clPoints; 5774 PetscScalar *array; 5775 const PetscScalar *vArray; 5776 PetscInt *points = NULL; 5777 const PetscInt *clp, *perm = NULL; 5778 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5779 5780 PetscFunctionBeginHot; 5781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5782 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5783 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5784 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5785 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5786 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5787 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5788 if (mdepth == 1 && numFields < 2) { 5789 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5790 PetscFunctionReturn(0); 5791 } 5792 /* Get points */ 5793 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5794 for (clsize = 0, p = 0; p < Np; p++) { 5795 PetscInt dof; 5796 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 5797 clsize += dof; 5798 } 5799 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &perm)); 5800 /* Filter points */ 5801 for (p = 0; p < numPoints * 2; p += 2) { 5802 PetscInt dep; 5803 5804 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5805 if (dep != depth) continue; 5806 points[Np * 2 + 0] = points[p]; 5807 points[Np * 2 + 1] = points[p + 1]; 5808 ++Np; 5809 } 5810 /* Get array */ 5811 if (!values || !*values) { 5812 PetscInt asize = 0, dof; 5813 5814 for (p = 0; p < Np * 2; p += 2) { 5815 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5816 asize += dof; 5817 } 5818 if (!values) { 5819 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5820 if (csize) *csize = asize; 5821 PetscFunctionReturn(0); 5822 } 5823 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5824 } else { 5825 array = *values; 5826 } 5827 PetscCall(VecGetArrayRead(v, &vArray)); 5828 /* Get values */ 5829 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5830 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5831 /* Cleanup points */ 5832 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 5833 /* Cleanup array */ 5834 PetscCall(VecRestoreArrayRead(v, &vArray)); 5835 if (!*values) { 5836 if (csize) *csize = size; 5837 *values = array; 5838 } else { 5839 PetscCheck(size <= *csize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5840 *csize = size; 5841 } 5842 PetscFunctionReturn(0); 5843 } 5844 5845 /*@C 5846 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5847 5848 Not collective 5849 5850 Input Parameters: 5851 + dm - The DM 5852 . section - The section describing the layout in v, or NULL to use the default section 5853 . v - The local vector 5854 . point - The point in the DM 5855 . csize - The number of values in the closure, or NULL 5856 - values - The array of values, which is a borrowed array and should not be freed 5857 5858 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5859 5860 Fortran Notes: 5861 Since it returns an array, this routine is only available in Fortran 90, and you must 5862 include petsc.h90 in your code. 5863 5864 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5865 5866 Level: intermediate 5867 5868 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5869 @*/ 5870 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) { 5871 PetscInt size = 0; 5872 5873 PetscFunctionBegin; 5874 /* Should work without recalculating size */ 5875 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void *)values)); 5876 *values = NULL; 5877 PetscFunctionReturn(0); 5878 } 5879 5880 static inline void add(PetscScalar *x, PetscScalar y) { 5881 *x += y; 5882 } 5883 static inline void insert(PetscScalar *x, PetscScalar y) { 5884 *x = y; 5885 } 5886 5887 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[]) { 5888 PetscInt cdof; /* The number of constraints on this point */ 5889 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5890 PetscScalar *a; 5891 PetscInt off, cind = 0, k; 5892 5893 PetscFunctionBegin; 5894 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5895 PetscCall(PetscSectionGetOffset(section, point, &off)); 5896 a = &array[off]; 5897 if (!cdof || setBC) { 5898 if (clperm) { 5899 if (perm) { 5900 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5901 } else { 5902 for (k = 0; k < dof; ++k) fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5903 } 5904 } else { 5905 if (perm) { 5906 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5907 } else { 5908 for (k = 0; k < dof; ++k) fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5909 } 5910 } 5911 } else { 5912 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5913 if (clperm) { 5914 if (perm) { 5915 for (k = 0; k < dof; ++k) { 5916 if ((cind < cdof) && (k == cdofs[cind])) { 5917 ++cind; 5918 continue; 5919 } 5920 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5921 } 5922 } else { 5923 for (k = 0; k < dof; ++k) { 5924 if ((cind < cdof) && (k == cdofs[cind])) { 5925 ++cind; 5926 continue; 5927 } 5928 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5929 } 5930 } 5931 } else { 5932 if (perm) { 5933 for (k = 0; k < dof; ++k) { 5934 if ((cind < cdof) && (k == cdofs[cind])) { 5935 ++cind; 5936 continue; 5937 } 5938 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5939 } 5940 } else { 5941 for (k = 0; k < dof; ++k) { 5942 if ((cind < cdof) && (k == cdofs[cind])) { 5943 ++cind; 5944 continue; 5945 } 5946 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5947 } 5948 } 5949 } 5950 } 5951 PetscFunctionReturn(0); 5952 } 5953 5954 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[]) { 5955 PetscInt cdof; /* The number of constraints on this point */ 5956 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5957 PetscScalar *a; 5958 PetscInt off, cind = 0, k; 5959 5960 PetscFunctionBegin; 5961 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5962 PetscCall(PetscSectionGetOffset(section, point, &off)); 5963 a = &array[off]; 5964 if (cdof) { 5965 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5966 if (clperm) { 5967 if (perm) { 5968 for (k = 0; k < dof; ++k) { 5969 if ((cind < cdof) && (k == cdofs[cind])) { 5970 fuse(&a[k], values[clperm[offset + perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5971 cind++; 5972 } 5973 } 5974 } else { 5975 for (k = 0; k < dof; ++k) { 5976 if ((cind < cdof) && (k == cdofs[cind])) { 5977 fuse(&a[k], values[clperm[offset + k]] * (flip ? flip[k] : 1.)); 5978 cind++; 5979 } 5980 } 5981 } 5982 } else { 5983 if (perm) { 5984 for (k = 0; k < dof; ++k) { 5985 if ((cind < cdof) && (k == cdofs[cind])) { 5986 fuse(&a[k], values[offset + perm[k]] * (flip ? flip[perm[k]] : 1.)); 5987 cind++; 5988 } 5989 } 5990 } else { 5991 for (k = 0; k < dof; ++k) { 5992 if ((cind < cdof) && (k == cdofs[cind])) { 5993 fuse(&a[k], values[offset + k] * (flip ? flip[k] : 1.)); 5994 cind++; 5995 } 5996 } 5997 } 5998 } 5999 } 6000 PetscFunctionReturn(0); 6001 } 6002 6003 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[]) { 6004 PetscScalar *a; 6005 PetscInt fdof, foff, fcdof, foffset = *offset; 6006 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6007 PetscInt cind = 0, b; 6008 6009 PetscFunctionBegin; 6010 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6011 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6012 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6013 a = &array[foff]; 6014 if (!fcdof || setBC) { 6015 if (clperm) { 6016 if (perm) { 6017 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6018 } else { 6019 for (b = 0; b < fdof; b++) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6020 } 6021 } else { 6022 if (perm) { 6023 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6024 } else { 6025 for (b = 0; b < fdof; b++) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6026 } 6027 } 6028 } else { 6029 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6030 if (clperm) { 6031 if (perm) { 6032 for (b = 0; b < fdof; b++) { 6033 if ((cind < fcdof) && (b == fcdofs[cind])) { 6034 ++cind; 6035 continue; 6036 } 6037 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6038 } 6039 } else { 6040 for (b = 0; b < fdof; b++) { 6041 if ((cind < fcdof) && (b == fcdofs[cind])) { 6042 ++cind; 6043 continue; 6044 } 6045 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6046 } 6047 } 6048 } else { 6049 if (perm) { 6050 for (b = 0; b < fdof; b++) { 6051 if ((cind < fcdof) && (b == fcdofs[cind])) { 6052 ++cind; 6053 continue; 6054 } 6055 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6056 } 6057 } else { 6058 for (b = 0; b < fdof; b++) { 6059 if ((cind < fcdof) && (b == fcdofs[cind])) { 6060 ++cind; 6061 continue; 6062 } 6063 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6064 } 6065 } 6066 } 6067 } 6068 *offset += fdof; 6069 PetscFunctionReturn(0); 6070 } 6071 6072 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[]) { 6073 PetscScalar *a; 6074 PetscInt fdof, foff, fcdof, foffset = *offset; 6075 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6076 PetscInt Nc, cind = 0, ncind = 0, b; 6077 PetscBool ncSet, fcSet; 6078 6079 PetscFunctionBegin; 6080 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6081 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6082 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6083 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6084 a = &array[foff]; 6085 if (fcdof) { 6086 /* We just override fcdof and fcdofs with Ncc and comps */ 6087 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6088 if (clperm) { 6089 if (perm) { 6090 if (comps) { 6091 for (b = 0; b < fdof; b++) { 6092 ncSet = fcSet = PETSC_FALSE; 6093 if (b % Nc == comps[ncind]) { 6094 ncind = (ncind + 1) % Ncc; 6095 ncSet = PETSC_TRUE; 6096 } 6097 if ((cind < fcdof) && (b == fcdofs[cind])) { 6098 ++cind; 6099 fcSet = PETSC_TRUE; 6100 } 6101 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6102 } 6103 } else { 6104 for (b = 0; b < fdof; b++) { 6105 if ((cind < fcdof) && (b == fcdofs[cind])) { 6106 fuse(&a[b], values[clperm[foffset + perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6107 ++cind; 6108 } 6109 } 6110 } 6111 } else { 6112 if (comps) { 6113 for (b = 0; b < fdof; b++) { 6114 ncSet = fcSet = PETSC_FALSE; 6115 if (b % Nc == comps[ncind]) { 6116 ncind = (ncind + 1) % Ncc; 6117 ncSet = PETSC_TRUE; 6118 } 6119 if ((cind < fcdof) && (b == fcdofs[cind])) { 6120 ++cind; 6121 fcSet = PETSC_TRUE; 6122 } 6123 if (ncSet && fcSet) fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6124 } 6125 } else { 6126 for (b = 0; b < fdof; b++) { 6127 if ((cind < fcdof) && (b == fcdofs[cind])) { 6128 fuse(&a[b], values[clperm[foffset + b]] * (flip ? flip[b] : 1.)); 6129 ++cind; 6130 } 6131 } 6132 } 6133 } 6134 } else { 6135 if (perm) { 6136 if (comps) { 6137 for (b = 0; b < fdof; b++) { 6138 ncSet = fcSet = PETSC_FALSE; 6139 if (b % Nc == comps[ncind]) { 6140 ncind = (ncind + 1) % Ncc; 6141 ncSet = PETSC_TRUE; 6142 } 6143 if ((cind < fcdof) && (b == fcdofs[cind])) { 6144 ++cind; 6145 fcSet = PETSC_TRUE; 6146 } 6147 if (ncSet && fcSet) fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6148 } 6149 } else { 6150 for (b = 0; b < fdof; b++) { 6151 if ((cind < fcdof) && (b == fcdofs[cind])) { 6152 fuse(&a[b], values[foffset + perm[b]] * (flip ? flip[perm[b]] : 1.)); 6153 ++cind; 6154 } 6155 } 6156 } 6157 } else { 6158 if (comps) { 6159 for (b = 0; b < fdof; b++) { 6160 ncSet = fcSet = PETSC_FALSE; 6161 if (b % Nc == comps[ncind]) { 6162 ncind = (ncind + 1) % Ncc; 6163 ncSet = PETSC_TRUE; 6164 } 6165 if ((cind < fcdof) && (b == fcdofs[cind])) { 6166 ++cind; 6167 fcSet = PETSC_TRUE; 6168 } 6169 if (ncSet && fcSet) fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6170 } 6171 } else { 6172 for (b = 0; b < fdof; b++) { 6173 if ((cind < fcdof) && (b == fcdofs[cind])) { 6174 fuse(&a[b], values[foffset + b] * (flip ? flip[b] : 1.)); 6175 ++cind; 6176 } 6177 } 6178 } 6179 } 6180 } 6181 } 6182 *offset += fdof; 6183 PetscFunctionReturn(0); 6184 } 6185 6186 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6187 PetscScalar *array; 6188 const PetscInt *cone, *coneO; 6189 PetscInt pStart, pEnd, p, numPoints, off, dof; 6190 6191 PetscFunctionBeginHot; 6192 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6193 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6194 PetscCall(DMPlexGetCone(dm, point, &cone)); 6195 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6196 PetscCall(VecGetArray(v, &array)); 6197 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6198 const PetscInt cp = !p ? point : cone[p - 1]; 6199 const PetscInt o = !p ? 0 : coneO[p - 1]; 6200 6201 if ((cp < pStart) || (cp >= pEnd)) { 6202 dof = 0; 6203 continue; 6204 } 6205 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6206 /* ADD_VALUES */ 6207 { 6208 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6209 PetscScalar *a; 6210 PetscInt cdof, coff, cind = 0, k; 6211 6212 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6213 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6214 a = &array[coff]; 6215 if (!cdof) { 6216 if (o >= 0) { 6217 for (k = 0; k < dof; ++k) a[k] += values[off + k]; 6218 } else { 6219 for (k = 0; k < dof; ++k) a[k] += values[off + dof - k - 1]; 6220 } 6221 } else { 6222 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6223 if (o >= 0) { 6224 for (k = 0; k < dof; ++k) { 6225 if ((cind < cdof) && (k == cdofs[cind])) { 6226 ++cind; 6227 continue; 6228 } 6229 a[k] += values[off + k]; 6230 } 6231 } else { 6232 for (k = 0; k < dof; ++k) { 6233 if ((cind < cdof) && (k == cdofs[cind])) { 6234 ++cind; 6235 continue; 6236 } 6237 a[k] += values[off + dof - k - 1]; 6238 } 6239 } 6240 } 6241 } 6242 } 6243 PetscCall(VecRestoreArray(v, &array)); 6244 PetscFunctionReturn(0); 6245 } 6246 6247 /*@C 6248 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6249 6250 Not collective 6251 6252 Input Parameters: 6253 + dm - The DM 6254 . section - The section describing the layout in v, or NULL to use the default section 6255 . v - The local vector 6256 . point - The point in the DM 6257 . values - The array of values 6258 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6259 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6260 6261 Fortran Notes: 6262 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6263 6264 Level: intermediate 6265 6266 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6267 @*/ 6268 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) { 6269 PetscSection clSection; 6270 IS clPoints; 6271 PetscScalar *array; 6272 PetscInt *points = NULL; 6273 const PetscInt *clp, *clperm = NULL; 6274 PetscInt depth, numFields, numPoints, p, clsize; 6275 6276 PetscFunctionBeginHot; 6277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6278 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6279 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6280 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6281 PetscCall(DMPlexGetDepth(dm, &depth)); 6282 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6283 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6284 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6285 PetscFunctionReturn(0); 6286 } 6287 /* Get points */ 6288 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6289 for (clsize = 0, p = 0; p < numPoints; p++) { 6290 PetscInt dof; 6291 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 6292 clsize += dof; 6293 } 6294 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 6295 /* Get array */ 6296 PetscCall(VecGetArray(v, &array)); 6297 /* Get values */ 6298 if (numFields > 0) { 6299 PetscInt offset = 0, f; 6300 for (f = 0; f < numFields; ++f) { 6301 const PetscInt **perms = NULL; 6302 const PetscScalar **flips = NULL; 6303 6304 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6305 switch (mode) { 6306 case INSERT_VALUES: 6307 for (p = 0; p < numPoints; p++) { 6308 const PetscInt point = points[2 * p]; 6309 const PetscInt *perm = perms ? perms[p] : NULL; 6310 const PetscScalar *flip = flips ? flips[p] : NULL; 6311 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6312 } 6313 break; 6314 case INSERT_ALL_VALUES: 6315 for (p = 0; p < numPoints; p++) { 6316 const PetscInt point = points[2 * p]; 6317 const PetscInt *perm = perms ? perms[p] : NULL; 6318 const PetscScalar *flip = flips ? flips[p] : NULL; 6319 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6320 } 6321 break; 6322 case INSERT_BC_VALUES: 6323 for (p = 0; p < numPoints; p++) { 6324 const PetscInt point = points[2 * p]; 6325 const PetscInt *perm = perms ? perms[p] : NULL; 6326 const PetscScalar *flip = flips ? flips[p] : NULL; 6327 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6328 } 6329 break; 6330 case ADD_VALUES: 6331 for (p = 0; p < numPoints; p++) { 6332 const PetscInt point = points[2 * p]; 6333 const PetscInt *perm = perms ? perms[p] : NULL; 6334 const PetscScalar *flip = flips ? flips[p] : NULL; 6335 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6336 } 6337 break; 6338 case ADD_ALL_VALUES: 6339 for (p = 0; p < numPoints; p++) { 6340 const PetscInt point = points[2 * p]; 6341 const PetscInt *perm = perms ? perms[p] : NULL; 6342 const PetscScalar *flip = flips ? flips[p] : NULL; 6343 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6344 } 6345 break; 6346 case ADD_BC_VALUES: 6347 for (p = 0; p < numPoints; p++) { 6348 const PetscInt point = points[2 * p]; 6349 const PetscInt *perm = perms ? perms[p] : NULL; 6350 const PetscScalar *flip = flips ? flips[p] : NULL; 6351 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6352 } 6353 break; 6354 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6355 } 6356 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6357 } 6358 } else { 6359 PetscInt dof, off; 6360 const PetscInt **perms = NULL; 6361 const PetscScalar **flips = NULL; 6362 6363 PetscCall(PetscSectionGetPointSyms(section, numPoints, points, &perms, &flips)); 6364 switch (mode) { 6365 case INSERT_VALUES: 6366 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6367 const PetscInt point = points[2 * p]; 6368 const PetscInt *perm = perms ? perms[p] : NULL; 6369 const PetscScalar *flip = flips ? flips[p] : NULL; 6370 PetscCall(PetscSectionGetDof(section, point, &dof)); 6371 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6372 } 6373 break; 6374 case INSERT_ALL_VALUES: 6375 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6376 const PetscInt point = points[2 * p]; 6377 const PetscInt *perm = perms ? perms[p] : NULL; 6378 const PetscScalar *flip = flips ? flips[p] : NULL; 6379 PetscCall(PetscSectionGetDof(section, point, &dof)); 6380 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6381 } 6382 break; 6383 case INSERT_BC_VALUES: 6384 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6385 const PetscInt point = points[2 * p]; 6386 const PetscInt *perm = perms ? perms[p] : NULL; 6387 const PetscScalar *flip = flips ? flips[p] : NULL; 6388 PetscCall(PetscSectionGetDof(section, point, &dof)); 6389 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6390 } 6391 break; 6392 case ADD_VALUES: 6393 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6394 const PetscInt point = points[2 * p]; 6395 const PetscInt *perm = perms ? perms[p] : NULL; 6396 const PetscScalar *flip = flips ? flips[p] : NULL; 6397 PetscCall(PetscSectionGetDof(section, point, &dof)); 6398 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6399 } 6400 break; 6401 case ADD_ALL_VALUES: 6402 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6403 const PetscInt point = points[2 * p]; 6404 const PetscInt *perm = perms ? perms[p] : NULL; 6405 const PetscScalar *flip = flips ? flips[p] : NULL; 6406 PetscCall(PetscSectionGetDof(section, point, &dof)); 6407 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6408 } 6409 break; 6410 case ADD_BC_VALUES: 6411 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6412 const PetscInt point = points[2 * p]; 6413 const PetscInt *perm = perms ? perms[p] : NULL; 6414 const PetscScalar *flip = flips ? flips[p] : NULL; 6415 PetscCall(PetscSectionGetDof(section, point, &dof)); 6416 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6417 } 6418 break; 6419 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6420 } 6421 PetscCall(PetscSectionRestorePointSyms(section, numPoints, points, &perms, &flips)); 6422 } 6423 /* Cleanup points */ 6424 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6425 /* Cleanup array */ 6426 PetscCall(VecRestoreArray(v, &array)); 6427 PetscFunctionReturn(0); 6428 } 6429 6430 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6431 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset, PetscBool *contains) { 6432 PetscFunctionBegin; 6433 *contains = PETSC_TRUE; 6434 if (label) { 6435 PetscInt fdof; 6436 6437 PetscCall(DMLabelStratumHasPoint(label, labelId, point, contains)); 6438 if (!*contains) { 6439 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6440 *offset += fdof; 6441 PetscFunctionReturn(0); 6442 } 6443 } 6444 PetscFunctionReturn(0); 6445 } 6446 6447 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6448 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) { 6449 PetscSection clSection; 6450 IS clPoints; 6451 PetscScalar *array; 6452 PetscInt *points = NULL; 6453 const PetscInt *clp; 6454 PetscInt numFields, numPoints, p; 6455 PetscInt offset = 0, f; 6456 6457 PetscFunctionBeginHot; 6458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6459 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6460 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6461 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6462 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6463 /* Get points */ 6464 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6465 /* Get array */ 6466 PetscCall(VecGetArray(v, &array)); 6467 /* Get values */ 6468 for (f = 0; f < numFields; ++f) { 6469 const PetscInt **perms = NULL; 6470 const PetscScalar **flips = NULL; 6471 PetscBool contains; 6472 6473 if (!fieldActive[f]) { 6474 for (p = 0; p < numPoints * 2; p += 2) { 6475 PetscInt fdof; 6476 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6477 offset += fdof; 6478 } 6479 continue; 6480 } 6481 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6482 switch (mode) { 6483 case INSERT_VALUES: 6484 for (p = 0; p < numPoints; p++) { 6485 const PetscInt point = points[2 * p]; 6486 const PetscInt *perm = perms ? perms[p] : NULL; 6487 const PetscScalar *flip = flips ? flips[p] : NULL; 6488 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6489 if (!contains) continue; 6490 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6491 } 6492 break; 6493 case INSERT_ALL_VALUES: 6494 for (p = 0; p < numPoints; p++) { 6495 const PetscInt point = points[2 * p]; 6496 const PetscInt *perm = perms ? perms[p] : NULL; 6497 const PetscScalar *flip = flips ? flips[p] : NULL; 6498 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6499 if (!contains) continue; 6500 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6501 } 6502 break; 6503 case INSERT_BC_VALUES: 6504 for (p = 0; p < numPoints; p++) { 6505 const PetscInt point = points[2 * p]; 6506 const PetscInt *perm = perms ? perms[p] : NULL; 6507 const PetscScalar *flip = flips ? flips[p] : NULL; 6508 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6509 if (!contains) continue; 6510 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6511 } 6512 break; 6513 case ADD_VALUES: 6514 for (p = 0; p < numPoints; p++) { 6515 const PetscInt point = points[2 * p]; 6516 const PetscInt *perm = perms ? perms[p] : NULL; 6517 const PetscScalar *flip = flips ? flips[p] : NULL; 6518 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6519 if (!contains) continue; 6520 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6521 } 6522 break; 6523 case ADD_ALL_VALUES: 6524 for (p = 0; p < numPoints; p++) { 6525 const PetscInt point = points[2 * p]; 6526 const PetscInt *perm = perms ? perms[p] : NULL; 6527 const PetscScalar *flip = flips ? flips[p] : NULL; 6528 PetscCall(CheckPoint_Private(label, labelId, section, point, f, &offset, &contains)); 6529 if (!contains) continue; 6530 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6531 } 6532 break; 6533 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6534 } 6535 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6536 } 6537 /* Cleanup points */ 6538 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6539 /* Cleanup array */ 6540 PetscCall(VecRestoreArray(v, &array)); 6541 PetscFunctionReturn(0); 6542 } 6543 6544 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) { 6545 PetscMPIInt rank; 6546 PetscInt i, j; 6547 6548 PetscFunctionBegin; 6549 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6550 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6551 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6552 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6553 numCIndices = numCIndices ? numCIndices : numRIndices; 6554 if (!values) PetscFunctionReturn(0); 6555 for (i = 0; i < numRIndices; i++) { 6556 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6557 for (j = 0; j < numCIndices; j++) { 6558 #if defined(PETSC_USE_COMPLEX) 6559 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6560 #else 6561 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6562 #endif 6563 } 6564 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6565 } 6566 PetscFunctionReturn(0); 6567 } 6568 6569 /* 6570 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6571 6572 Input Parameters: 6573 + section - The section for this data layout 6574 . islocal - Is the section (and thus indices being requested) local or global? 6575 . point - The point contributing dofs with these indices 6576 . off - The global offset of this point 6577 . loff - The local offset of each field 6578 . setBC - The flag determining whether to include indices of boundary values 6579 . perm - A permutation of the dofs on this point, or NULL 6580 - indperm - A permutation of the entire indices array, or NULL 6581 6582 Output Parameter: 6583 . indices - Indices for dofs on this point 6584 6585 Level: developer 6586 6587 Note: The indices could be local or global, depending on the value of 'off'. 6588 */ 6589 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) { 6590 PetscInt dof; /* The number of unknowns on this point */ 6591 PetscInt cdof; /* The number of constraints on this point */ 6592 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6593 PetscInt cind = 0, k; 6594 6595 PetscFunctionBegin; 6596 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6597 PetscCall(PetscSectionGetDof(section, point, &dof)); 6598 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6599 if (!cdof || setBC) { 6600 for (k = 0; k < dof; ++k) { 6601 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6602 const PetscInt ind = indperm ? indperm[preind] : preind; 6603 6604 indices[ind] = off + k; 6605 } 6606 } else { 6607 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6608 for (k = 0; k < dof; ++k) { 6609 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6610 const PetscInt ind = indperm ? indperm[preind] : preind; 6611 6612 if ((cind < cdof) && (k == cdofs[cind])) { 6613 /* Insert check for returning constrained indices */ 6614 indices[ind] = -(off + k + 1); 6615 ++cind; 6616 } else { 6617 indices[ind] = off + k - (islocal ? 0 : cind); 6618 } 6619 } 6620 } 6621 *loff += dof; 6622 PetscFunctionReturn(0); 6623 } 6624 6625 /* 6626 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6627 6628 Input Parameters: 6629 + section - a section (global or local) 6630 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6631 . point - point within section 6632 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6633 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6634 . setBC - identify constrained (boundary condition) points via involution. 6635 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6636 . permsoff - offset 6637 - indperm - index permutation 6638 6639 Output Parameter: 6640 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6641 . indices - array to hold indices (as defined by section) of each dof associated with point 6642 6643 Notes: 6644 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6645 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6646 in the local vector. 6647 6648 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6649 significant). It is invalid to call with a global section and setBC=true. 6650 6651 Developer Note: 6652 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6653 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6654 offset could be obtained from the section instead of passing it explicitly as we do now. 6655 6656 Example: 6657 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6658 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6659 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6660 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. 6661 6662 Level: developer 6663 */ 6664 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[]) { 6665 PetscInt numFields, foff, f; 6666 6667 PetscFunctionBegin; 6668 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6669 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6670 for (f = 0, foff = 0; f < numFields; ++f) { 6671 PetscInt fdof, cfdof; 6672 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6673 PetscInt cind = 0, b; 6674 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6675 6676 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6677 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6678 if (!cfdof || setBC) { 6679 for (b = 0; b < fdof; ++b) { 6680 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6681 const PetscInt ind = indperm ? indperm[preind] : preind; 6682 6683 indices[ind] = off + foff + b; 6684 } 6685 } else { 6686 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6687 for (b = 0; b < fdof; ++b) { 6688 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6689 const PetscInt ind = indperm ? indperm[preind] : preind; 6690 6691 if ((cind < cfdof) && (b == fcdofs[cind])) { 6692 indices[ind] = -(off + foff + b + 1); 6693 ++cind; 6694 } else { 6695 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6696 } 6697 } 6698 } 6699 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6700 foffs[f] += fdof; 6701 } 6702 PetscFunctionReturn(0); 6703 } 6704 6705 /* 6706 This version believes the globalSection offsets for each field, rather than just the point offset 6707 6708 . foffs - The offset into 'indices' for each field, since it is segregated by field 6709 6710 Notes: 6711 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6712 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6713 */ 6714 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) { 6715 PetscInt numFields, foff, f; 6716 6717 PetscFunctionBegin; 6718 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6719 for (f = 0; f < numFields; ++f) { 6720 PetscInt fdof, cfdof; 6721 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6722 PetscInt cind = 0, b; 6723 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6724 6725 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6726 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6727 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6728 if (!cfdof) { 6729 for (b = 0; b < fdof; ++b) { 6730 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6731 const PetscInt ind = indperm ? indperm[preind] : preind; 6732 6733 indices[ind] = foff + b; 6734 } 6735 } else { 6736 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6737 for (b = 0; b < fdof; ++b) { 6738 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6739 const PetscInt ind = indperm ? indperm[preind] : preind; 6740 6741 if ((cind < cfdof) && (b == fcdofs[cind])) { 6742 indices[ind] = -(foff + b + 1); 6743 ++cind; 6744 } else { 6745 indices[ind] = foff + b - cind; 6746 } 6747 } 6748 } 6749 foffs[f] += fdof; 6750 } 6751 PetscFunctionReturn(0); 6752 } 6753 6754 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) { 6755 Mat cMat; 6756 PetscSection aSec, cSec; 6757 IS aIS; 6758 PetscInt aStart = -1, aEnd = -1; 6759 const PetscInt *anchors; 6760 PetscInt numFields, f, p, q, newP = 0; 6761 PetscInt newNumPoints = 0, newNumIndices = 0; 6762 PetscInt *newPoints, *indices, *newIndices; 6763 PetscInt maxAnchor, maxDof; 6764 PetscInt newOffsets[32]; 6765 PetscInt *pointMatOffsets[32]; 6766 PetscInt *newPointOffsets[32]; 6767 PetscScalar *pointMat[32]; 6768 PetscScalar *newValues = NULL, *tmpValues; 6769 PetscBool anyConstrained = PETSC_FALSE; 6770 6771 PetscFunctionBegin; 6772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6773 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6774 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6775 6776 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6777 /* if there are point-to-point constraints */ 6778 if (aSec) { 6779 PetscCall(PetscArrayzero(newOffsets, 32)); 6780 PetscCall(ISGetIndices(aIS, &anchors)); 6781 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6782 /* figure out how many points are going to be in the new element matrix 6783 * (we allow double counting, because it's all just going to be summed 6784 * into the global matrix anyway) */ 6785 for (p = 0; p < 2 * numPoints; p += 2) { 6786 PetscInt b = points[p]; 6787 PetscInt bDof = 0, bSecDof; 6788 6789 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6790 if (!bSecDof) continue; 6791 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6792 if (bDof) { 6793 /* this point is constrained */ 6794 /* it is going to be replaced by its anchors */ 6795 PetscInt bOff, q; 6796 6797 anyConstrained = PETSC_TRUE; 6798 newNumPoints += bDof; 6799 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6800 for (q = 0; q < bDof; q++) { 6801 PetscInt a = anchors[bOff + q]; 6802 PetscInt aDof; 6803 6804 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6805 newNumIndices += aDof; 6806 for (f = 0; f < numFields; ++f) { 6807 PetscInt fDof; 6808 6809 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6810 newOffsets[f + 1] += fDof; 6811 } 6812 } 6813 } else { 6814 /* this point is not constrained */ 6815 newNumPoints++; 6816 newNumIndices += bSecDof; 6817 for (f = 0; f < numFields; ++f) { 6818 PetscInt fDof; 6819 6820 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6821 newOffsets[f + 1] += fDof; 6822 } 6823 } 6824 } 6825 } 6826 if (!anyConstrained) { 6827 if (outNumPoints) *outNumPoints = 0; 6828 if (outNumIndices) *outNumIndices = 0; 6829 if (outPoints) *outPoints = NULL; 6830 if (outValues) *outValues = NULL; 6831 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6832 PetscFunctionReturn(0); 6833 } 6834 6835 if (outNumPoints) *outNumPoints = newNumPoints; 6836 if (outNumIndices) *outNumIndices = newNumIndices; 6837 6838 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 6839 6840 if (!outPoints && !outValues) { 6841 if (offsets) { 6842 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 6843 } 6844 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6845 PetscFunctionReturn(0); 6846 } 6847 6848 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6849 6850 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6851 6852 /* workspaces */ 6853 if (numFields) { 6854 for (f = 0; f < numFields; f++) { 6855 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 6856 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 6857 } 6858 } else { 6859 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 6860 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 6861 } 6862 6863 /* get workspaces for the point-to-point matrices */ 6864 if (numFields) { 6865 PetscInt totalOffset, totalMatOffset; 6866 6867 for (p = 0; p < numPoints; p++) { 6868 PetscInt b = points[2 * p]; 6869 PetscInt bDof = 0, bSecDof; 6870 6871 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6872 if (!bSecDof) { 6873 for (f = 0; f < numFields; f++) { 6874 newPointOffsets[f][p + 1] = 0; 6875 pointMatOffsets[f][p + 1] = 0; 6876 } 6877 continue; 6878 } 6879 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6880 if (bDof) { 6881 for (f = 0; f < numFields; f++) { 6882 PetscInt fDof, q, bOff, allFDof = 0; 6883 6884 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6885 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6886 for (q = 0; q < bDof; q++) { 6887 PetscInt a = anchors[bOff + q]; 6888 PetscInt aFDof; 6889 6890 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6891 allFDof += aFDof; 6892 } 6893 newPointOffsets[f][p + 1] = allFDof; 6894 pointMatOffsets[f][p + 1] = fDof * allFDof; 6895 } 6896 } else { 6897 for (f = 0; f < numFields; f++) { 6898 PetscInt fDof; 6899 6900 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6901 newPointOffsets[f][p + 1] = fDof; 6902 pointMatOffsets[f][p + 1] = 0; 6903 } 6904 } 6905 } 6906 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6907 newPointOffsets[f][0] = totalOffset; 6908 pointMatOffsets[f][0] = totalMatOffset; 6909 for (p = 0; p < numPoints; p++) { 6910 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 6911 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 6912 } 6913 totalOffset = newPointOffsets[f][numPoints]; 6914 totalMatOffset = pointMatOffsets[f][numPoints]; 6915 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 6916 } 6917 } else { 6918 for (p = 0; p < numPoints; p++) { 6919 PetscInt b = points[2 * p]; 6920 PetscInt bDof = 0, bSecDof; 6921 6922 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6923 if (!bSecDof) { 6924 newPointOffsets[0][p + 1] = 0; 6925 pointMatOffsets[0][p + 1] = 0; 6926 continue; 6927 } 6928 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6929 if (bDof) { 6930 PetscInt bOff, q, allDof = 0; 6931 6932 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6933 for (q = 0; q < bDof; q++) { 6934 PetscInt a = anchors[bOff + q], aDof; 6935 6936 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6937 allDof += aDof; 6938 } 6939 newPointOffsets[0][p + 1] = allDof; 6940 pointMatOffsets[0][p + 1] = bSecDof * allDof; 6941 } else { 6942 newPointOffsets[0][p + 1] = bSecDof; 6943 pointMatOffsets[0][p + 1] = 0; 6944 } 6945 } 6946 newPointOffsets[0][0] = 0; 6947 pointMatOffsets[0][0] = 0; 6948 for (p = 0; p < numPoints; p++) { 6949 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 6950 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 6951 } 6952 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 6953 } 6954 6955 /* output arrays */ 6956 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 6957 6958 /* get the point-to-point matrices; construct newPoints */ 6959 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6960 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6961 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 6962 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 6963 if (numFields) { 6964 for (p = 0, newP = 0; p < numPoints; p++) { 6965 PetscInt b = points[2 * p]; 6966 PetscInt o = points[2 * p + 1]; 6967 PetscInt bDof = 0, bSecDof; 6968 6969 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6970 if (!bSecDof) continue; 6971 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6972 if (bDof) { 6973 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6974 6975 fStart[0] = 0; 6976 fEnd[0] = 0; 6977 for (f = 0; f < numFields; f++) { 6978 PetscInt fDof; 6979 6980 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6981 fStart[f + 1] = fStart[f] + fDof; 6982 fEnd[f + 1] = fStart[f + 1]; 6983 } 6984 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6985 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6986 6987 fAnchorStart[0] = 0; 6988 fAnchorEnd[0] = 0; 6989 for (f = 0; f < numFields; f++) { 6990 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6991 6992 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 6993 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 6994 } 6995 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6996 for (q = 0; q < bDof; q++) { 6997 PetscInt a = anchors[bOff + q], aOff; 6998 6999 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7000 newPoints[2 * (newP + q)] = a; 7001 newPoints[2 * (newP + q) + 1] = 0; 7002 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7003 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7004 } 7005 newP += bDof; 7006 7007 if (outValues) { 7008 /* get the point-to-point submatrix */ 7009 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])); 7010 } 7011 } else { 7012 newPoints[2 * newP] = b; 7013 newPoints[2 * newP + 1] = o; 7014 newP++; 7015 } 7016 } 7017 } else { 7018 for (p = 0; p < numPoints; p++) { 7019 PetscInt b = points[2 * p]; 7020 PetscInt o = points[2 * p + 1]; 7021 PetscInt bDof = 0, bSecDof; 7022 7023 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7024 if (!bSecDof) continue; 7025 if (b >= aStart && b < aEnd) PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7026 if (bDof) { 7027 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7028 7029 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7030 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7031 7032 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7033 for (q = 0; q < bDof; q++) { 7034 PetscInt a = anchors[bOff + q], aOff; 7035 7036 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7037 7038 newPoints[2 * (newP + q)] = a; 7039 newPoints[2 * (newP + q) + 1] = 0; 7040 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7041 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7042 } 7043 newP += bDof; 7044 7045 /* get the point-to-point submatrix */ 7046 if (outValues) PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); 7047 } else { 7048 newPoints[2 * newP] = b; 7049 newPoints[2 * newP + 1] = o; 7050 newP++; 7051 } 7052 } 7053 } 7054 7055 if (outValues) { 7056 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7057 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7058 /* multiply constraints on the right */ 7059 if (numFields) { 7060 for (f = 0; f < numFields; f++) { 7061 PetscInt oldOff = offsets[f]; 7062 7063 for (p = 0; p < numPoints; p++) { 7064 PetscInt cStart = newPointOffsets[f][p]; 7065 PetscInt b = points[2 * p]; 7066 PetscInt c, r, k; 7067 PetscInt dof; 7068 7069 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7070 if (!dof) continue; 7071 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7072 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7073 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7074 7075 for (r = 0; r < numIndices; r++) { 7076 for (c = 0; c < nCols; c++) { 7077 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7078 } 7079 } 7080 } else { 7081 /* copy this column as is */ 7082 for (r = 0; r < numIndices; r++) { 7083 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7084 } 7085 } 7086 oldOff += dof; 7087 } 7088 } 7089 } else { 7090 PetscInt oldOff = 0; 7091 for (p = 0; p < numPoints; p++) { 7092 PetscInt cStart = newPointOffsets[0][p]; 7093 PetscInt b = points[2 * p]; 7094 PetscInt c, r, k; 7095 PetscInt dof; 7096 7097 PetscCall(PetscSectionGetDof(section, b, &dof)); 7098 if (!dof) continue; 7099 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7100 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7101 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7102 7103 for (r = 0; r < numIndices; r++) { 7104 for (c = 0; c < nCols; c++) { 7105 for (k = 0; k < dof; k++) tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7106 } 7107 } 7108 } else { 7109 /* copy this column as is */ 7110 for (r = 0; r < numIndices; r++) { 7111 for (c = 0; c < dof; c++) tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7112 } 7113 } 7114 oldOff += dof; 7115 } 7116 } 7117 7118 if (multiplyLeft) { 7119 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7120 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7121 /* multiply constraints transpose on the left */ 7122 if (numFields) { 7123 for (f = 0; f < numFields; f++) { 7124 PetscInt oldOff = offsets[f]; 7125 7126 for (p = 0; p < numPoints; p++) { 7127 PetscInt rStart = newPointOffsets[f][p]; 7128 PetscInt b = points[2 * p]; 7129 PetscInt c, r, k; 7130 PetscInt dof; 7131 7132 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7133 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7134 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7135 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7136 7137 for (r = 0; r < nRows; r++) { 7138 for (c = 0; c < newNumIndices; c++) { 7139 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7140 } 7141 } 7142 } else { 7143 /* copy this row as is */ 7144 for (r = 0; r < dof; r++) { 7145 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7146 } 7147 } 7148 oldOff += dof; 7149 } 7150 } 7151 } else { 7152 PetscInt oldOff = 0; 7153 7154 for (p = 0; p < numPoints; p++) { 7155 PetscInt rStart = newPointOffsets[0][p]; 7156 PetscInt b = points[2 * p]; 7157 PetscInt c, r, k; 7158 PetscInt dof; 7159 7160 PetscCall(PetscSectionGetDof(section, b, &dof)); 7161 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7162 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7163 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7164 7165 for (r = 0; r < nRows; r++) { 7166 for (c = 0; c < newNumIndices; c++) { 7167 for (k = 0; k < dof; k++) newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7168 } 7169 } 7170 } else { 7171 /* copy this row as is */ 7172 for (r = 0; r < dof; r++) { 7173 for (c = 0; c < newNumIndices; c++) newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7174 } 7175 } 7176 oldOff += dof; 7177 } 7178 } 7179 7180 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7181 } else { 7182 newValues = tmpValues; 7183 } 7184 } 7185 7186 /* clean up */ 7187 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7188 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7189 7190 if (numFields) { 7191 for (f = 0; f < numFields; f++) { 7192 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7193 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7194 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7195 } 7196 } else { 7197 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7198 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7199 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7200 } 7201 PetscCall(ISRestoreIndices(aIS, &anchors)); 7202 7203 /* output */ 7204 if (outPoints) { 7205 *outPoints = newPoints; 7206 } else { 7207 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7208 } 7209 if (outValues) *outValues = newValues; 7210 for (f = 0; f <= numFields; f++) offsets[f] = newOffsets[f]; 7211 PetscFunctionReturn(0); 7212 } 7213 7214 /*@C 7215 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7216 7217 Not collective 7218 7219 Input Parameters: 7220 + dm - The DM 7221 . section - The PetscSection describing the points (a local section) 7222 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7223 . point - The point defining the closure 7224 - useClPerm - Use the closure point permutation if available 7225 7226 Output Parameters: 7227 + numIndices - The number of dof indices in the closure of point with the input sections 7228 . indices - The dof indices 7229 . outOffsets - Array to write the field offsets into, or NULL 7230 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7231 7232 Notes: 7233 Must call DMPlexRestoreClosureIndices() to free allocated memory 7234 7235 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7236 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7237 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7238 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7239 indices (with the above semantics) are implied. 7240 7241 Level: advanced 7242 7243 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7244 @*/ 7245 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7246 /* Closure ordering */ 7247 PetscSection clSection; 7248 IS clPoints; 7249 const PetscInt *clp; 7250 PetscInt *points; 7251 const PetscInt *clperm = NULL; 7252 /* Dof permutation and sign flips */ 7253 const PetscInt **perms[32] = {NULL}; 7254 const PetscScalar **flips[32] = {NULL}; 7255 PetscScalar *valCopy = NULL; 7256 /* Hanging node constraints */ 7257 PetscInt *pointsC = NULL; 7258 PetscScalar *valuesC = NULL; 7259 PetscInt NclC, NiC; 7260 7261 PetscInt *idx; 7262 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7263 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7264 7265 PetscFunctionBeginHot; 7266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7267 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7268 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7269 if (numIndices) PetscValidIntPointer(numIndices, 6); 7270 if (indices) PetscValidPointer(indices, 7); 7271 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7272 if (values) PetscValidPointer(values, 9); 7273 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7274 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7275 PetscCall(PetscArrayzero(offsets, 32)); 7276 /* 1) Get points in closure */ 7277 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7278 if (useClPerm) { 7279 PetscInt depth, clsize; 7280 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7281 for (clsize = 0, p = 0; p < Ncl; p++) { 7282 PetscInt dof; 7283 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7284 clsize += dof; 7285 } 7286 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7287 } 7288 /* 2) Get number of indices on these points and field offsets from section */ 7289 for (p = 0; p < Ncl * 2; p += 2) { 7290 PetscInt dof, fdof; 7291 7292 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7293 for (f = 0; f < Nf; ++f) { 7294 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7295 offsets[f + 1] += fdof; 7296 } 7297 Ni += dof; 7298 } 7299 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7300 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7301 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7302 for (f = 0; f < PetscMax(1, Nf); ++f) { 7303 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7304 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7305 /* may need to apply sign changes to the element matrix */ 7306 if (values && flips[f]) { 7307 PetscInt foffset = offsets[f]; 7308 7309 for (p = 0; p < Ncl; ++p) { 7310 PetscInt pnt = points[2 * p], fdof; 7311 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7312 7313 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7314 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7315 if (flip) { 7316 PetscInt i, j, k; 7317 7318 if (!valCopy) { 7319 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7320 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7321 *values = valCopy; 7322 } 7323 for (i = 0; i < fdof; ++i) { 7324 PetscScalar fval = flip[i]; 7325 7326 for (k = 0; k < Ni; ++k) { 7327 valCopy[Ni * (foffset + i) + k] *= fval; 7328 valCopy[Ni * k + (foffset + i)] *= fval; 7329 } 7330 } 7331 } 7332 foffset += fdof; 7333 } 7334 } 7335 } 7336 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7337 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7338 if (NclC) { 7339 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7340 for (f = 0; f < PetscMax(1, Nf); ++f) { 7341 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7342 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7343 } 7344 for (f = 0; f < PetscMax(1, Nf); ++f) { 7345 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7346 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7347 } 7348 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7349 Ncl = NclC; 7350 Ni = NiC; 7351 points = pointsC; 7352 if (values) *values = valuesC; 7353 } 7354 /* 5) Calculate indices */ 7355 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7356 if (Nf) { 7357 PetscInt idxOff; 7358 PetscBool useFieldOffsets; 7359 7360 if (outOffsets) { 7361 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7362 } 7363 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7364 if (useFieldOffsets) { 7365 for (p = 0; p < Ncl; ++p) { 7366 const PetscInt pnt = points[p * 2]; 7367 7368 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7369 } 7370 } else { 7371 for (p = 0; p < Ncl; ++p) { 7372 const PetscInt pnt = points[p * 2]; 7373 7374 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7375 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7376 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7377 * global section. */ 7378 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7379 } 7380 } 7381 } else { 7382 PetscInt off = 0, idxOff; 7383 7384 for (p = 0; p < Ncl; ++p) { 7385 const PetscInt pnt = points[p * 2]; 7386 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7387 7388 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7389 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7390 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7391 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7392 } 7393 } 7394 /* 6) Cleanup */ 7395 for (f = 0; f < PetscMax(1, Nf); ++f) { 7396 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7397 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7398 } 7399 if (NclC) { 7400 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7401 } else { 7402 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7403 } 7404 7405 if (numIndices) *numIndices = Ni; 7406 if (indices) *indices = idx; 7407 PetscFunctionReturn(0); 7408 } 7409 7410 /*@C 7411 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7412 7413 Not collective 7414 7415 Input Parameters: 7416 + dm - The DM 7417 . section - The PetscSection describing the points (a local section) 7418 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7419 . point - The point defining the closure 7420 - useClPerm - Use the closure point permutation if available 7421 7422 Output Parameters: 7423 + numIndices - The number of dof indices in the closure of point with the input sections 7424 . indices - The dof indices 7425 . outOffsets - Array to write the field offsets into, or NULL 7426 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7427 7428 Notes: 7429 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7430 7431 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7432 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7433 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7434 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7435 indices (with the above semantics) are implied. 7436 7437 Level: advanced 7438 7439 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7440 @*/ 7441 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7442 PetscFunctionBegin; 7443 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7444 PetscValidPointer(indices, 7); 7445 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7446 PetscFunctionReturn(0); 7447 } 7448 7449 /*@C 7450 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7451 7452 Not collective 7453 7454 Input Parameters: 7455 + dm - The DM 7456 . section - The section describing the layout in v, or NULL to use the default section 7457 . globalSection - The section describing the layout in v, or NULL to use the default global section 7458 . A - The matrix 7459 . point - The point in the DM 7460 . values - The array of values 7461 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7462 7463 Fortran Notes: 7464 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7465 7466 Level: intermediate 7467 7468 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7469 @*/ 7470 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7471 DM_Plex *mesh = (DM_Plex *)dm->data; 7472 PetscInt *indices; 7473 PetscInt numIndices; 7474 const PetscScalar *valuesOrig = values; 7475 PetscErrorCode ierr; 7476 7477 PetscFunctionBegin; 7478 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7479 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7480 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7481 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7482 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7483 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7484 7485 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7486 7487 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7488 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7489 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7490 if (ierr) { 7491 PetscMPIInt rank; 7492 7493 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7494 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7495 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7496 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7497 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7498 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7499 } 7500 if (mesh->printFEM > 1) { 7501 PetscInt i; 7502 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7503 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7504 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7505 } 7506 7507 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7508 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7509 PetscFunctionReturn(0); 7510 } 7511 7512 /*@C 7513 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7514 7515 Not collective 7516 7517 Input Parameters: 7518 + dmRow - The DM for the row fields 7519 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7520 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7521 . dmCol - The DM for the column fields 7522 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7523 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7524 . A - The matrix 7525 . point - The point in the DMs 7526 . values - The array of values 7527 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7528 7529 Level: intermediate 7530 7531 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7532 @*/ 7533 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7534 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7535 PetscInt *indicesRow, *indicesCol; 7536 PetscInt numIndicesRow, numIndicesCol; 7537 const PetscScalar *valuesOrig = values; 7538 PetscErrorCode ierr; 7539 7540 PetscFunctionBegin; 7541 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7542 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7543 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7544 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7545 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7546 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7547 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7548 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7549 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7550 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7551 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7552 7553 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7554 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7555 7556 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7557 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7558 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7559 if (ierr) { 7560 PetscMPIInt rank; 7561 7562 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7563 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7564 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7565 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7566 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7567 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7568 } 7569 7570 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7571 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7572 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7573 PetscFunctionReturn(0); 7574 } 7575 7576 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7577 DM_Plex *mesh = (DM_Plex *)dmf->data; 7578 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7579 PetscInt *cpoints = NULL; 7580 PetscInt *findices, *cindices; 7581 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7582 PetscInt foffsets[32], coffsets[32]; 7583 DMPolytopeType ct; 7584 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7585 PetscErrorCode ierr; 7586 7587 PetscFunctionBegin; 7588 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7589 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7590 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7591 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7592 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7593 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7594 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7595 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7596 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7597 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7598 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7599 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7600 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7601 PetscCall(PetscArrayzero(foffsets, 32)); 7602 PetscCall(PetscArrayzero(coffsets, 32)); 7603 /* Column indices */ 7604 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7605 maxFPoints = numCPoints; 7606 /* Compress out points not in the section */ 7607 /* TODO: Squeeze out points with 0 dof as well */ 7608 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7609 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7610 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7611 cpoints[q * 2] = cpoints[p]; 7612 cpoints[q * 2 + 1] = cpoints[p + 1]; 7613 ++q; 7614 } 7615 } 7616 numCPoints = q; 7617 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7618 PetscInt fdof; 7619 7620 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7621 if (!dof) continue; 7622 for (f = 0; f < numFields; ++f) { 7623 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7624 coffsets[f + 1] += fdof; 7625 } 7626 numCIndices += dof; 7627 } 7628 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7629 /* Row indices */ 7630 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7631 { 7632 DMPlexTransform tr; 7633 DMPolytopeType *rct; 7634 PetscInt *rsize, *rcone, *rornt, Nt; 7635 7636 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7637 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7638 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7639 numSubcells = rsize[Nt - 1]; 7640 PetscCall(DMPlexTransformDestroy(&tr)); 7641 } 7642 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7643 for (r = 0, q = 0; r < numSubcells; ++r) { 7644 /* TODO Map from coarse to fine cells */ 7645 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7646 /* Compress out points not in the section */ 7647 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7648 for (p = 0; p < numFPoints * 2; p += 2) { 7649 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7650 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7651 if (!dof) continue; 7652 for (s = 0; s < q; ++s) 7653 if (fpoints[p] == ftotpoints[s * 2]) break; 7654 if (s < q) continue; 7655 ftotpoints[q * 2] = fpoints[p]; 7656 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7657 ++q; 7658 } 7659 } 7660 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7661 } 7662 numFPoints = q; 7663 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7664 PetscInt fdof; 7665 7666 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7667 if (!dof) continue; 7668 for (f = 0; f < numFields; ++f) { 7669 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7670 foffsets[f + 1] += fdof; 7671 } 7672 numFIndices += dof; 7673 } 7674 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7675 7676 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7677 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7678 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7679 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7680 if (numFields) { 7681 const PetscInt **permsF[32] = {NULL}; 7682 const PetscInt **permsC[32] = {NULL}; 7683 7684 for (f = 0; f < numFields; f++) { 7685 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7686 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7687 } 7688 for (p = 0; p < numFPoints; p++) { 7689 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7690 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7691 } 7692 for (p = 0; p < numCPoints; p++) { 7693 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7694 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7695 } 7696 for (f = 0; f < numFields; f++) { 7697 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7698 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7699 } 7700 } else { 7701 const PetscInt **permsF = NULL; 7702 const PetscInt **permsC = NULL; 7703 7704 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7705 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7706 for (p = 0, off = 0; p < numFPoints; p++) { 7707 const PetscInt *perm = permsF ? permsF[p] : NULL; 7708 7709 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7710 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7711 } 7712 for (p = 0, off = 0; p < numCPoints; p++) { 7713 const PetscInt *perm = permsC ? permsC[p] : NULL; 7714 7715 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7716 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7717 } 7718 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7719 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7720 } 7721 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7722 /* TODO: flips */ 7723 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7724 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7725 if (ierr) { 7726 PetscMPIInt rank; 7727 7728 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7729 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7730 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7731 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7732 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7733 } 7734 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7735 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7736 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7737 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7738 PetscFunctionReturn(0); 7739 } 7740 7741 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) { 7742 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7743 PetscInt *cpoints = NULL; 7744 PetscInt foffsets[32], coffsets[32]; 7745 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7746 DMPolytopeType ct; 7747 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7748 7749 PetscFunctionBegin; 7750 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7751 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7752 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7753 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7754 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7755 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7756 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7757 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7758 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7759 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7760 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7761 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7762 PetscCall(PetscArrayzero(foffsets, 32)); 7763 PetscCall(PetscArrayzero(coffsets, 32)); 7764 /* Column indices */ 7765 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7766 maxFPoints = numCPoints; 7767 /* Compress out points not in the section */ 7768 /* TODO: Squeeze out points with 0 dof as well */ 7769 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7770 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7771 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7772 cpoints[q * 2] = cpoints[p]; 7773 cpoints[q * 2 + 1] = cpoints[p + 1]; 7774 ++q; 7775 } 7776 } 7777 numCPoints = q; 7778 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7779 PetscInt fdof; 7780 7781 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7782 if (!dof) continue; 7783 for (f = 0; f < numFields; ++f) { 7784 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7785 coffsets[f + 1] += fdof; 7786 } 7787 numCIndices += dof; 7788 } 7789 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7790 /* Row indices */ 7791 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7792 { 7793 DMPlexTransform tr; 7794 DMPolytopeType *rct; 7795 PetscInt *rsize, *rcone, *rornt, Nt; 7796 7797 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7798 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7799 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7800 numSubcells = rsize[Nt - 1]; 7801 PetscCall(DMPlexTransformDestroy(&tr)); 7802 } 7803 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7804 for (r = 0, q = 0; r < numSubcells; ++r) { 7805 /* TODO Map from coarse to fine cells */ 7806 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7807 /* Compress out points not in the section */ 7808 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7809 for (p = 0; p < numFPoints * 2; p += 2) { 7810 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7811 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7812 if (!dof) continue; 7813 for (s = 0; s < q; ++s) 7814 if (fpoints[p] == ftotpoints[s * 2]) break; 7815 if (s < q) continue; 7816 ftotpoints[q * 2] = fpoints[p]; 7817 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7818 ++q; 7819 } 7820 } 7821 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7822 } 7823 numFPoints = q; 7824 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7825 PetscInt fdof; 7826 7827 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7828 if (!dof) continue; 7829 for (f = 0; f < numFields; ++f) { 7830 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7831 foffsets[f + 1] += fdof; 7832 } 7833 numFIndices += dof; 7834 } 7835 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7836 7837 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7838 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7839 if (numFields) { 7840 const PetscInt **permsF[32] = {NULL}; 7841 const PetscInt **permsC[32] = {NULL}; 7842 7843 for (f = 0; f < numFields; f++) { 7844 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7845 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7846 } 7847 for (p = 0; p < numFPoints; p++) { 7848 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7849 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7850 } 7851 for (p = 0; p < numCPoints; p++) { 7852 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7853 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7854 } 7855 for (f = 0; f < numFields; f++) { 7856 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7857 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7858 } 7859 } else { 7860 const PetscInt **permsF = NULL; 7861 const PetscInt **permsC = NULL; 7862 7863 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7864 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7865 for (p = 0, off = 0; p < numFPoints; p++) { 7866 const PetscInt *perm = permsF ? permsF[p] : NULL; 7867 7868 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7869 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7870 } 7871 for (p = 0, off = 0; p < numCPoints; p++) { 7872 const PetscInt *perm = permsC ? permsC[p] : NULL; 7873 7874 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7875 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7876 } 7877 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7878 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7879 } 7880 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7881 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7882 PetscFunctionReturn(0); 7883 } 7884 7885 /*@C 7886 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7887 7888 Input Parameter: 7889 . dm - The DMPlex object 7890 7891 Output Parameter: 7892 . cellHeight - The height of a cell 7893 7894 Level: developer 7895 7896 .seealso `DMPlexSetVTKCellHeight()` 7897 @*/ 7898 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) { 7899 DM_Plex *mesh = (DM_Plex *)dm->data; 7900 7901 PetscFunctionBegin; 7902 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7903 PetscValidIntPointer(cellHeight, 2); 7904 *cellHeight = mesh->vtkCellHeight; 7905 PetscFunctionReturn(0); 7906 } 7907 7908 /*@C 7909 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7910 7911 Input Parameters: 7912 + dm - The DMPlex object 7913 - cellHeight - The height of a cell 7914 7915 Level: developer 7916 7917 .seealso `DMPlexGetVTKCellHeight()` 7918 @*/ 7919 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) { 7920 DM_Plex *mesh = (DM_Plex *)dm->data; 7921 7922 PetscFunctionBegin; 7923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7924 mesh->vtkCellHeight = cellHeight; 7925 PetscFunctionReturn(0); 7926 } 7927 7928 /*@ 7929 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7930 7931 Input Parameter: 7932 . dm - The DMPlex object 7933 7934 Output Parameters: 7935 + gcStart - The first ghost cell, or NULL 7936 - gcEnd - The upper bound on ghost cells, or NULL 7937 7938 Level: advanced 7939 7940 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7941 @*/ 7942 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) { 7943 DMLabel ctLabel; 7944 7945 PetscFunctionBegin; 7946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7947 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7948 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7949 // Reset label for fast lookup 7950 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 7951 PetscFunctionReturn(0); 7952 } 7953 7954 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) { 7955 PetscSection section, globalSection; 7956 PetscInt *numbers, p; 7957 7958 PetscFunctionBegin; 7959 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf, PETSC_TRUE)); 7960 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 7961 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 7962 for (p = pStart; p < pEnd; ++p) PetscCall(PetscSectionSetDof(section, p, 1)); 7963 PetscCall(PetscSectionSetUp(section)); 7964 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 7965 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 7966 for (p = pStart; p < pEnd; ++p) { 7967 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 7968 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 7969 else numbers[p - pStart] += shift; 7970 } 7971 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 7972 if (globalSize) { 7973 PetscLayout layout; 7974 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 7975 PetscCall(PetscLayoutGetSize(layout, globalSize)); 7976 PetscCall(PetscLayoutDestroy(&layout)); 7977 } 7978 PetscCall(PetscSectionDestroy(§ion)); 7979 PetscCall(PetscSectionDestroy(&globalSection)); 7980 PetscFunctionReturn(0); 7981 } 7982 7983 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) { 7984 PetscInt cellHeight, cStart, cEnd; 7985 7986 PetscFunctionBegin; 7987 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 7988 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 7989 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 7990 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 7991 PetscFunctionReturn(0); 7992 } 7993 7994 /*@ 7995 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 7996 7997 Input Parameter: 7998 . dm - The DMPlex object 7999 8000 Output Parameter: 8001 . globalCellNumbers - Global cell numbers for all cells on this process 8002 8003 Level: developer 8004 8005 .seealso `DMPlexGetVertexNumbering()` 8006 @*/ 8007 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) { 8008 DM_Plex *mesh = (DM_Plex *)dm->data; 8009 8010 PetscFunctionBegin; 8011 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8012 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8013 *globalCellNumbers = mesh->globalCellNumbers; 8014 PetscFunctionReturn(0); 8015 } 8016 8017 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) { 8018 PetscInt vStart, vEnd; 8019 8020 PetscFunctionBegin; 8021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8022 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8023 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8024 PetscFunctionReturn(0); 8025 } 8026 8027 /*@ 8028 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8029 8030 Input Parameter: 8031 . dm - The DMPlex object 8032 8033 Output Parameter: 8034 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8035 8036 Level: developer 8037 8038 .seealso `DMPlexGetCellNumbering()` 8039 @*/ 8040 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) { 8041 DM_Plex *mesh = (DM_Plex *)dm->data; 8042 8043 PetscFunctionBegin; 8044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8045 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8046 *globalVertexNumbers = mesh->globalVertexNumbers; 8047 PetscFunctionReturn(0); 8048 } 8049 8050 /*@ 8051 DMPlexCreatePointNumbering - Create a global numbering for all points. 8052 8053 Collective on dm 8054 8055 Input Parameter: 8056 . dm - The DMPlex object 8057 8058 Output Parameter: 8059 . globalPointNumbers - Global numbers for all points on this process 8060 8061 Notes: 8062 8063 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8064 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8065 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8066 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8067 8068 The partitioned mesh is 8069 ``` 8070 (2)--0--(3)--1--(4) (1)--0--(2) 8071 ``` 8072 and its global numbering is 8073 ``` 8074 (3)--0--(4)--1--(5)--2--(6) 8075 ``` 8076 Then the global numbering is provided as 8077 ``` 8078 [0] Number of indices in set 5 8079 [0] 0 0 8080 [0] 1 1 8081 [0] 2 3 8082 [0] 3 4 8083 [0] 4 -6 8084 [1] Number of indices in set 3 8085 [1] 0 2 8086 [1] 1 5 8087 [1] 2 6 8088 ``` 8089 8090 Level: developer 8091 8092 .seealso `DMPlexGetCellNumbering()` 8093 @*/ 8094 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) { 8095 IS nums[4]; 8096 PetscInt depths[4], gdepths[4], starts[4]; 8097 PetscInt depth, d, shift = 0; 8098 PetscBool empty = PETSC_FALSE; 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 // If any stratum is empty, we must mark all empty 8106 for (d = 0; d <= depth; ++d) { 8107 PetscInt end; 8108 8109 depths[d] = depth - d; 8110 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8111 if (!(starts[d] - end)) empty = PETSC_TRUE; 8112 } 8113 if (empty) 8114 for (d = 0; d <= depth; ++d) { 8115 depths[d] = -1; 8116 starts[d] = -1; 8117 } 8118 else PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8119 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8120 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]); 8121 // Note here that 'shift' is collective, so that the numbering is stratified by depth 8122 for (d = 0; d <= depth; ++d) { 8123 PetscInt pStart, pEnd, gsize; 8124 8125 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8126 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8127 shift += gsize; 8128 } 8129 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8130 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8131 PetscFunctionReturn(0); 8132 } 8133 8134 /*@ 8135 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8136 8137 Input Parameter: 8138 . dm - The DMPlex object 8139 8140 Output Parameter: 8141 . ranks - The rank field 8142 8143 Options Database Keys: 8144 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8145 8146 Level: intermediate 8147 8148 .seealso: `DMView()` 8149 @*/ 8150 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) { 8151 DM rdm; 8152 PetscFE fe; 8153 PetscScalar *r; 8154 PetscMPIInt rank; 8155 DMPolytopeType ct; 8156 PetscInt dim, cStart, cEnd, c; 8157 PetscBool simplex; 8158 8159 PetscFunctionBeginUser; 8160 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8161 PetscValidPointer(ranks, 2); 8162 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8163 PetscCall(DMClone(dm, &rdm)); 8164 PetscCall(DMGetDimension(rdm, &dim)); 8165 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8166 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8167 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8168 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8169 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8170 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8171 PetscCall(PetscFEDestroy(&fe)); 8172 PetscCall(DMCreateDS(rdm)); 8173 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8174 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8175 PetscCall(VecGetArray(*ranks, &r)); 8176 for (c = cStart; c < cEnd; ++c) { 8177 PetscScalar *lr; 8178 8179 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8180 if (lr) *lr = rank; 8181 } 8182 PetscCall(VecRestoreArray(*ranks, &r)); 8183 PetscCall(DMDestroy(&rdm)); 8184 PetscFunctionReturn(0); 8185 } 8186 8187 /*@ 8188 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8189 8190 Input Parameters: 8191 + dm - The DMPlex 8192 - label - The DMLabel 8193 8194 Output Parameter: 8195 . val - The label value field 8196 8197 Options Database Keys: 8198 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8199 8200 Level: intermediate 8201 8202 .seealso: `DMView()` 8203 @*/ 8204 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) { 8205 DM rdm; 8206 PetscFE fe; 8207 PetscScalar *v; 8208 PetscInt dim, cStart, cEnd, c; 8209 8210 PetscFunctionBeginUser; 8211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8212 PetscValidPointer(label, 2); 8213 PetscValidPointer(val, 3); 8214 PetscCall(DMClone(dm, &rdm)); 8215 PetscCall(DMGetDimension(rdm, &dim)); 8216 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8217 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8218 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8219 PetscCall(PetscFEDestroy(&fe)); 8220 PetscCall(DMCreateDS(rdm)); 8221 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8222 PetscCall(DMCreateGlobalVector(rdm, val)); 8223 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8224 PetscCall(VecGetArray(*val, &v)); 8225 for (c = cStart; c < cEnd; ++c) { 8226 PetscScalar *lv; 8227 PetscInt cval; 8228 8229 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8230 PetscCall(DMLabelGetValue(label, c, &cval)); 8231 *lv = cval; 8232 } 8233 PetscCall(VecRestoreArray(*val, &v)); 8234 PetscCall(DMDestroy(&rdm)); 8235 PetscFunctionReturn(0); 8236 } 8237 8238 /*@ 8239 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8240 8241 Input Parameter: 8242 . dm - The DMPlex object 8243 8244 Notes: 8245 This is a useful diagnostic when creating meshes programmatically. 8246 8247 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8248 8249 Level: developer 8250 8251 .seealso: `DMCreate()`, `DMSetFromOptions()` 8252 @*/ 8253 PetscErrorCode DMPlexCheckSymmetry(DM dm) { 8254 PetscSection coneSection, supportSection; 8255 const PetscInt *cone, *support; 8256 PetscInt coneSize, c, supportSize, s; 8257 PetscInt pStart, pEnd, p, pp, csize, ssize; 8258 PetscBool storagecheck = PETSC_TRUE; 8259 8260 PetscFunctionBegin; 8261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8262 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8263 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8264 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8265 /* Check that point p is found in the support of its cone points, and vice versa */ 8266 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8267 for (p = pStart; p < pEnd; ++p) { 8268 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8269 PetscCall(DMPlexGetCone(dm, p, &cone)); 8270 for (c = 0; c < coneSize; ++c) { 8271 PetscBool dup = PETSC_FALSE; 8272 PetscInt d; 8273 for (d = c - 1; d >= 0; --d) { 8274 if (cone[c] == cone[d]) { 8275 dup = PETSC_TRUE; 8276 break; 8277 } 8278 } 8279 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8280 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8281 for (s = 0; s < supportSize; ++s) { 8282 if (support[s] == p) break; 8283 } 8284 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8285 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8286 for (s = 0; s < coneSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8287 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8288 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8289 for (s = 0; s < supportSize; ++s) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8290 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8291 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]); 8292 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8293 } 8294 } 8295 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8296 if (p != pp) { 8297 storagecheck = PETSC_FALSE; 8298 continue; 8299 } 8300 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8301 PetscCall(DMPlexGetSupport(dm, p, &support)); 8302 for (s = 0; s < supportSize; ++s) { 8303 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8304 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8305 for (c = 0; c < coneSize; ++c) { 8306 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8307 if (cone[c] != pp) { 8308 c = 0; 8309 break; 8310 } 8311 if (cone[c] == p) break; 8312 } 8313 if (c >= coneSize) { 8314 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8315 for (c = 0; c < supportSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8316 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8317 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8318 for (c = 0; c < coneSize; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8319 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8320 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8321 } 8322 } 8323 } 8324 if (storagecheck) { 8325 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8326 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8327 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8328 } 8329 PetscFunctionReturn(0); 8330 } 8331 8332 /* 8333 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. 8334 */ 8335 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) { 8336 DMPolytopeType cct; 8337 PetscInt ptpoints[4]; 8338 const PetscInt *cone, *ccone, *ptcone; 8339 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8340 8341 PetscFunctionBegin; 8342 *unsplit = 0; 8343 switch (ct) { 8344 case DM_POLYTOPE_POINT_PRISM_TENSOR: ptpoints[npt++] = c; break; 8345 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8346 PetscCall(DMPlexGetCone(dm, c, &cone)); 8347 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8348 for (cp = 0; cp < coneSize; ++cp) { 8349 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8350 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8351 } 8352 break; 8353 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8354 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8355 PetscCall(DMPlexGetCone(dm, c, &cone)); 8356 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8357 for (cp = 0; cp < coneSize; ++cp) { 8358 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8359 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8360 for (ccp = 0; ccp < cconeSize; ++ccp) { 8361 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8362 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8363 PetscInt p; 8364 for (p = 0; p < npt; ++p) 8365 if (ptpoints[p] == ccone[ccp]) break; 8366 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8367 } 8368 } 8369 } 8370 break; 8371 default: break; 8372 } 8373 for (pt = 0; pt < npt; ++pt) { 8374 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8375 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8376 } 8377 PetscFunctionReturn(0); 8378 } 8379 8380 /*@ 8381 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8382 8383 Input Parameters: 8384 + dm - The DMPlex object 8385 - cellHeight - Normally 0 8386 8387 Notes: 8388 This is a useful diagnostic when creating meshes programmatically. 8389 Currently applicable only to homogeneous simplex or tensor meshes. 8390 8391 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8392 8393 Level: developer 8394 8395 .seealso: `DMCreate()`, `DMSetFromOptions()` 8396 @*/ 8397 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) { 8398 DMPlexInterpolatedFlag interp; 8399 DMPolytopeType ct; 8400 PetscInt vStart, vEnd, cStart, cEnd, c; 8401 8402 PetscFunctionBegin; 8403 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8404 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8405 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8406 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8407 for (c = cStart; c < cEnd; ++c) { 8408 PetscInt *closure = NULL; 8409 PetscInt coneSize, closureSize, cl, Nv = 0; 8410 8411 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8412 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8413 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8414 if (interp == DMPLEX_INTERPOLATED_FULL) { 8415 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8416 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)); 8417 } 8418 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8419 for (cl = 0; cl < closureSize * 2; cl += 2) { 8420 const PetscInt p = closure[cl]; 8421 if ((p >= vStart) && (p < vEnd)) ++Nv; 8422 } 8423 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8424 /* Special Case: Tensor faces with identified vertices */ 8425 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8426 PetscInt unsplit; 8427 8428 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8429 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8430 } 8431 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)); 8432 } 8433 PetscFunctionReturn(0); 8434 } 8435 8436 /*@ 8437 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8438 8439 Collective 8440 8441 Input Parameters: 8442 + dm - The DMPlex object 8443 - cellHeight - Normally 0 8444 8445 Notes: 8446 This is a useful diagnostic when creating meshes programmatically. 8447 This routine is only relevant for meshes that are fully interpolated across all ranks. 8448 It will error out if a partially interpolated mesh is given on some rank. 8449 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8450 8451 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8452 8453 Level: developer 8454 8455 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8456 @*/ 8457 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) { 8458 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8459 DMPlexInterpolatedFlag interpEnum; 8460 8461 PetscFunctionBegin; 8462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8463 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8464 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8465 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8466 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8467 PetscFunctionReturn(0); 8468 } 8469 8470 PetscCall(DMGetDimension(dm, &dim)); 8471 PetscCall(DMPlexGetDepth(dm, &depth)); 8472 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8473 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8474 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8475 for (c = cStart; c < cEnd; ++c) { 8476 const PetscInt *cone, *ornt, *faceSizes, *faces; 8477 const DMPolytopeType *faceTypes; 8478 DMPolytopeType ct; 8479 PetscInt numFaces, coneSize, f; 8480 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8481 8482 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8483 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8484 if (unsplit) continue; 8485 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8486 PetscCall(DMPlexGetCone(dm, c, &cone)); 8487 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8488 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8489 for (cl = 0; cl < closureSize * 2; cl += 2) { 8490 const PetscInt p = closure[cl]; 8491 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8492 } 8493 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8494 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); 8495 for (f = 0; f < numFaces; ++f) { 8496 DMPolytopeType fct; 8497 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8498 8499 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8500 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8501 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8502 const PetscInt p = fclosure[cl]; 8503 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8504 } 8505 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]); 8506 for (v = 0; v < fnumCorners; ++v) { 8507 if (fclosure[v] != faces[fOff + v]) { 8508 PetscInt v1; 8509 8510 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8511 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8512 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8513 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8514 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8515 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]); 8516 } 8517 } 8518 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8519 fOff += faceSizes[f]; 8520 } 8521 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8522 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8523 } 8524 } 8525 PetscFunctionReturn(0); 8526 } 8527 8528 /*@ 8529 DMPlexCheckGeometry - Check the geometry of mesh cells 8530 8531 Input Parameter: 8532 . dm - The DMPlex object 8533 8534 Notes: 8535 This is a useful diagnostic when creating meshes programmatically. 8536 8537 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8538 8539 Level: developer 8540 8541 .seealso: `DMCreate()`, `DMSetFromOptions()` 8542 @*/ 8543 PetscErrorCode DMPlexCheckGeometry(DM dm) { 8544 Vec coordinates; 8545 PetscReal detJ, J[9], refVol = 1.0; 8546 PetscReal vol; 8547 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8548 8549 PetscFunctionBegin; 8550 PetscCall(DMGetDimension(dm, &dim)); 8551 PetscCall(DMGetCoordinateDim(dm, &dE)); 8552 if (dim != dE) PetscFunctionReturn(0); 8553 PetscCall(DMPlexGetDepth(dm, &depth)); 8554 for (d = 0; d < dim; ++d) refVol *= 2.0; 8555 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8556 /* Make sure local coordinates are created, because that step is collective */ 8557 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8558 for (c = cStart; c < cEnd; ++c) { 8559 DMPolytopeType ct; 8560 PetscInt unsplit; 8561 PetscBool ignoreZeroVol = PETSC_FALSE; 8562 8563 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8564 switch (ct) { 8565 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8566 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8567 case DM_POLYTOPE_QUAD_PRISM_TENSOR: ignoreZeroVol = PETSC_TRUE; break; 8568 default: break; 8569 } 8570 switch (ct) { 8571 case DM_POLYTOPE_TRI_PRISM: 8572 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8573 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8574 case DM_POLYTOPE_PYRAMID: continue; 8575 default: break; 8576 } 8577 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8578 if (unsplit) continue; 8579 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8580 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); 8581 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8582 /* This should work with periodicity since DG coordinates should be used */ 8583 if (depth > 1) { 8584 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8585 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); 8586 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8587 } 8588 } 8589 PetscFunctionReturn(0); 8590 } 8591 8592 /*@ 8593 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8594 8595 Collective 8596 8597 Input Parameters: 8598 + dm - The DMPlex object 8599 . pointSF - The Point SF, or NULL for Point SF attached to DM 8600 - allowExtraRoots - Flag to allow extra points not present in the DM 8601 8602 Notes: 8603 This is mainly intended for debugging/testing purposes. 8604 8605 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8606 8607 Extra roots can come from priodic cuts, where additional points appear on the boundary 8608 8609 Level: developer 8610 8611 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8612 @*/ 8613 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF, PetscBool allowExtraRoots) { 8614 PetscInt l, nleaves, nroots, overlap; 8615 const PetscInt *locals; 8616 const PetscSFNode *remotes; 8617 PetscBool distributed; 8618 MPI_Comm comm; 8619 PetscMPIInt rank; 8620 8621 PetscFunctionBegin; 8622 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8623 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8624 else pointSF = dm->sf; 8625 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8626 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8627 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8628 { 8629 PetscMPIInt mpiFlag; 8630 8631 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8632 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8633 } 8634 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8635 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8636 if (!distributed) { 8637 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); 8638 PetscFunctionReturn(0); 8639 } 8640 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); 8641 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8642 8643 /* Check SF graph is compatible with DMPlex chart */ 8644 { 8645 PetscInt pStart, pEnd, maxLeaf; 8646 8647 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8648 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8649 PetscCheck(allowExtraRoots || pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8650 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8651 } 8652 8653 /* Check Point SF has no local points referenced */ 8654 for (l = 0; l < nleaves; l++) { 8655 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); 8656 } 8657 8658 /* Check there are no cells in interface */ 8659 if (!overlap) { 8660 PetscInt cellHeight, cStart, cEnd; 8661 8662 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8663 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8664 for (l = 0; l < nleaves; ++l) { 8665 const PetscInt point = locals ? locals[l] : l; 8666 8667 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8668 } 8669 } 8670 8671 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8672 { 8673 const PetscInt *rootdegree; 8674 8675 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8676 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8677 for (l = 0; l < nleaves; ++l) { 8678 const PetscInt point = locals ? locals[l] : l; 8679 const PetscInt *cone; 8680 PetscInt coneSize, c, idx; 8681 8682 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8683 PetscCall(DMPlexGetCone(dm, point, &cone)); 8684 for (c = 0; c < coneSize; ++c) { 8685 if (!rootdegree[cone[c]]) { 8686 if (locals) { 8687 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8688 } else { 8689 idx = (cone[c] < nleaves) ? cone[c] : -1; 8690 } 8691 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8692 } 8693 } 8694 } 8695 } 8696 PetscFunctionReturn(0); 8697 } 8698 8699 /*@ 8700 DMPlexCheck - Perform various checks of Plex sanity 8701 8702 Input Parameter: 8703 . dm - The DMPlex object 8704 8705 Notes: 8706 This is a useful diagnostic when creating meshes programmatically. 8707 8708 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8709 8710 Currently does not include DMPlexCheckCellShape(). 8711 8712 Level: developer 8713 8714 .seealso: DMCreate(), DMSetFromOptions() 8715 @*/ 8716 PetscErrorCode DMPlexCheck(DM dm) { 8717 PetscInt cellHeight; 8718 8719 PetscFunctionBegin; 8720 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8721 PetscCall(DMPlexCheckSymmetry(dm)); 8722 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8723 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8724 PetscCall(DMPlexCheckGeometry(dm)); 8725 PetscCall(DMPlexCheckPointSF(dm, NULL, PETSC_FALSE)); 8726 PetscCall(DMPlexCheckInterfaceCones(dm)); 8727 PetscFunctionReturn(0); 8728 } 8729 8730 typedef struct cell_stats { 8731 PetscReal min, max, sum, squaresum; 8732 PetscInt count; 8733 } cell_stats_t; 8734 8735 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) { 8736 PetscInt i, N = *len; 8737 8738 for (i = 0; i < N; i++) { 8739 cell_stats_t *A = (cell_stats_t *)a; 8740 cell_stats_t *B = (cell_stats_t *)b; 8741 8742 B->min = PetscMin(A->min, B->min); 8743 B->max = PetscMax(A->max, B->max); 8744 B->sum += A->sum; 8745 B->squaresum += A->squaresum; 8746 B->count += A->count; 8747 } 8748 } 8749 8750 /*@ 8751 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8752 8753 Collective on dm 8754 8755 Input Parameters: 8756 + dm - The DMPlex object 8757 . output - If true, statistics will be displayed on stdout 8758 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8759 8760 Notes: 8761 This is mainly intended for debugging/testing purposes. 8762 8763 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8764 8765 Level: developer 8766 8767 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8768 @*/ 8769 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) { 8770 DM dmCoarse; 8771 cell_stats_t stats, globalStats; 8772 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8773 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8774 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8775 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8776 PetscMPIInt rank, size; 8777 8778 PetscFunctionBegin; 8779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8780 stats.min = PETSC_MAX_REAL; 8781 stats.max = PETSC_MIN_REAL; 8782 stats.sum = stats.squaresum = 0.; 8783 stats.count = 0; 8784 8785 PetscCallMPI(MPI_Comm_size(comm, &size)); 8786 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8787 PetscCall(DMGetCoordinateDim(dm, &cdim)); 8788 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8789 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 8790 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8791 for (c = cStart; c < cEnd; c++) { 8792 PetscInt i; 8793 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8794 8795 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 8796 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8797 for (i = 0; i < PetscSqr(cdim); ++i) { 8798 frobJ += J[i] * J[i]; 8799 frobInvJ += invJ[i] * invJ[i]; 8800 } 8801 cond2 = frobJ * frobInvJ; 8802 cond = PetscSqrtReal(cond2); 8803 8804 stats.min = PetscMin(stats.min, cond); 8805 stats.max = PetscMax(stats.max, cond); 8806 stats.sum += cond; 8807 stats.squaresum += cond2; 8808 stats.count++; 8809 if (output && cond > limit) { 8810 PetscSection coordSection; 8811 Vec coordsLocal; 8812 PetscScalar *coords = NULL; 8813 PetscInt Nv, d, clSize, cl, *closure = NULL; 8814 8815 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8816 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8817 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8818 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 8819 for (i = 0; i < Nv / cdim; ++i) { 8820 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8821 for (d = 0; d < cdim; ++d) { 8822 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8823 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 8824 } 8825 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8826 } 8827 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8828 for (cl = 0; cl < clSize * 2; cl += 2) { 8829 const PetscInt edge = closure[cl]; 8830 8831 if ((edge >= eStart) && (edge < eEnd)) { 8832 PetscReal len; 8833 8834 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8835 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 8836 } 8837 } 8838 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8839 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8840 } 8841 } 8842 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8843 8844 if (size > 1) { 8845 PetscMPIInt blockLengths[2] = {4, 1}; 8846 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 8847 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 8848 MPI_Op statReduce; 8849 8850 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 8851 PetscCallMPI(MPI_Type_commit(&statType)); 8852 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8853 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 8854 PetscCallMPI(MPI_Op_free(&statReduce)); 8855 PetscCallMPI(MPI_Type_free(&statType)); 8856 } else { 8857 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 8858 } 8859 if (rank == 0) { 8860 count = globalStats.count; 8861 min = globalStats.min; 8862 max = globalStats.max; 8863 mean = globalStats.sum / globalStats.count; 8864 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 8865 } 8866 8867 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)); 8868 PetscCall(PetscFree2(J, invJ)); 8869 8870 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 8871 if (dmCoarse) { 8872 PetscBool isplex; 8873 8874 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 8875 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 8876 } 8877 PetscFunctionReturn(0); 8878 } 8879 8880 /*@ 8881 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8882 orthogonal quality below given tolerance. 8883 8884 Collective on dm 8885 8886 Input Parameters: 8887 + dm - The DMPlex object 8888 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8889 - atol - [0, 1] Absolute tolerance for tagging cells. 8890 8891 Output Parameters: 8892 + OrthQual - Vec containing orthogonal quality per cell 8893 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8894 8895 Options Database Keys: 8896 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8897 supported. 8898 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8899 8900 Notes: 8901 Orthogonal quality is given by the following formula: 8902 8903 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8904 8905 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 8906 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8907 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8908 calculating the cosine of the angle between these vectors. 8909 8910 Orthogonal quality ranges from 1 (best) to 0 (worst). 8911 8912 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8913 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8914 8915 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8916 8917 Level: intermediate 8918 8919 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8920 @*/ 8921 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) { 8922 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8923 PetscInt *idx; 8924 PetscScalar *oqVals; 8925 const PetscScalar *cellGeomArr, *faceGeomArr; 8926 PetscReal *ci, *fi, *Ai; 8927 MPI_Comm comm; 8928 Vec cellgeom, facegeom; 8929 DM dmFace, dmCell; 8930 IS glob; 8931 ISLocalToGlobalMapping ltog; 8932 PetscViewer vwr; 8933 8934 PetscFunctionBegin; 8935 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8936 if (fv) PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 8937 PetscValidPointer(OrthQual, 4); 8938 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 8939 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8940 PetscCall(DMGetDimension(dm, &nc)); 8941 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8942 { 8943 DMPlexInterpolatedFlag interpFlag; 8944 8945 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8946 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8947 PetscMPIInt rank; 8948 8949 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8950 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8951 } 8952 } 8953 if (OrthQualLabel) { 8954 PetscValidPointer(OrthQualLabel, 5); 8955 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8956 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8957 } else { 8958 *OrthQualLabel = NULL; 8959 } 8960 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8961 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8962 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8963 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8964 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8965 PetscCall(VecCreate(comm, OrthQual)); 8966 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8967 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 8968 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8969 PetscCall(VecSetUp(*OrthQual)); 8970 PetscCall(ISDestroy(&glob)); 8971 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8972 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8973 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8974 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8975 PetscCall(VecGetDM(cellgeom, &dmCell)); 8976 PetscCall(VecGetDM(facegeom, &dmFace)); 8977 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8978 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 8979 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8980 PetscInt cellarr[2], *adj = NULL; 8981 PetscScalar *cArr, *fArr; 8982 PetscReal minvalc = 1.0, minvalf = 1.0; 8983 PetscFVCellGeom *cg; 8984 8985 idx[cellIter] = cell - cStart; 8986 cellarr[0] = cell; 8987 /* Make indexing into cellGeom easier */ 8988 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8989 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8990 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8991 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8992 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 8993 PetscInt i; 8994 const PetscInt neigh = adj[cellneigh]; 8995 PetscReal normci = 0, normfi = 0, normai = 0; 8996 PetscFVCellGeom *cgneigh; 8997 PetscFVFaceGeom *fg; 8998 8999 /* Don't count ourselves in the neighbor list */ 9000 if (neigh == cell) continue; 9001 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9002 cellarr[1] = neigh; 9003 { 9004 PetscInt numcovpts; 9005 const PetscInt *covpts; 9006 9007 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9008 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9009 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9010 } 9011 9012 /* Compute c_i, f_i and their norms */ 9013 for (i = 0; i < nc; i++) { 9014 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9015 fi[i] = fg->centroid[i] - cg->centroid[i]; 9016 Ai[i] = fg->normal[i]; 9017 normci += PetscPowReal(ci[i], 2); 9018 normfi += PetscPowReal(fi[i], 2); 9019 normai += PetscPowReal(Ai[i], 2); 9020 } 9021 normci = PetscSqrtReal(normci); 9022 normfi = PetscSqrtReal(normfi); 9023 normai = PetscSqrtReal(normai); 9024 9025 /* Normalize and compute for each face-cell-normal pair */ 9026 for (i = 0; i < nc; i++) { 9027 ci[i] = ci[i] / normci; 9028 fi[i] = fi[i] / normfi; 9029 Ai[i] = Ai[i] / normai; 9030 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9031 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9032 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9033 } 9034 if (PetscRealPart(cArr[cellneighiter]) < minvalc) minvalc = PetscRealPart(cArr[cellneighiter]); 9035 if (PetscRealPart(fArr[cellneighiter]) < minvalf) minvalf = PetscRealPart(fArr[cellneighiter]); 9036 } 9037 PetscCall(PetscFree(adj)); 9038 PetscCall(PetscFree2(cArr, fArr)); 9039 /* Defer to cell if they're equal */ 9040 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9041 if (OrthQualLabel) { 9042 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9043 } 9044 } 9045 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9046 PetscCall(VecAssemblyBegin(*OrthQual)); 9047 PetscCall(VecAssemblyEnd(*OrthQual)); 9048 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9049 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9050 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9051 if (OrthQualLabel) { 9052 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9053 } 9054 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9055 PetscCall(PetscViewerDestroy(&vwr)); 9056 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9057 PetscFunctionReturn(0); 9058 } 9059 9060 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9061 * interpolator construction */ 9062 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) { 9063 PetscSection section, newSection, gsection; 9064 PetscSF sf; 9065 PetscBool hasConstraints, ghasConstraints; 9066 9067 PetscFunctionBegin; 9068 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9069 PetscValidPointer(odm, 2); 9070 PetscCall(DMGetLocalSection(dm, §ion)); 9071 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9072 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9073 if (!ghasConstraints) { 9074 PetscCall(PetscObjectReference((PetscObject)dm)); 9075 *odm = dm; 9076 PetscFunctionReturn(0); 9077 } 9078 PetscCall(DMClone(dm, odm)); 9079 PetscCall(DMCopyFields(dm, *odm)); 9080 PetscCall(DMGetLocalSection(*odm, &newSection)); 9081 PetscCall(DMGetPointSF(*odm, &sf)); 9082 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9083 PetscCall(DMSetGlobalSection(*odm, gsection)); 9084 PetscCall(PetscSectionDestroy(&gsection)); 9085 PetscFunctionReturn(0); 9086 } 9087 9088 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) { 9089 DM dmco, dmfo; 9090 Mat interpo; 9091 Vec rscale; 9092 Vec cglobalo, clocal; 9093 Vec fglobal, fglobalo, flocal; 9094 PetscBool regular; 9095 9096 PetscFunctionBegin; 9097 PetscCall(DMGetFullDM(dmc, &dmco)); 9098 PetscCall(DMGetFullDM(dmf, &dmfo)); 9099 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9100 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9101 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9102 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9103 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9104 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9105 PetscCall(VecSet(cglobalo, 0.)); 9106 PetscCall(VecSet(clocal, 0.)); 9107 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9108 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9109 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9110 PetscCall(VecSet(fglobal, 0.)); 9111 PetscCall(VecSet(fglobalo, 0.)); 9112 PetscCall(VecSet(flocal, 0.)); 9113 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9114 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9115 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9116 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9117 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9118 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9119 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9120 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9121 *shift = fglobal; 9122 PetscCall(VecDestroy(&flocal)); 9123 PetscCall(VecDestroy(&fglobalo)); 9124 PetscCall(VecDestroy(&clocal)); 9125 PetscCall(VecDestroy(&cglobalo)); 9126 PetscCall(VecDestroy(&rscale)); 9127 PetscCall(MatDestroy(&interpo)); 9128 PetscCall(DMDestroy(&dmfo)); 9129 PetscCall(DMDestroy(&dmco)); 9130 PetscFunctionReturn(0); 9131 } 9132 9133 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) { 9134 PetscObject shifto; 9135 Vec shift; 9136 9137 PetscFunctionBegin; 9138 if (!interp) { 9139 Vec rscale; 9140 9141 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9142 PetscCall(VecDestroy(&rscale)); 9143 } else { 9144 PetscCall(PetscObjectReference((PetscObject)interp)); 9145 } 9146 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9147 if (!shifto) { 9148 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9149 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9150 shifto = (PetscObject)shift; 9151 PetscCall(VecDestroy(&shift)); 9152 } 9153 shift = (Vec)shifto; 9154 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9155 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9156 PetscCall(MatDestroy(&interp)); 9157 PetscFunctionReturn(0); 9158 } 9159 9160 /* Pointwise interpolation 9161 Just code FEM for now 9162 u^f = I u^c 9163 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9164 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9165 I_{ij} = psi^f_i phi^c_j 9166 */ 9167 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) { 9168 PetscSection gsc, gsf; 9169 PetscInt m, n; 9170 void *ctx; 9171 DM cdm; 9172 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9173 9174 PetscFunctionBegin; 9175 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9176 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9177 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9178 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9179 9180 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9181 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9182 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9183 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9184 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9185 9186 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9187 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9188 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9189 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9190 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9191 if (scaling) { 9192 /* Use naive scaling */ 9193 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9194 } 9195 PetscFunctionReturn(0); 9196 } 9197 9198 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) { 9199 VecScatter ctx; 9200 9201 PetscFunctionBegin; 9202 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9203 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9204 PetscCall(VecScatterDestroy(&ctx)); 9205 PetscFunctionReturn(0); 9206 } 9207 9208 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[]) { 9209 const PetscInt Nc = uOff[1] - uOff[0]; 9210 PetscInt c; 9211 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9212 } 9213 9214 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) { 9215 DM dmc; 9216 PetscDS ds; 9217 Vec ones, locmass; 9218 IS cellIS; 9219 PetscFormKey key; 9220 PetscInt depth; 9221 9222 PetscFunctionBegin; 9223 PetscCall(DMClone(dm, &dmc)); 9224 PetscCall(DMCopyDisc(dm, dmc)); 9225 PetscCall(DMGetDS(dmc, &ds)); 9226 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9227 PetscCall(DMCreateGlobalVector(dmc, mass)); 9228 PetscCall(DMGetLocalVector(dmc, &ones)); 9229 PetscCall(DMGetLocalVector(dmc, &locmass)); 9230 PetscCall(DMPlexGetDepth(dmc, &depth)); 9231 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9232 PetscCall(VecSet(locmass, 0.0)); 9233 PetscCall(VecSet(ones, 1.0)); 9234 key.label = NULL; 9235 key.value = 0; 9236 key.field = 0; 9237 key.part = 0; 9238 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9239 PetscCall(ISDestroy(&cellIS)); 9240 PetscCall(VecSet(*mass, 0.0)); 9241 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9242 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9243 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9244 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9245 PetscCall(DMDestroy(&dmc)); 9246 PetscFunctionReturn(0); 9247 } 9248 9249 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) { 9250 PetscSection gsc, gsf; 9251 PetscInt m, n; 9252 void *ctx; 9253 DM cdm; 9254 PetscBool regular; 9255 9256 PetscFunctionBegin; 9257 if (dmFine == dmCoarse) { 9258 DM dmc; 9259 PetscDS ds; 9260 PetscWeakForm wf; 9261 Vec u; 9262 IS cellIS; 9263 PetscFormKey key; 9264 PetscInt depth; 9265 9266 PetscCall(DMClone(dmFine, &dmc)); 9267 PetscCall(DMCopyDisc(dmFine, dmc)); 9268 PetscCall(DMGetDS(dmc, &ds)); 9269 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9270 PetscCall(PetscWeakFormClear(wf)); 9271 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9272 PetscCall(DMCreateMatrix(dmc, mass)); 9273 PetscCall(DMGetLocalVector(dmc, &u)); 9274 PetscCall(DMPlexGetDepth(dmc, &depth)); 9275 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9276 PetscCall(MatZeroEntries(*mass)); 9277 key.label = NULL; 9278 key.value = 0; 9279 key.field = 0; 9280 key.part = 0; 9281 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9282 PetscCall(ISDestroy(&cellIS)); 9283 PetscCall(DMRestoreLocalVector(dmc, &u)); 9284 PetscCall(DMDestroy(&dmc)); 9285 } else { 9286 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9287 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9288 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9289 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9290 9291 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9292 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9293 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9294 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9295 9296 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9297 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9298 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9299 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9300 } 9301 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9302 PetscFunctionReturn(0); 9303 } 9304 9305 /*@ 9306 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9307 9308 Input Parameter: 9309 . dm - The DMPlex object 9310 9311 Output Parameter: 9312 . regular - The flag 9313 9314 Level: intermediate 9315 9316 .seealso: `DMPlexSetRegularRefinement()` 9317 @*/ 9318 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) { 9319 PetscFunctionBegin; 9320 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9321 PetscValidBoolPointer(regular, 2); 9322 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9323 PetscFunctionReturn(0); 9324 } 9325 9326 /*@ 9327 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9328 9329 Input Parameters: 9330 + dm - The DMPlex object 9331 - regular - The flag 9332 9333 Level: intermediate 9334 9335 .seealso: `DMPlexGetRegularRefinement()` 9336 @*/ 9337 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) { 9338 PetscFunctionBegin; 9339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9340 ((DM_Plex *)dm->data)->regularRefinement = regular; 9341 PetscFunctionReturn(0); 9342 } 9343 9344 /* anchors */ 9345 /*@ 9346 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9347 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9348 9349 not collective 9350 9351 Input Parameter: 9352 . dm - The DMPlex object 9353 9354 Output Parameters: 9355 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9356 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9357 9358 Level: intermediate 9359 9360 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9361 @*/ 9362 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) { 9363 DM_Plex *plex = (DM_Plex *)dm->data; 9364 9365 PetscFunctionBegin; 9366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9367 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9368 if (anchorSection) *anchorSection = plex->anchorSection; 9369 if (anchorIS) *anchorIS = plex->anchorIS; 9370 PetscFunctionReturn(0); 9371 } 9372 9373 /*@ 9374 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9375 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9376 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9377 9378 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9379 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9380 9381 collective on dm 9382 9383 Input Parameters: 9384 + dm - The DMPlex object 9385 . 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). 9386 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9387 9388 The reference counts of anchorSection and anchorIS are incremented. 9389 9390 Level: intermediate 9391 9392 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9393 @*/ 9394 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) { 9395 DM_Plex *plex = (DM_Plex *)dm->data; 9396 PetscMPIInt result; 9397 9398 PetscFunctionBegin; 9399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9400 if (anchorSection) { 9401 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9402 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9403 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9404 } 9405 if (anchorIS) { 9406 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9407 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9408 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9409 } 9410 9411 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9412 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9413 plex->anchorSection = anchorSection; 9414 9415 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9416 PetscCall(ISDestroy(&plex->anchorIS)); 9417 plex->anchorIS = anchorIS; 9418 9419 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9420 PetscInt size, a, pStart, pEnd; 9421 const PetscInt *anchors; 9422 9423 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9424 PetscCall(ISGetLocalSize(anchorIS, &size)); 9425 PetscCall(ISGetIndices(anchorIS, &anchors)); 9426 for (a = 0; a < size; a++) { 9427 PetscInt p; 9428 9429 p = anchors[a]; 9430 if (p >= pStart && p < pEnd) { 9431 PetscInt dof; 9432 9433 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9434 if (dof) { 9435 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9436 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9437 } 9438 } 9439 } 9440 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9441 } 9442 /* reset the generic constraints */ 9443 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9444 PetscFunctionReturn(0); 9445 } 9446 9447 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) { 9448 PetscSection anchorSection; 9449 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9450 9451 PetscFunctionBegin; 9452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9453 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9454 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9455 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9456 if (numFields) { 9457 PetscInt f; 9458 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9459 9460 for (f = 0; f < numFields; f++) { 9461 PetscInt numComp; 9462 9463 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9464 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9465 } 9466 } 9467 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9468 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9469 pStart = PetscMax(pStart, sStart); 9470 pEnd = PetscMin(pEnd, sEnd); 9471 pEnd = PetscMax(pStart, pEnd); 9472 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9473 for (p = pStart; p < pEnd; p++) { 9474 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9475 if (dof) { 9476 PetscCall(PetscSectionGetDof(section, p, &dof)); 9477 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9478 for (f = 0; f < numFields; f++) { 9479 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9480 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9481 } 9482 } 9483 } 9484 PetscCall(PetscSectionSetUp(*cSec)); 9485 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9486 PetscFunctionReturn(0); 9487 } 9488 9489 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) { 9490 PetscSection aSec; 9491 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9492 const PetscInt *anchors; 9493 PetscInt numFields, f; 9494 IS aIS; 9495 MatType mtype; 9496 PetscBool iscuda, iskokkos; 9497 9498 PetscFunctionBegin; 9499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9500 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9501 PetscCall(PetscSectionGetStorageSize(section, &n)); 9502 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9503 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9504 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9505 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9506 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9507 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9508 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9509 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9510 else mtype = MATSEQAIJ; 9511 PetscCall(MatSetType(*cMat, mtype)); 9512 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9513 PetscCall(ISGetIndices(aIS, &anchors)); 9514 /* cSec will be a subset of aSec and section */ 9515 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9516 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9517 PetscCall(PetscMalloc1(m + 1, &i)); 9518 i[0] = 0; 9519 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9520 for (p = pStart; p < pEnd; p++) { 9521 PetscInt rDof, rOff, r; 9522 9523 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9524 if (!rDof) continue; 9525 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9526 if (numFields) { 9527 for (f = 0; f < numFields; f++) { 9528 annz = 0; 9529 for (r = 0; r < rDof; r++) { 9530 a = anchors[rOff + r]; 9531 if (a < sStart || a >= sEnd) continue; 9532 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9533 annz += aDof; 9534 } 9535 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9536 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9537 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9538 } 9539 } else { 9540 annz = 0; 9541 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9542 for (q = 0; q < dof; q++) { 9543 a = anchors[rOff + q]; 9544 if (a < sStart || a >= sEnd) continue; 9545 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9546 annz += aDof; 9547 } 9548 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9549 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9550 for (q = 0; q < dof; q++) i[off + q + 1] = i[off + q] + annz; 9551 } 9552 } 9553 nnz = i[m]; 9554 PetscCall(PetscMalloc1(nnz, &j)); 9555 offset = 0; 9556 for (p = pStart; p < pEnd; p++) { 9557 if (numFields) { 9558 for (f = 0; f < numFields; f++) { 9559 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9560 for (q = 0; q < dof; q++) { 9561 PetscInt rDof, rOff, r; 9562 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9563 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9564 for (r = 0; r < rDof; r++) { 9565 PetscInt s; 9566 9567 a = anchors[rOff + r]; 9568 if (a < sStart || a >= sEnd) continue; 9569 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9570 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9571 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9572 } 9573 } 9574 } 9575 } else { 9576 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9577 for (q = 0; q < dof; q++) { 9578 PetscInt rDof, rOff, r; 9579 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9580 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9581 for (r = 0; r < rDof; r++) { 9582 PetscInt s; 9583 9584 a = anchors[rOff + r]; 9585 if (a < sStart || a >= sEnd) continue; 9586 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9587 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9588 for (s = 0; s < aDof; s++) j[offset++] = aOff + s; 9589 } 9590 } 9591 } 9592 } 9593 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9594 PetscCall(PetscFree(i)); 9595 PetscCall(PetscFree(j)); 9596 PetscCall(ISRestoreIndices(aIS, &anchors)); 9597 PetscFunctionReturn(0); 9598 } 9599 9600 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) { 9601 DM_Plex *plex = (DM_Plex *)dm->data; 9602 PetscSection anchorSection, section, cSec; 9603 Mat cMat; 9604 9605 PetscFunctionBegin; 9606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9607 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9608 if (anchorSection) { 9609 PetscInt Nf; 9610 9611 PetscCall(DMGetLocalSection(dm, §ion)); 9612 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9613 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9614 PetscCall(DMGetNumFields(dm, &Nf)); 9615 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9616 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9617 PetscCall(PetscSectionDestroy(&cSec)); 9618 PetscCall(MatDestroy(&cMat)); 9619 } 9620 PetscFunctionReturn(0); 9621 } 9622 9623 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) { 9624 IS subis; 9625 PetscSection section, subsection; 9626 9627 PetscFunctionBegin; 9628 PetscCall(DMGetLocalSection(dm, §ion)); 9629 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9630 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9631 /* Create subdomain */ 9632 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9633 /* Create submodel */ 9634 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9635 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9636 PetscCall(DMSetLocalSection(*subdm, subsection)); 9637 PetscCall(PetscSectionDestroy(&subsection)); 9638 PetscCall(DMCopyDisc(dm, *subdm)); 9639 /* Create map from submodel to global model */ 9640 if (is) { 9641 PetscSection sectionGlobal, subsectionGlobal; 9642 IS spIS; 9643 const PetscInt *spmap; 9644 PetscInt *subIndices; 9645 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9646 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9647 9648 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9649 PetscCall(ISGetIndices(spIS, &spmap)); 9650 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9651 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9652 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9653 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9654 for (p = pStart; p < pEnd; ++p) { 9655 PetscInt gdof, pSubSize = 0; 9656 9657 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9658 if (gdof > 0) { 9659 for (f = 0; f < Nf; ++f) { 9660 PetscInt fdof, fcdof; 9661 9662 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9663 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9664 pSubSize += fdof - fcdof; 9665 } 9666 subSize += pSubSize; 9667 if (pSubSize) { 9668 if (bs < 0) { 9669 bs = pSubSize; 9670 } else if (bs != pSubSize) { 9671 /* Layout does not admit a pointwise block size */ 9672 bs = 1; 9673 } 9674 } 9675 } 9676 } 9677 /* Must have same blocksize on all procs (some might have no points) */ 9678 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9679 bsLocal[1] = bs; 9680 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9681 if (bsMinMax[0] != bsMinMax[1]) { 9682 bs = 1; 9683 } else { 9684 bs = bsMinMax[0]; 9685 } 9686 PetscCall(PetscMalloc1(subSize, &subIndices)); 9687 for (p = pStart; p < pEnd; ++p) { 9688 PetscInt gdof, goff; 9689 9690 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9691 if (gdof > 0) { 9692 const PetscInt point = spmap[p]; 9693 9694 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9695 for (f = 0; f < Nf; ++f) { 9696 PetscInt fdof, fcdof, fc, f2, poff = 0; 9697 9698 /* Can get rid of this loop by storing field information in the global section */ 9699 for (f2 = 0; f2 < f; ++f2) { 9700 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9701 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9702 poff += fdof - fcdof; 9703 } 9704 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9705 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9706 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) subIndices[subOff] = goff + poff + fc; 9707 } 9708 } 9709 } 9710 PetscCall(ISRestoreIndices(spIS, &spmap)); 9711 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9712 if (bs > 1) { 9713 /* We need to check that the block size does not come from non-contiguous fields */ 9714 PetscInt i, j, set = 1; 9715 for (i = 0; i < subSize; i += bs) { 9716 for (j = 0; j < bs; ++j) { 9717 if (subIndices[i + j] != subIndices[i] + j) { 9718 set = 0; 9719 break; 9720 } 9721 } 9722 } 9723 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9724 } 9725 /* Attach nullspace */ 9726 for (f = 0; f < Nf; ++f) { 9727 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9728 if ((*subdm)->nullspaceConstructors[f]) break; 9729 } 9730 if (f < Nf) { 9731 MatNullSpace nullSpace; 9732 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9733 9734 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9735 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9736 } 9737 } 9738 PetscFunctionReturn(0); 9739 } 9740 9741 /*@ 9742 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9743 9744 Input Parameter: 9745 - dm - The DM 9746 9747 Level: developer 9748 9749 Options Database Keys: 9750 . -dm_plex_monitor_throughput - Activate the monitor 9751 9752 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9753 @*/ 9754 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) { 9755 #if defined(PETSC_USE_LOG) 9756 PetscStageLog stageLog; 9757 PetscLogEvent event; 9758 PetscLogStage stage; 9759 PetscEventPerfInfo eventInfo; 9760 PetscReal cellRate, flopRate; 9761 PetscInt cStart, cEnd, Nf, N; 9762 const char *name; 9763 #endif 9764 9765 PetscFunctionBegin; 9766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9767 #if defined(PETSC_USE_LOG) 9768 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 9769 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9770 PetscCall(DMGetNumFields(dm, &Nf)); 9771 PetscCall(PetscLogGetStageLog(&stageLog)); 9772 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9773 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9774 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9775 N = (cEnd - cStart) * Nf * eventInfo.count; 9776 flopRate = eventInfo.flops / eventInfo.time; 9777 cellRate = N / eventInfo.time; 9778 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))); 9779 #else 9780 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9781 #endif 9782 PetscFunctionReturn(0); 9783 } 9784