1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> 3 #include <petsc/private/isimpl.h> 4 #include <petsc/private/vecimpl.h> 5 #include <petsc/private/glvisvecimpl.h> 6 #include <petscsf.h> 7 #include <petscds.h> 8 #include <petscdraw.h> 9 #include <petscdmfield.h> 10 #include <petscdmplextransform.h> 11 12 /* Logging support */ 13 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF, DMPLEX_LocatePoints, DMPLEX_TopologyView, DMPLEX_LabelsView, DMPLEX_CoordinatesView, DMPLEX_SectionView, DMPLEX_GlobalVectorView, DMPLEX_LocalVectorView, DMPLEX_TopologyLoad, DMPLEX_LabelsLoad, DMPLEX_CoordinatesLoad, DMPLEX_SectionLoad, DMPLEX_GlobalVectorLoad, DMPLEX_LocalVectorLoad; 14 PetscLogEvent DMPLEX_RebalBuildGraph, DMPLEX_RebalRewriteSF, DMPLEX_RebalGatherGraph, DMPLEX_RebalPartition, DMPLEX_RebalScatterPart; 15 16 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 17 18 /*@ 19 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 20 21 Input Parameter: 22 . dm - The DMPlex object 23 24 Output Parameter: 25 . simplex - Flag checking for a simplex 26 27 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 28 If the mesh has no cells, this returns PETSC_FALSE. 29 30 Level: intermediate 31 32 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 33 @*/ 34 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) { 35 DMPolytopeType ct; 36 PetscInt cStart, cEnd; 37 38 PetscFunctionBegin; 39 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 40 if (cEnd <= cStart) { 41 *simplex = PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 45 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 46 PetscFunctionReturn(0); 47 } 48 49 /*@ 50 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 51 52 Input Parameters: 53 + dm - The DMPlex object 54 - height - The cell height in the Plex, 0 is the default 55 56 Output Parameters: 57 + cStart - The first "normal" cell 58 - cEnd - The upper bound on "normal"" cells 59 60 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 61 62 Level: developer 63 64 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 65 @*/ 66 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) { 67 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 68 PetscInt cS, cE, c; 69 70 PetscFunctionBegin; 71 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 72 for (c = cS; c < cE; ++c) { 73 DMPolytopeType cct; 74 75 PetscCall(DMPlexGetCellType(dm, c, &cct)); 76 if ((PetscInt)cct < 0) break; 77 switch (cct) { 78 case DM_POLYTOPE_POINT: 79 case DM_POLYTOPE_SEGMENT: 80 case DM_POLYTOPE_TRIANGLE: 81 case DM_POLYTOPE_QUADRILATERAL: 82 case DM_POLYTOPE_TETRAHEDRON: 83 case DM_POLYTOPE_HEXAHEDRON: ct = cct; break; 84 default: break; 85 } 86 if (ct != DM_POLYTOPE_UNKNOWN) break; 87 } 88 if (ct != DM_POLYTOPE_UNKNOWN) { 89 DMLabel ctLabel; 90 91 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 92 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 93 // Reset label for fast lookup 94 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 95 } 96 if (cStart) *cStart = cS; 97 if (cEnd) *cEnd = cE; 98 PetscFunctionReturn(0); 99 } 100 101 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) { 102 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 103 PetscInt vcdof[2] = {0, 0}, globalvcdof[2]; 104 105 PetscFunctionBegin; 106 *ft = PETSC_VTK_INVALID; 107 PetscCall(DMGetCoordinateDim(dm, &cdim)); 108 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 109 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 110 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 111 if (field >= 0) { 112 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 113 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 114 } else { 115 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 116 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 117 } 118 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 119 if (globalvcdof[0]) { 120 *sStart = vStart; 121 *sEnd = vEnd; 122 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 123 else *ft = PETSC_VTK_POINT_FIELD; 124 } else if (globalvcdof[1]) { 125 *sStart = cStart; 126 *sEnd = cEnd; 127 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 128 else *ft = PETSC_VTK_CELL_FIELD; 129 } else { 130 if (field >= 0) { 131 const char *fieldname; 132 133 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 134 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 135 } else { 136 PetscCall(PetscInfo((PetscObject)dm, "Could not classify VTK output type of section\n")); 137 } 138 } 139 PetscFunctionReturn(0); 140 } 141 142 /*@ 143 DMPlexVecView1D - Plot many 1D solutions on the same line graph 144 145 Collective on dm 146 147 Input Parameters: 148 + dm - The DMPlex 149 . n - The number of vectors 150 . u - The array of local vectors 151 - viewer - The Draw viewer 152 153 Level: advanced 154 155 .seealso: `VecViewFromOptions()`, `VecView()` 156 @*/ 157 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) { 158 PetscDS ds; 159 PetscDraw draw = NULL; 160 PetscDrawLG lg; 161 Vec coordinates; 162 const PetscScalar *coords, **sol; 163 PetscReal *vals; 164 PetscInt *Nc; 165 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 166 char **names; 167 168 PetscFunctionBegin; 169 PetscCall(DMGetDS(dm, &ds)); 170 PetscCall(PetscDSGetNumFields(ds, &Nf)); 171 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 172 PetscCall(PetscDSGetComponents(ds, &Nc)); 173 174 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 175 if (!draw) PetscFunctionReturn(0); 176 PetscCall(PetscDrawLGCreate(draw, n * Nl, &lg)); 177 178 PetscCall(PetscMalloc3(n, &sol, n * Nl, &names, n * Nl, &vals)); 179 for (i = 0, l = 0; i < n; ++i) { 180 const char *vname; 181 182 PetscCall(PetscObjectGetName((PetscObject)u[i], &vname)); 183 for (f = 0; f < Nf; ++f) { 184 PetscObject disc; 185 const char *fname; 186 char tmpname[PETSC_MAX_PATH_LEN]; 187 188 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 189 /* TODO Create names for components */ 190 for (c = 0; c < Nc[f]; ++c, ++l) { 191 PetscCall(PetscObjectGetName(disc, &fname)); 192 PetscCall(PetscStrcpy(tmpname, vname)); 193 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 195 PetscCall(PetscStrallocpy(tmpname, &names[l])); 196 } 197 } 198 } 199 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *)names)); 200 /* Just add P_1 support for now */ 201 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 202 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 203 PetscCall(VecGetArrayRead(coordinates, &coords)); 204 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 205 for (v = vStart; v < vEnd; ++v) { 206 PetscScalar *x, *svals; 207 208 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 209 for (i = 0; i < n; ++i) { 210 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 211 for (l = 0; l < Nl; ++l) vals[i * Nl + l] = PetscRealPart(svals[l]); 212 } 213 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 214 } 215 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 216 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 217 for (l = 0; l < n * Nl; ++l) PetscCall(PetscFree(names[l])); 218 PetscCall(PetscFree3(sol, names, vals)); 219 220 PetscCall(PetscDrawLGDraw(lg)); 221 PetscCall(PetscDrawLGDestroy(&lg)); 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) { 235 DM dm; 236 PetscSection s; 237 PetscDraw draw, popup; 238 DM cdm; 239 PetscSection coordSection; 240 Vec coordinates; 241 const PetscScalar *coords, *array; 242 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 243 PetscReal vbound[2], time; 244 PetscBool flg; 245 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 246 const char *name; 247 char title[PETSC_MAX_PATH_LEN]; 248 249 PetscFunctionBegin; 250 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 251 PetscCall(VecGetDM(v, &dm)); 252 PetscCall(DMGetCoordinateDim(dm, &dim)); 253 PetscCall(DMGetLocalSection(dm, &s)); 254 PetscCall(PetscSectionGetNumFields(s, &Nf)); 255 PetscCall(DMGetCoarsenLevel(dm, &level)); 256 PetscCall(DMGetCoordinateDM(dm, &cdm)); 257 PetscCall(DMGetLocalSection(cdm, &coordSection)); 258 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 259 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 260 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 261 262 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 263 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 264 265 PetscCall(VecGetLocalSize(coordinates, &N)); 266 PetscCall(VecGetArrayRead(coordinates, &coords)); 267 for (c = 0; c < N; c += dim) { 268 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 269 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 271 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 272 } 273 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 274 PetscCall(PetscDrawClear(draw)); 275 276 /* Could implement something like DMDASelectFields() */ 277 for (f = 0; f < Nf; ++f) { 278 DM fdm = dm; 279 Vec fv = v; 280 IS fis; 281 char prefix[PETSC_MAX_PATH_LEN]; 282 const char *fname; 283 284 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 285 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 286 287 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix, sizeof(prefix))); 288 else { prefix[0] = '\0'; } 289 if (Nf > 1) { 290 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 291 PetscCall(VecGetSubVector(v, fis, &fv)); 292 PetscCall(PetscStrlcat(prefix, fname, sizeof(prefix))); 293 PetscCall(PetscStrlcat(prefix, "_", sizeof(prefix))); 294 } 295 for (comp = 0; comp < Nc; ++comp, ++w) { 296 PetscInt nmax = 2; 297 298 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 299 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 300 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 301 PetscCall(PetscDrawSetTitle(draw, title)); 302 303 /* TODO Get max and min only for this component */ 304 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 305 if (!flg) { 306 PetscCall(VecMin(fv, NULL, &vbound[0])); 307 PetscCall(VecMax(fv, NULL, &vbound[1])); 308 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 309 } 310 PetscCall(PetscDrawGetPopup(draw, &popup)); 311 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 312 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 313 314 PetscCall(VecGetArrayRead(fv, &array)); 315 for (c = cStart; c < cEnd; ++c) { 316 PetscScalar *coords = NULL, *a = NULL; 317 PetscInt numCoords, color[4] = {-1, -1, -1, -1}; 318 319 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 320 if (a) { 321 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 322 color[1] = color[2] = color[3] = color[0]; 323 } else { 324 PetscScalar *vals = NULL; 325 PetscInt numVals, va; 326 327 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 328 PetscCheck(numVals % Nc == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 329 switch (numVals / Nc) { 330 case 3: /* P1 Triangle */ 331 case 4: /* P1 Quadrangle */ 332 for (va = 0; va < numVals / Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp]), vbound[0], vbound[1]); 333 break; 334 case 6: /* P2 Triangle */ 335 case 8: /* P2 Quadrangle */ 336 for (va = 0; va < numVals / (Nc * 2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va * Nc + comp + numVals / (Nc * 2)]), vbound[0], vbound[1]); 337 break; 338 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals / Nc); 339 } 340 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 341 } 342 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 343 switch (numCoords) { 344 case 6: 345 case 12: /* Localized triangle */ 346 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 347 break; 348 case 8: 349 case 16: /* Localized quadrilateral */ 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 351 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 352 break; 353 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 354 } 355 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 356 } 357 PetscCall(VecRestoreArrayRead(fv, &array)); 358 PetscCall(PetscDrawFlush(draw)); 359 PetscCall(PetscDrawPause(draw)); 360 PetscCall(PetscDrawSave(draw)); 361 } 362 if (Nf > 1) { 363 PetscCall(VecRestoreSubVector(v, fis, &fv)); 364 PetscCall(ISDestroy(&fis)); 365 PetscCall(DMDestroy(&fdm)); 366 } 367 } 368 PetscFunctionReturn(0); 369 } 370 371 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer)); break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer)); break; 387 default: SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) { 393 DM dm; 394 Vec locv; 395 const char *name; 396 PetscSection section; 397 PetscInt pStart, pEnd; 398 PetscInt numFields; 399 PetscViewerVTKFieldType ft; 400 401 PetscFunctionBegin; 402 PetscCall(VecGetDM(v, &dm)); 403 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 404 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 405 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 406 PetscCall(VecCopy(v, locv)); 407 PetscCall(DMGetLocalSection(dm, §ion)); 408 PetscCall(PetscSectionGetNumFields(section, &numFields)); 409 if (!numFields) { 410 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 411 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE, (PetscObject)locv)); 412 } else { 413 PetscInt f; 414 415 for (f = 0; f < numFields; f++) { 416 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 417 if (ft == PETSC_VTK_INVALID) continue; 418 PetscCall(PetscObjectReference((PetscObject)locv)); 419 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject)dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE, (PetscObject)locv)); 420 } 421 PetscCall(VecDestroy(&locv)); 422 } 423 PetscFunctionReturn(0); 424 } 425 426 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) { 427 DM dm; 428 PetscBool isvtk, ishdf5, isdraw, isglvis, iscgns; 429 430 PetscFunctionBegin; 431 PetscCall(VecGetDM(v, &dm)); 432 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 433 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 434 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 436 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 437 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 438 if (isvtk || ishdf5 || isdraw || isglvis || iscgns) { 439 PetscInt i, numFields; 440 PetscObject fe; 441 PetscBool fem = PETSC_FALSE; 442 Vec locv = v; 443 const char *name; 444 PetscInt step; 445 PetscReal time; 446 447 PetscCall(DMGetNumFields(dm, &numFields)); 448 for (i = 0; i < numFields; i++) { 449 PetscCall(DMGetField(dm, i, NULL, &fe)); 450 if (fe->classid == PETSCFE_CLASSID) { 451 fem = PETSC_TRUE; 452 break; 453 } 454 } 455 if (fem) { 456 PetscObject isZero; 457 458 PetscCall(DMGetLocalVector(dm, &locv)); 459 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 460 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 461 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 462 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 463 PetscCall(VecCopy(v, locv)); 464 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 465 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 466 } 467 if (isvtk) { 468 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 469 } else if (ishdf5) { 470 #if defined(PETSC_HAVE_HDF5) 471 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 472 #else 473 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 474 #endif 475 } else if (isdraw) { 476 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 477 } else if (isglvis) { 478 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 479 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 480 PetscCall(VecView_GLVis(locv, viewer)); 481 } else if (iscgns) { 482 #if defined(PETSC_HAVE_CGNS) 483 PetscCall(VecView_Plex_Local_CGNS(locv, viewer)); 484 #else 485 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CGNS not supported in this build.\nPlease reconfigure using --download-cgns"); 486 #endif 487 } 488 if (fem) { 489 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 490 PetscCall(DMRestoreLocalVector(dm, &locv)); 491 } 492 } else { 493 PetscBool isseq; 494 495 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 496 if (isseq) PetscCall(VecView_Seq(v, viewer)); 497 else PetscCall(VecView_MPI(v, viewer)); 498 } 499 PetscFunctionReturn(0); 500 } 501 502 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) { 503 DM dm; 504 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii, iscgns; 505 506 PetscFunctionBegin; 507 PetscCall(VecGetDM(v, &dm)); 508 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 509 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 510 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 511 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 512 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 513 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 514 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 515 if (isvtk || isdraw || isglvis || iscgns) { 516 Vec locv; 517 PetscObject isZero; 518 const char *name; 519 520 PetscCall(DMGetLocalVector(dm, &locv)); 521 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 522 PetscCall(PetscObjectSetName((PetscObject)locv, name)); 523 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 524 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 525 PetscCall(PetscObjectQuery((PetscObject)v, "__Vec_bc_zero__", &isZero)); 526 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", isZero)); 527 PetscCall(VecView_Plex_Local(locv, viewer)); 528 PetscCall(PetscObjectCompose((PetscObject)locv, "__Vec_bc_zero__", NULL)); 529 PetscCall(DMRestoreLocalVector(dm, &locv)); 530 } else if (ishdf5) { 531 #if defined(PETSC_HAVE_HDF5) 532 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 533 #else 534 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 535 #endif 536 } else if (isexodusii) { 537 #if defined(PETSC_HAVE_EXODUSII) 538 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 539 #else 540 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 541 #endif 542 } else { 543 PetscBool isseq; 544 545 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 546 if (isseq) PetscCall(VecView_Seq(v, viewer)); 547 else PetscCall(VecView_MPI(v, viewer)); 548 } 549 PetscFunctionReturn(0); 550 } 551 552 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) { 553 DM dm; 554 MPI_Comm comm; 555 PetscViewerFormat format; 556 Vec v; 557 PetscBool isvtk, ishdf5; 558 559 PetscFunctionBegin; 560 PetscCall(VecGetDM(originalv, &dm)); 561 PetscCall(PetscObjectGetComm((PetscObject)originalv, &comm)); 562 PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 563 PetscCall(PetscViewerGetFormat(viewer, &format)); 564 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 565 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 566 if (format == PETSC_VIEWER_NATIVE) { 567 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 568 /* this need a better fix */ 569 if (dm->useNatural) { 570 if (dm->sfNatural) { 571 const char *vecname; 572 PetscInt n, nroots; 573 574 PetscCall(VecGetLocalSize(originalv, &n)); 575 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 576 if (n == nroots) { 577 PetscCall(DMGetGlobalVector(dm, &v)); 578 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 579 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 580 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 581 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 582 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 583 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 584 } else v = originalv; 585 } else v = originalv; 586 587 if (ishdf5) { 588 #if defined(PETSC_HAVE_HDF5) 589 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 590 #else 591 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 592 #endif 593 } else if (isvtk) { 594 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 595 } else { 596 PetscBool isseq; 597 598 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 599 if (isseq) PetscCall(VecView_Seq(v, viewer)); 600 else PetscCall(VecView_MPI(v, viewer)); 601 } 602 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 603 PetscFunctionReturn(0); 604 } 605 606 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) { 607 DM dm; 608 PetscBool ishdf5; 609 610 PetscFunctionBegin; 611 PetscCall(VecGetDM(v, &dm)); 612 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 613 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 614 if (ishdf5) { 615 DM dmBC; 616 Vec gv; 617 const char *name; 618 619 PetscCall(DMGetOutputDM(dm, &dmBC)); 620 PetscCall(DMGetGlobalVector(dmBC, &gv)); 621 PetscCall(PetscObjectGetName((PetscObject)v, &name)); 622 PetscCall(PetscObjectSetName((PetscObject)gv, name)); 623 PetscCall(VecLoad_Default(gv, viewer)); 624 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 625 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 626 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 627 } else PetscCall(VecLoad_Default(v, viewer)); 628 PetscFunctionReturn(0); 629 } 630 631 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) { 632 DM dm; 633 PetscBool ishdf5, isexodusii; 634 635 PetscFunctionBegin; 636 PetscCall(VecGetDM(v, &dm)); 637 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 638 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodusii)); 640 if (ishdf5) { 641 #if defined(PETSC_HAVE_HDF5) 642 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 643 #else 644 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 645 #endif 646 } else if (isexodusii) { 647 #if defined(PETSC_HAVE_EXODUSII) 648 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 649 #else 650 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 651 #endif 652 } else PetscCall(VecLoad_Default(v, viewer)); 653 PetscFunctionReturn(0); 654 } 655 656 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm, PetscObjectComm((PetscObject)originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject)originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject)v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else PetscCall(VecLoad_Default(originalv, viewer)); 687 } 688 PetscFunctionReturn(0); 689 } 690 691 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) { 692 PetscSection coordSection; 693 Vec coordinates; 694 DMLabel depthLabel, celltypeLabel; 695 const char *name[4]; 696 const PetscScalar *a; 697 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 698 699 PetscFunctionBegin; 700 PetscCall(DMGetDimension(dm, &dim)); 701 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 702 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 703 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 704 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 705 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 706 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 707 PetscCall(VecGetArrayRead(coordinates, &a)); 708 name[0] = "vertex"; 709 name[1] = "edge"; 710 name[dim - 1] = "face"; 711 name[dim] = "cell"; 712 for (c = cStart; c < cEnd; ++c) { 713 PetscInt *closure = NULL; 714 PetscInt closureSize, cl, ct; 715 716 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 717 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 718 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 719 PetscCall(PetscViewerASCIIPushTab(viewer)); 720 for (cl = 0; cl < closureSize * 2; cl += 2) { 721 PetscInt point = closure[cl], depth, dof, off, d, p; 722 723 if ((point < pStart) || (point >= pEnd)) continue; 724 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 725 if (!dof) continue; 726 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 727 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 728 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 729 for (p = 0; p < dof / dim; ++p) { 730 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 731 for (d = 0; d < dim; ++d) { 732 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 733 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double)PetscRealPart(a[off + p * dim + d]))); 734 } 735 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 736 } 737 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 738 } 739 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 740 PetscCall(PetscViewerASCIIPopTab(viewer)); 741 } 742 PetscCall(VecRestoreArrayRead(coordinates, &a)); 743 PetscFunctionReturn(0); 744 } 745 746 typedef enum { 747 CS_CARTESIAN, 748 CS_POLAR, 749 CS_CYLINDRICAL, 750 CS_SPHERICAL 751 } CoordSystem; 752 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 753 754 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) { 755 PetscInt i; 756 757 PetscFunctionBegin; 758 if (dim > 3) { 759 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPart(x[i]))); 760 } else { 761 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 762 763 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 764 switch (cs) { 765 case CS_CARTESIAN: 766 for (i = 0; i < dim; ++i) trcoords[i] = coords[i]; 767 break; 768 case CS_POLAR: 769 PetscCheck(dim == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 770 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 771 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 772 break; 773 case CS_CYLINDRICAL: 774 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 775 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 776 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 777 trcoords[2] = coords[2]; 778 break; 779 case CS_SPHERICAL: 780 PetscCheck(dim == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 781 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 782 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 783 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 784 break; 785 } 786 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)trcoords[i])); 787 } 788 PetscFunctionReturn(0); 789 } 790 791 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) { 792 DM_Plex *mesh = (DM_Plex *)dm->data; 793 DM cdm, cdmCell; 794 PetscSection coordSection, coordSectionCell; 795 Vec coordinates, coordinatesCell; 796 PetscViewerFormat format; 797 798 PetscFunctionBegin; 799 PetscCall(DMGetCoordinateDM(dm, &cdm)); 800 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 801 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 802 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 803 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 804 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinatesCell)); 805 PetscCall(PetscViewerGetFormat(viewer, &format)); 806 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 807 const char *name; 808 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 809 PetscInt pStart, pEnd, p, numLabels, l; 810 PetscMPIInt rank, size; 811 812 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 813 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 814 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 815 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 816 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 817 PetscCall(DMGetDimension(dm, &dim)); 818 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 819 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 820 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 821 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 822 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 823 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 824 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 825 for (p = pStart; p < pEnd; ++p) { 826 PetscInt dof, off, s; 827 828 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 829 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 830 for (s = off; s < off + dof; ++s) { PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); } 831 } 832 PetscCall(PetscViewerFlush(viewer)); 833 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 834 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 835 for (p = pStart; p < pEnd; ++p) { 836 PetscInt dof, off, c; 837 838 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 839 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 840 for (c = off; c < off + dof; ++c) { PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); } 841 } 842 PetscCall(PetscViewerFlush(viewer)); 843 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 844 if (coordSection && coordinates) { 845 CoordSystem cs = CS_CARTESIAN; 846 const PetscScalar *array, *arrayCell = NULL; 847 PetscInt Nf, Nc, pvStart, pvEnd, pcStart = PETSC_MAX_INT, pcEnd = PETSC_MIN_INT, pStart, pEnd, p; 848 PetscMPIInt rank; 849 const char *name; 850 851 PetscCall(PetscOptionsGetEnum(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *)&cs, NULL)); 852 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 853 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 854 PetscCheck(Nf == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 855 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 856 PetscCall(PetscSectionGetChart(coordSection, &pvStart, &pvEnd)); 857 if (coordSectionCell) PetscCall(PetscSectionGetChart(coordSectionCell, &pcStart, &pcEnd)); 858 pStart = PetscMin(pvStart, pcStart); 859 pEnd = PetscMax(pvEnd, pcEnd); 860 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 861 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 862 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 863 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 864 865 PetscCall(VecGetArrayRead(coordinates, &array)); 866 if (coordinatesCell) PetscCall(VecGetArrayRead(coordinatesCell, &arrayCell)); 867 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 868 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 869 for (p = pStart; p < pEnd; ++p) { 870 PetscInt dof, off; 871 872 if (p >= pvStart && p < pvEnd) { 873 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 874 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 875 if (dof) { 876 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 877 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 878 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 879 } 880 } 881 if (cdmCell && p >= pcStart && p < pcEnd) { 882 PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 883 PetscCall(PetscSectionGetOffset(coordSectionCell, p, &off)); 884 if (dof) { 885 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 886 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &arrayCell[off])); 887 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 888 } 889 } 890 } 891 PetscCall(PetscViewerFlush(viewer)); 892 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 893 PetscCall(VecRestoreArrayRead(coordinates, &array)); 894 if (coordinatesCell) PetscCall(VecRestoreArrayRead(coordinatesCell, &arrayCell)); 895 } 896 PetscCall(DMGetNumLabels(dm, &numLabels)); 897 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 898 for (l = 0; l < numLabels; ++l) { 899 DMLabel label; 900 PetscBool isdepth; 901 const char *name; 902 903 PetscCall(DMGetLabelName(dm, l, &name)); 904 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 905 if (isdepth) continue; 906 PetscCall(DMGetLabel(dm, name, &label)); 907 PetscCall(DMLabelView(label, viewer)); 908 } 909 if (size > 1) { 910 PetscSF sf; 911 912 PetscCall(DMGetPointSF(dm, &sf)); 913 PetscCall(PetscSFView(sf, viewer)); 914 } 915 PetscCall(PetscViewerFlush(viewer)); 916 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 917 const char *name, *color; 918 const char *defcolors[3] = {"gray", "orange", "green"}; 919 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 920 char lname[PETSC_MAX_PATH_LEN]; 921 PetscReal scale = 2.0; 922 PetscReal tikzscale = 1.0; 923 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 924 double tcoords[3]; 925 PetscScalar *coords; 926 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 927 PetscMPIInt rank, size; 928 char **names, **colors, **lcolors; 929 PetscBool flg, lflg; 930 PetscBT wp = NULL; 931 PetscInt pEnd, pStart; 932 933 PetscCall(DMGetDimension(dm, &dim)); 934 PetscCall(DMPlexGetDepth(dm, &depth)); 935 PetscCall(DMGetNumLabels(dm, &numLabels)); 936 numLabels = PetscMax(numLabels, 10); 937 numColors = 10; 938 numLColors = 10; 939 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 940 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 941 PetscCall(PetscOptionsGetReal(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 942 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 943 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 944 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 945 n = 4; 946 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 947 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 948 PetscCall(PetscOptionsGetBoolArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 949 PetscCheck(!flg || n == dim + 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim + 1); 950 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 951 if (!useLabels) numLabels = 0; 952 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 953 if (!useColors) { 954 numColors = 3; 955 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 956 } 957 PetscCall(PetscOptionsGetStringArray(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 958 if (!useColors) { 959 numLColors = 4; 960 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 961 } 962 PetscCall(PetscOptionsGetString(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 963 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 964 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 965 PetscCheck(!flg || !plotEdges || depth >= dim, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 966 if (depth < dim) plotEdges = PETSC_FALSE; 967 PetscCall(PetscOptionsGetBool(((PetscObject)viewer)->options, ((PetscObject)viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 968 969 /* filter points with labelvalue != labeldefaultvalue */ 970 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 971 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 972 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 973 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 974 if (lflg) { 975 DMLabel lbl; 976 977 PetscCall(DMGetLabel(dm, lname, &lbl)); 978 if (lbl) { 979 PetscInt val, defval; 980 981 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 982 PetscCall(PetscBTCreate(pEnd - pStart, &wp)); 983 for (c = pStart; c < pEnd; c++) { 984 PetscInt *closure = NULL; 985 PetscInt closureSize; 986 987 PetscCall(DMLabelGetValue(lbl, c, &val)); 988 if (val == defval) continue; 989 990 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 991 for (p = 0; p < closureSize * 2; p += 2) { PetscCall(PetscBTSet(wp, closure[p] - pStart)); } 992 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 993 } 994 } 995 } 996 997 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 998 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 999 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 1001 \\documentclass[tikz]{standalone}\n\n\ 1002 \\usepackage{pgflibraryshapes}\n\ 1003 \\usetikzlibrary{backgrounds}\n\ 1004 \\usetikzlibrary{arrows}\n\ 1005 \\begin{document}\n")); 1006 if (size > 1) { 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 1008 for (p = 0; p < size; ++p) { 1009 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size - 1) ? ", and " : ", ")); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p % numColors], p)); 1011 } 1012 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 1013 } 1014 if (drawHasse) { 1015 PetscInt maxStratum = PetscMax(vEnd - vStart, PetscMax(eEnd - eStart, cEnd - cStart)); 1016 1017 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1018 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd - 1)); 1019 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd - vStart)); 1020 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum - (vEnd - vStart)) / 2.)); 1021 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1022 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd - 1)); 1023 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum - (eEnd - eStart)) / 2.)); 1024 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd - eStart)); 1025 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1026 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd - 1)); 1027 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd - cStart)); 1028 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum - (cEnd - cStart)) / 2.)); 1029 } 1030 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double)tikzscale)); 1031 1032 /* Plot vertices */ 1033 PetscCall(VecGetArray(coordinates, &coords)); 1034 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1035 for (v = vStart; v < vEnd; ++v) { 1036 PetscInt off, dof, d; 1037 PetscBool isLabeled = PETSC_FALSE; 1038 1039 if (wp && !PetscBTLookup(wp, v - pStart)) continue; 1040 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1041 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1042 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1043 PetscCheck(dof <= 3, PETSC_COMM_SELF, PETSC_ERR_PLIB, "coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3", v, dof); 1044 for (d = 0; d < dof; ++d) { 1045 tcoords[d] = (double)(scale * PetscRealPart(coords[off + d])); 1046 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1047 } 1048 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1049 if (dim == 3) { 1050 PetscReal tmp = tcoords[1]; 1051 tcoords[1] = tcoords[2]; 1052 tcoords[2] = -tmp; 1053 } 1054 for (d = 0; d < dof; ++d) { 1055 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1056 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1057 } 1058 if (drawHasse) color = colors[0 % numColors]; 1059 else color = colors[rank % numColors]; 1060 for (l = 0; l < numLabels; ++l) { 1061 PetscInt val; 1062 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1063 if (val >= 0) { 1064 color = lcolors[l % numLColors]; 1065 isLabeled = PETSC_TRUE; 1066 break; 1067 } 1068 } 1069 if (drawNumbers[0]) { 1070 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1071 } else if (drawColors[0]) { 1072 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1073 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1074 } 1075 PetscCall(VecRestoreArray(coordinates, &coords)); 1076 PetscCall(PetscViewerFlush(viewer)); 1077 /* Plot edges */ 1078 if (plotEdges) { 1079 PetscCall(VecGetArray(coordinates, &coords)); 1080 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1081 for (e = eStart; e < eEnd; ++e) { 1082 const PetscInt *cone; 1083 PetscInt coneSize, offA, offB, dof, d; 1084 1085 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1086 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1087 PetscCheck(coneSize == 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1088 PetscCall(DMPlexGetCone(dm, e, &cone)); 1089 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1090 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1091 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1092 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1093 for (d = 0; d < dof; ++d) { 1094 tcoords[d] = (double)(0.5 * scale * PetscRealPart(coords[offA + d] + coords[offB + d])); 1095 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1096 } 1097 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1098 if (dim == 3) { 1099 PetscReal tmp = tcoords[1]; 1100 tcoords[1] = tcoords[2]; 1101 tcoords[2] = -tmp; 1102 } 1103 for (d = 0; d < dof; ++d) { 1104 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1105 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1106 } 1107 if (drawHasse) color = colors[1 % numColors]; 1108 else color = colors[rank % numColors]; 1109 for (l = 0; l < numLabels; ++l) { 1110 PetscInt val; 1111 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1112 if (val >= 0) { 1113 color = lcolors[l % numLColors]; 1114 break; 1115 } 1116 } 1117 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1118 } 1119 PetscCall(VecRestoreArray(coordinates, &coords)); 1120 PetscCall(PetscViewerFlush(viewer)); 1121 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1122 } 1123 /* Plot cells */ 1124 if (dim == 3 || !drawNumbers[1]) { 1125 for (e = eStart; e < eEnd; ++e) { 1126 const PetscInt *cone; 1127 1128 if (wp && !PetscBTLookup(wp, e - pStart)) continue; 1129 color = colors[rank % numColors]; 1130 for (l = 0; l < numLabels; ++l) { 1131 PetscInt val; 1132 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1133 if (val >= 0) { 1134 color = lcolors[l % numLColors]; 1135 break; 1136 } 1137 } 1138 PetscCall(DMPlexGetCone(dm, e, &cone)); 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1140 } 1141 } else { 1142 DMPolytopeType ct; 1143 1144 /* Drawing a 2D polygon */ 1145 for (c = cStart; c < cEnd; ++c) { 1146 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1147 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1148 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1149 const PetscInt *cone; 1150 PetscInt coneSize, e; 1151 1152 PetscCall(DMPlexGetCone(dm, c, &cone)); 1153 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1154 for (e = 0; e < coneSize; ++e) { 1155 const PetscInt *econe; 1156 1157 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1158 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank % numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1159 } 1160 } else { 1161 PetscInt *closure = NULL; 1162 PetscInt closureSize, Nv = 0, v; 1163 1164 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1165 for (p = 0; p < closureSize * 2; p += 2) { 1166 const PetscInt point = closure[p]; 1167 1168 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1169 } 1170 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank % numColors])); 1171 for (v = 0; v <= Nv; ++v) { 1172 const PetscInt vertex = closure[v % Nv]; 1173 1174 if (v > 0) { 1175 if (plotEdges) { 1176 const PetscInt *edge; 1177 PetscInt endpoints[2], ne; 1178 1179 endpoints[0] = closure[v - 1]; 1180 endpoints[1] = vertex; 1181 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1182 PetscCheck(ne == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1183 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1184 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1185 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1186 } 1187 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1188 } 1189 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1190 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1191 } 1192 } 1193 } 1194 for (c = cStart; c < cEnd; ++c) { 1195 double ccoords[3] = {0.0, 0.0, 0.0}; 1196 PetscBool isLabeled = PETSC_FALSE; 1197 PetscScalar *cellCoords = NULL; 1198 const PetscScalar *array; 1199 PetscInt numCoords, cdim, d; 1200 PetscBool isDG; 1201 1202 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1203 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1204 PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1205 PetscCheck(!(numCoords % cdim), PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "coordinate dim %" PetscInt_FMT " does not divide numCoords %" PetscInt_FMT, cdim, numCoords); 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1207 for (p = 0; p < numCoords / cdim; ++p) { 1208 for (d = 0; d < cdim; ++d) { 1209 tcoords[d] = (double)(scale * PetscRealPart(cellCoords[p * cdim + d])); 1210 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1211 } 1212 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1213 if (cdim == 3) { 1214 PetscReal tmp = tcoords[1]; 1215 tcoords[1] = tcoords[2]; 1216 tcoords[2] = -tmp; 1217 } 1218 for (d = 0; d < dim; ++d) { ccoords[d] += tcoords[d]; } 1219 } 1220 for (d = 0; d < cdim; ++d) { ccoords[d] /= (numCoords / cdim); } 1221 PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &numCoords, &array, &cellCoords)); 1222 for (d = 0; d < cdim; ++d) { 1223 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1224 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)ccoords[d])); 1225 } 1226 if (drawHasse) color = colors[depth % numColors]; 1227 else color = colors[rank % numColors]; 1228 for (l = 0; l < numLabels; ++l) { 1229 PetscInt val; 1230 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1231 if (val >= 0) { 1232 color = lcolors[l % numLColors]; 1233 isLabeled = PETSC_TRUE; 1234 break; 1235 } 1236 } 1237 if (drawNumbers[dim]) { 1238 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1239 } else if (drawColors[dim]) { 1240 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1241 } else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1242 } 1243 if (drawHasse) { 1244 color = colors[depth % numColors]; 1245 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1246 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1249 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1250 1251 color = colors[1 % numColors]; 1252 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1253 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1254 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1255 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1256 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1257 1258 color = colors[0 % numColors]; 1259 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1260 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1261 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1262 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1263 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1264 1265 for (p = pStart; p < pEnd; ++p) { 1266 const PetscInt *cone; 1267 PetscInt coneSize, cp; 1268 1269 PetscCall(DMPlexGetCone(dm, p, &cone)); 1270 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1271 for (cp = 0; cp < coneSize; ++cp) { PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); } 1272 } 1273 } 1274 PetscCall(PetscViewerFlush(viewer)); 1275 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1276 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1277 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1278 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1279 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1280 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1281 PetscCall(PetscFree3(names, colors, lcolors)); 1282 PetscCall(PetscBTDestroy(&wp)); 1283 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1284 Vec cown, acown; 1285 VecScatter sct; 1286 ISLocalToGlobalMapping g2l; 1287 IS gid, acis; 1288 MPI_Comm comm, ncomm = MPI_COMM_NULL; 1289 MPI_Group ggroup, ngroup; 1290 PetscScalar *array, nid; 1291 const PetscInt *idxs; 1292 PetscInt *idxs2, *start, *adjacency, *work; 1293 PetscInt64 lm[3], gm[3]; 1294 PetscInt i, c, cStart, cEnd, cum, numVertices, ect, ectn, cellHeight; 1295 PetscMPIInt d1, d2, rank; 1296 1297 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1298 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1299 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1300 PetscCallMPI(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &ncomm)); 1301 #endif 1302 if (ncomm != MPI_COMM_NULL) { 1303 PetscCallMPI(MPI_Comm_group(comm, &ggroup)); 1304 PetscCallMPI(MPI_Comm_group(ncomm, &ngroup)); 1305 d1 = 0; 1306 PetscCallMPI(MPI_Group_translate_ranks(ngroup, 1, &d1, ggroup, &d2)); 1307 nid = d2; 1308 PetscCallMPI(MPI_Group_free(&ggroup)); 1309 PetscCallMPI(MPI_Group_free(&ngroup)); 1310 PetscCallMPI(MPI_Comm_free(&ncomm)); 1311 } else nid = 0.0; 1312 1313 /* Get connectivity */ 1314 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1315 PetscCall(DMPlexCreatePartitionerGraph(dm, cellHeight, &numVertices, &start, &adjacency, &gid)); 1316 1317 /* filter overlapped local cells */ 1318 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 1319 PetscCall(ISGetIndices(gid, &idxs)); 1320 PetscCall(ISGetLocalSize(gid, &cum)); 1321 PetscCall(PetscMalloc1(cum, &idxs2)); 1322 for (c = cStart, cum = 0; c < cEnd; c++) { 1323 if (idxs[c - cStart] < 0) continue; 1324 idxs2[cum++] = idxs[c - cStart]; 1325 } 1326 PetscCall(ISRestoreIndices(gid, &idxs)); 1327 PetscCheck(numVertices == cum, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, numVertices, cum); 1328 PetscCall(ISDestroy(&gid)); 1329 PetscCall(ISCreateGeneral(comm, numVertices, idxs2, PETSC_OWN_POINTER, &gid)); 1330 1331 /* support for node-aware cell locality */ 1332 PetscCall(ISCreateGeneral(comm, start[numVertices], adjacency, PETSC_USE_POINTER, &acis)); 1333 PetscCall(VecCreateSeq(PETSC_COMM_SELF, start[numVertices], &acown)); 1334 PetscCall(VecCreateMPI(comm, numVertices, PETSC_DECIDE, &cown)); 1335 PetscCall(VecGetArray(cown, &array)); 1336 for (c = 0; c < numVertices; c++) array[c] = nid; 1337 PetscCall(VecRestoreArray(cown, &array)); 1338 PetscCall(VecScatterCreate(cown, acis, acown, NULL, &sct)); 1339 PetscCall(VecScatterBegin(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1340 PetscCall(VecScatterEnd(sct, cown, acown, INSERT_VALUES, SCATTER_FORWARD)); 1341 PetscCall(ISDestroy(&acis)); 1342 PetscCall(VecScatterDestroy(&sct)); 1343 PetscCall(VecDestroy(&cown)); 1344 1345 /* compute edgeCut */ 1346 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum, start[c + 1] - start[c]); 1347 PetscCall(PetscMalloc1(cum, &work)); 1348 PetscCall(ISLocalToGlobalMappingCreateIS(gid, &g2l)); 1349 PetscCall(ISLocalToGlobalMappingSetType(g2l, ISLOCALTOGLOBALMAPPINGHASH)); 1350 PetscCall(ISDestroy(&gid)); 1351 PetscCall(VecGetArray(acown, &array)); 1352 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1353 PetscInt totl; 1354 1355 totl = start[c + 1] - start[c]; 1356 PetscCall(ISGlobalToLocalMappingApply(g2l, IS_GTOLM_MASK, totl, adjacency + start[c], NULL, work)); 1357 for (i = 0; i < totl; i++) { 1358 if (work[i] < 0) { 1359 ect += 1; 1360 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1361 } 1362 } 1363 } 1364 PetscCall(PetscFree(work)); 1365 PetscCall(VecRestoreArray(acown, &array)); 1366 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1367 lm[1] = -numVertices; 1368 PetscCall(MPIU_Allreduce(lm, gm, 2, MPIU_INT64, MPI_MIN, comm)); 1369 PetscCall(PetscViewerASCIIPrintf(viewer, " Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT, -((double)gm[1]) / ((double)gm[0]), -(PetscInt)gm[1], (PetscInt)gm[0])); 1370 lm[0] = ect; /* edgeCut */ 1371 lm[1] = ectn; /* node-aware edgeCut */ 1372 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1373 PetscCall(MPIU_Allreduce(lm, gm, 3, MPIU_INT64, MPI_SUM, comm)); 1374 PetscCall(PetscViewerASCIIPrintf(viewer, ", empty %" PetscInt_FMT ")\n", (PetscInt)gm[2])); 1375 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1376 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), gm[0] ? ((double)(gm[1])) / ((double)gm[0]) : 1.)); 1377 #else 1378 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge Cut: %" PetscInt_FMT " (on node %.3f)\n", (PetscInt)(gm[0] / 2), 0.0)); 1379 #endif 1380 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1381 PetscCall(PetscFree(start)); 1382 PetscCall(PetscFree(adjacency)); 1383 PetscCall(VecDestroy(&acown)); 1384 } else { 1385 const char *name; 1386 PetscInt *sizes, *hybsizes, *ghostsizes; 1387 PetscInt locDepth, depth, cellHeight, dim, d; 1388 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1389 PetscInt numLabels, l, maxSize = 17; 1390 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1391 MPI_Comm comm; 1392 PetscMPIInt size, rank; 1393 1394 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1395 PetscCallMPI(MPI_Comm_size(comm, &size)); 1396 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1397 PetscCall(DMGetDimension(dm, &dim)); 1398 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1399 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 1400 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1401 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1402 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1403 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1404 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1405 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1406 gcNum = gcEnd - gcStart; 1407 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1408 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1409 for (d = 0; d <= depth; d++) { 1410 PetscInt Nc[2] = {0, 0}, ict; 1411 1412 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1413 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1414 ict = ct0; 1415 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1416 ct0 = (DMPolytopeType)ict; 1417 for (p = pStart; p < pEnd; ++p) { 1418 DMPolytopeType ct; 1419 1420 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1421 if (ct == ct0) ++Nc[0]; 1422 else ++Nc[1]; 1423 } 1424 if (size < maxSize) { 1425 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1426 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1427 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1428 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1429 for (p = 0; p < size; ++p) { 1430 if (rank == 0) { 1431 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p] + hybsizes[p])); 1432 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1433 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1434 } 1435 } 1436 } else { 1437 PetscInt locMinMax[2]; 1438 1439 locMinMax[0] = Nc[0] + Nc[1]; 1440 locMinMax[1] = Nc[0] + Nc[1]; 1441 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1442 locMinMax[0] = Nc[1]; 1443 locMinMax[1] = Nc[1]; 1444 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1445 if (d == depth) { 1446 locMinMax[0] = gcNum; 1447 locMinMax[1] = gcNum; 1448 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1449 } 1450 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1451 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1452 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1453 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1454 } 1455 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1456 } 1457 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1458 { 1459 const PetscReal *maxCell; 1460 const PetscReal *L; 1461 PetscBool localized; 1462 1463 PetscCall(DMGetPeriodicity(dm, &maxCell, NULL, &L)); 1464 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1465 if (L || localized) { 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh")); 1467 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1468 if (L) { 1469 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 1470 for (d = 0; d < dim; ++d) { 1471 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1472 PetscCall(PetscViewerASCIIPrintf(viewer, "%s", L[d] > 0.0 ? "PERIODIC" : "NONE")); 1473 } 1474 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 1475 } 1476 PetscCall(PetscViewerASCIIPrintf(viewer, " coordinates %s\n", localized ? "localized" : "not localized")); 1477 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1478 } 1479 } 1480 PetscCall(DMGetNumLabels(dm, &numLabels)); 1481 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1482 for (l = 0; l < numLabels; ++l) { 1483 DMLabel label; 1484 const char *name; 1485 IS valueIS; 1486 const PetscInt *values; 1487 PetscInt numValues, v; 1488 1489 PetscCall(DMGetLabelName(dm, l, &name)); 1490 PetscCall(DMGetLabel(dm, name, &label)); 1491 PetscCall(DMLabelGetNumValues(label, &numValues)); 1492 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1493 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1494 PetscCall(ISGetIndices(valueIS, &values)); 1495 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1496 for (v = 0; v < numValues; ++v) { 1497 PetscInt size; 1498 1499 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1500 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1501 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1502 } 1503 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1504 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1505 PetscCall(ISRestoreIndices(valueIS, &values)); 1506 PetscCall(ISDestroy(&valueIS)); 1507 } 1508 { 1509 char **labelNames; 1510 PetscInt Nl = numLabels; 1511 PetscBool flg; 1512 1513 PetscCall(PetscMalloc1(Nl, &labelNames)); 1514 PetscCall(PetscOptionsGetStringArray(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1515 for (l = 0; l < Nl; ++l) { 1516 DMLabel label; 1517 1518 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1519 if (flg) { 1520 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1521 PetscCall(DMLabelView(label, viewer)); 1522 } 1523 PetscCall(PetscFree(labelNames[l])); 1524 } 1525 PetscCall(PetscFree(labelNames)); 1526 } 1527 /* If no fields are specified, people do not want to see adjacency */ 1528 if (dm->Nf) { 1529 PetscInt f; 1530 1531 for (f = 0; f < dm->Nf; ++f) { 1532 const char *name; 1533 1534 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1535 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1536 PetscCall(PetscViewerASCIIPushTab(viewer)); 1537 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1538 if (dm->fields[f].adjacency[0]) { 1539 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1540 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1541 } else { 1542 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1543 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1544 } 1545 PetscCall(PetscViewerASCIIPopTab(viewer)); 1546 } 1547 } 1548 PetscCall(DMGetCoarseDM(dm, &cdm)); 1549 if (cdm) { 1550 PetscCall(PetscViewerASCIIPushTab(viewer)); 1551 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1552 PetscCall(PetscViewerASCIIPopTab(viewer)); 1553 } 1554 } 1555 PetscFunctionReturn(0); 1556 } 1557 1558 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) { 1559 DMPolytopeType ct; 1560 PetscMPIInt rank; 1561 PetscInt cdim; 1562 1563 PetscFunctionBegin; 1564 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1565 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1566 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1567 switch (ct) { 1568 case DM_POLYTOPE_SEGMENT: 1569 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1570 switch (cdim) { 1571 case 1: { 1572 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1573 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1574 1575 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1576 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y + dy, PetscRealPart(coords[0]), y - dy, PETSC_DRAW_BLACK)); 1577 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y + dy, PetscRealPart(coords[1]), y - dy, PETSC_DRAW_BLACK)); 1578 } break; 1579 case 2: { 1580 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1581 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1582 const PetscReal l = 0.1 / PetscSqrtReal(dx * dx + dy * dy); 1583 1584 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1585 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]) + l * dx, PetscRealPart(coords[1]) + l * dy, PetscRealPart(coords[0]) - l * dx, PetscRealPart(coords[1]) - l * dy, PETSC_DRAW_BLACK)); 1586 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]) + l * dx, PetscRealPart(coords[3]) + l * dy, PetscRealPart(coords[2]) - l * dx, PetscRealPart(coords[3]) - l * dy, PETSC_DRAW_BLACK)); 1587 } break; 1588 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1589 } 1590 break; 1591 case DM_POLYTOPE_TRIANGLE: 1592 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1593 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1594 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1595 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1596 break; 1597 case DM_POLYTOPE_QUADRILATERAL: 1598 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1599 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2, PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2)); 1600 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1601 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1602 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1603 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1604 break; 1605 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1606 } 1607 PetscFunctionReturn(0); 1608 } 1609 1610 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) { 1611 DMPolytopeType ct; 1612 PetscReal centroid[2] = {0., 0.}; 1613 PetscMPIInt rank; 1614 PetscInt fillColor, v, e, d; 1615 1616 PetscFunctionBegin; 1617 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 1618 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1619 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS - 2) + 2; 1620 switch (ct) { 1621 case DM_POLYTOPE_TRIANGLE: { 1622 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1623 1624 for (v = 0; v < 3; ++v) { 1625 centroid[0] += PetscRealPart(coords[v * 2 + 0]) / 3.; 1626 centroid[1] += PetscRealPart(coords[v * 2 + 1]) / 3.; 1627 } 1628 for (e = 0; e < 3; ++e) { 1629 refCoords[0] = refVertices[e * 2 + 0]; 1630 refCoords[1] = refVertices[e * 2 + 1]; 1631 for (d = 1; d <= edgeDiv; ++d) { 1632 refCoords[d * 2 + 0] = refCoords[0] + (refVertices[(e + 1) % 3 * 2 + 0] - refCoords[0]) * d / edgeDiv; 1633 refCoords[d * 2 + 1] = refCoords[1] + (refVertices[(e + 1) % 3 * 2 + 1] - refCoords[1]) * d / edgeDiv; 1634 } 1635 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv + 1, refCoords, edgeCoords)); 1636 for (d = 0; d < edgeDiv; ++d) { 1637 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], fillColor, fillColor, fillColor)); 1638 PetscCall(PetscDrawLine(draw, edgeCoords[d * 2 + 0], edgeCoords[d * 2 + 1], edgeCoords[(d + 1) * 2 + 0], edgeCoords[(d + 1) * 2 + 1], PETSC_DRAW_BLACK)); 1639 } 1640 } 1641 } break; 1642 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1643 } 1644 PetscFunctionReturn(0); 1645 } 1646 1647 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) { 1648 PetscDraw draw; 1649 DM cdm; 1650 PetscSection coordSection; 1651 Vec coordinates; 1652 const PetscScalar *coords; 1653 PetscReal xyl[2], xyr[2], bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1654 PetscReal *refCoords, *edgeCoords; 1655 PetscBool isnull, drawAffine = PETSC_TRUE; 1656 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1657 1658 PetscFunctionBegin; 1659 PetscCall(DMGetCoordinateDim(dm, &dim)); 1660 PetscCheck(dim <= 2, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1661 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1662 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv + 1) * dim, &refCoords, (edgeDiv + 1) * dim, &edgeCoords)); 1663 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1664 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1665 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1666 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1667 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1668 1669 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1670 PetscCall(PetscDrawIsNull(draw, &isnull)); 1671 if (isnull) PetscFunctionReturn(0); 1672 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1673 1674 PetscCall(VecGetLocalSize(coordinates, &N)); 1675 PetscCall(VecGetArrayRead(coordinates, &coords)); 1676 for (c = 0; c < N; c += dim) { 1677 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); 1678 bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1679 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c + 1])); 1680 bound[3] = PetscMax(bound[3], PetscRealPart(coords[c + 1])); 1681 } 1682 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1683 PetscCall(MPIU_Allreduce(&bound[0], xyl, 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 1684 PetscCall(MPIU_Allreduce(&bound[2], xyr, 2, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 1685 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1686 PetscCall(PetscDrawClear(draw)); 1687 1688 for (c = cStart; c < cEnd; ++c) { 1689 PetscScalar *coords = NULL; 1690 PetscInt numCoords; 1691 1692 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1693 if (drawAffine) PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1694 else PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1695 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1696 } 1697 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1698 PetscCall(PetscDrawFlush(draw)); 1699 PetscCall(PetscDrawPause(draw)); 1700 PetscCall(PetscDrawSave(draw)); 1701 PetscFunctionReturn(0); 1702 } 1703 1704 #if defined(PETSC_HAVE_EXODUSII) 1705 #include <exodusII.h> 1706 #include <petscviewerexodusii.h> 1707 #endif 1708 1709 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) { 1710 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus, iscgns; 1711 char name[PETSC_MAX_PATH_LEN]; 1712 1713 PetscFunctionBegin; 1714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1715 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1716 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk)); 1718 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw)); 1720 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis)); 1721 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWEREXODUSII, &isexodus)); 1722 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERCGNS, &iscgns)); 1723 if (iascii) { 1724 PetscViewerFormat format; 1725 PetscCall(PetscViewerGetFormat(viewer, &format)); 1726 if (format == PETSC_VIEWER_ASCII_GLVIS) PetscCall(DMPlexView_GLVis(dm, viewer)); 1727 else PetscCall(DMPlexView_Ascii(dm, viewer)); 1728 } else if (ishdf5) { 1729 #if defined(PETSC_HAVE_HDF5) 1730 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1731 #else 1732 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1733 #endif 1734 } else if (isvtk) { 1735 PetscCall(DMPlexVTKWriteAll((PetscObject)dm, viewer)); 1736 } else if (isdraw) { 1737 PetscCall(DMPlexView_Draw(dm, viewer)); 1738 } else if (isglvis) { 1739 PetscCall(DMPlexView_GLVis(dm, viewer)); 1740 #if defined(PETSC_HAVE_EXODUSII) 1741 } else if (isexodus) { 1742 /* 1743 exodusII requires that all sets be part of exactly one cell set. 1744 If the dm does not have a "Cell Sets" label defined, we create one 1745 with ID 1, containig all cells. 1746 Note that if the Cell Sets label is defined but does not cover all cells, 1747 we may still have a problem. This should probably be checked here or in the viewer; 1748 */ 1749 PetscInt numCS; 1750 PetscCall(DMGetLabelSize(dm, "Cell Sets", &numCS)); 1751 if (!numCS) { 1752 PetscInt cStart, cEnd, c; 1753 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1754 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1755 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1756 } 1757 PetscCall(DMView_PlexExodusII(dm, viewer)); 1758 #endif 1759 #if defined(PETSC_HAVE_CGNS) 1760 } else if (iscgns) { 1761 PetscCall(DMView_PlexCGNS(dm, viewer)); 1762 #endif 1763 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1764 /* Optionally view the partition */ 1765 PetscCall(PetscOptionsHasName(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_partition_view", &flg)); 1766 if (flg) { 1767 Vec ranks; 1768 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1769 PetscCall(VecView(ranks, viewer)); 1770 PetscCall(VecDestroy(&ranks)); 1771 } 1772 /* Optionally view a label */ 1773 PetscCall(PetscOptionsGetString(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1774 if (flg) { 1775 DMLabel label; 1776 Vec val; 1777 1778 PetscCall(DMGetLabel(dm, name, &label)); 1779 PetscCheck(label, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1780 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1781 PetscCall(VecView(val, viewer)); 1782 PetscCall(VecDestroy(&val)); 1783 } 1784 PetscFunctionReturn(0); 1785 } 1786 1787 /*@ 1788 DMPlexTopologyView - Saves a DMPlex topology into a file 1789 1790 Collective on DM 1791 1792 Input Parameters: 1793 + dm - The DM whose topology is to be saved 1794 - viewer - The PetscViewer for saving 1795 1796 Level: advanced 1797 1798 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1799 @*/ 1800 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) { 1801 PetscBool ishdf5; 1802 1803 PetscFunctionBegin; 1804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1805 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1806 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1807 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1808 if (ishdf5) { 1809 #if defined(PETSC_HAVE_HDF5) 1810 PetscViewerFormat format; 1811 PetscCall(PetscViewerGetFormat(viewer, &format)); 1812 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1813 IS globalPointNumbering; 1814 1815 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1816 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1817 PetscCall(ISDestroy(&globalPointNumbering)); 1818 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1819 #else 1820 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1821 #endif 1822 } 1823 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView, viewer, 0, 0, 0)); 1824 PetscFunctionReturn(0); 1825 } 1826 1827 /*@ 1828 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1829 1830 Collective on DM 1831 1832 Input Parameters: 1833 + dm - The DM whose coordinates are to be saved 1834 - viewer - The PetscViewer for saving 1835 1836 Level: advanced 1837 1838 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1839 @*/ 1840 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) { 1841 PetscBool ishdf5; 1842 1843 PetscFunctionBegin; 1844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1845 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1846 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1847 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1848 if (ishdf5) { 1849 #if defined(PETSC_HAVE_HDF5) 1850 PetscViewerFormat format; 1851 PetscCall(PetscViewerGetFormat(viewer, &format)); 1852 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1853 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1854 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1855 #else 1856 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1857 #endif 1858 } 1859 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView, viewer, 0, 0, 0)); 1860 PetscFunctionReturn(0); 1861 } 1862 1863 /*@ 1864 DMPlexLabelsView - Saves DMPlex labels into a file 1865 1866 Collective on DM 1867 1868 Input Parameters: 1869 + dm - The DM whose labels are to be saved 1870 - viewer - The PetscViewer for saving 1871 1872 Level: advanced 1873 1874 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1875 @*/ 1876 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) { 1877 PetscBool ishdf5; 1878 1879 PetscFunctionBegin; 1880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1881 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1882 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1883 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1884 if (ishdf5) { 1885 #if defined(PETSC_HAVE_HDF5) 1886 IS globalPointNumbering; 1887 PetscViewerFormat format; 1888 1889 PetscCall(PetscViewerGetFormat(viewer, &format)); 1890 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1891 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1892 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1893 PetscCall(ISDestroy(&globalPointNumbering)); 1894 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1895 #else 1896 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1897 #endif 1898 } 1899 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView, viewer, 0, 0, 0)); 1900 PetscFunctionReturn(0); 1901 } 1902 1903 /*@ 1904 DMPlexSectionView - Saves a section associated with a DMPlex 1905 1906 Collective on DM 1907 1908 Input Parameters: 1909 + dm - The DM that contains the topology on which the section to be saved is defined 1910 . viewer - The PetscViewer for saving 1911 - sectiondm - The DM that contains the section to be saved 1912 1913 Level: advanced 1914 1915 Notes: 1916 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1917 1918 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1919 1920 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1921 @*/ 1922 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) { 1923 PetscBool ishdf5; 1924 1925 PetscFunctionBegin; 1926 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1927 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1928 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1930 PetscCall(PetscLogEventBegin(DMPLEX_SectionView, viewer, 0, 0, 0)); 1931 if (ishdf5) { 1932 #if defined(PETSC_HAVE_HDF5) 1933 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1934 #else 1935 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1936 #endif 1937 } 1938 PetscCall(PetscLogEventEnd(DMPLEX_SectionView, viewer, 0, 0, 0)); 1939 PetscFunctionReturn(0); 1940 } 1941 1942 /*@ 1943 DMPlexGlobalVectorView - Saves a global vector 1944 1945 Collective on DM 1946 1947 Input Parameters: 1948 + dm - The DM that represents the topology 1949 . viewer - The PetscViewer to save data with 1950 . sectiondm - The DM that contains the global section on which vec is defined 1951 - vec - The global vector to be saved 1952 1953 Level: advanced 1954 1955 Notes: 1956 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1957 1958 Typical calling sequence 1959 $ DMCreate(PETSC_COMM_WORLD, &dm); 1960 $ DMSetType(dm, DMPLEX); 1961 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1962 $ DMClone(dm, §iondm); 1963 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1964 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1965 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1966 $ PetscSectionSetChart(section, pStart, pEnd); 1967 $ PetscSectionSetUp(section); 1968 $ DMSetLocalSection(sectiondm, section); 1969 $ PetscSectionDestroy(§ion); 1970 $ DMGetGlobalVector(sectiondm, &vec); 1971 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1972 $ DMPlexTopologyView(dm, viewer); 1973 $ DMPlexSectionView(dm, viewer, sectiondm); 1974 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1975 $ DMRestoreGlobalVector(sectiondm, &vec); 1976 $ DMDestroy(§iondm); 1977 $ DMDestroy(&dm); 1978 1979 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1980 @*/ 1981 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 1982 PetscBool ishdf5; 1983 1984 PetscFunctionBegin; 1985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1986 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1987 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1988 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1989 /* Check consistency */ 1990 { 1991 PetscSection section; 1992 PetscBool includesConstraints; 1993 PetscInt m, m1; 1994 1995 PetscCall(VecGetLocalSize(vec, &m1)); 1996 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1997 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1998 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1999 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2000 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2001 } 2002 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2003 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2004 if (ishdf5) { 2005 #if defined(PETSC_HAVE_HDF5) 2006 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2007 #else 2008 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2009 #endif 2010 } 2011 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView, viewer, 0, 0, 0)); 2012 PetscFunctionReturn(0); 2013 } 2014 2015 /*@ 2016 DMPlexLocalVectorView - Saves a local vector 2017 2018 Collective on DM 2019 2020 Input Parameters: 2021 + dm - The DM that represents the topology 2022 . viewer - The PetscViewer to save data with 2023 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2024 - vec - The local vector to be saved 2025 2026 Level: advanced 2027 2028 Notes: 2029 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2030 2031 Typical calling sequence 2032 $ DMCreate(PETSC_COMM_WORLD, &dm); 2033 $ DMSetType(dm, DMPLEX); 2034 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2035 $ DMClone(dm, §iondm); 2036 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2037 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2038 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2039 $ PetscSectionSetChart(section, pStart, pEnd); 2040 $ PetscSectionSetUp(section); 2041 $ DMSetLocalSection(sectiondm, section); 2042 $ DMGetLocalVector(sectiondm, &vec); 2043 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2044 $ DMPlexTopologyView(dm, viewer); 2045 $ DMPlexSectionView(dm, viewer, sectiondm); 2046 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2047 $ DMRestoreLocalVector(sectiondm, &vec); 2048 $ DMDestroy(§iondm); 2049 $ DMDestroy(&dm); 2050 2051 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2052 @*/ 2053 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) { 2054 PetscBool ishdf5; 2055 2056 PetscFunctionBegin; 2057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2058 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2059 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2060 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2061 /* Check consistency */ 2062 { 2063 PetscSection section; 2064 PetscBool includesConstraints; 2065 PetscInt m, m1; 2066 2067 PetscCall(VecGetLocalSize(vec, &m1)); 2068 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2069 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2070 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2071 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2072 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2073 } 2074 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2075 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2076 if (ishdf5) { 2077 #if defined(PETSC_HAVE_HDF5) 2078 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2079 #else 2080 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2081 #endif 2082 } 2083 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView, viewer, 0, 0, 0)); 2084 PetscFunctionReturn(0); 2085 } 2086 2087 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) { 2088 PetscBool ishdf5; 2089 2090 PetscFunctionBegin; 2091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2092 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2093 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2094 if (ishdf5) { 2095 #if defined(PETSC_HAVE_HDF5) 2096 PetscViewerFormat format; 2097 PetscCall(PetscViewerGetFormat(viewer, &format)); 2098 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2099 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2100 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2101 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2102 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2103 PetscFunctionReturn(0); 2104 #else 2105 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2106 #endif 2107 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2108 } 2109 2110 /*@ 2111 DMPlexTopologyLoad - Loads a topology into a DMPlex 2112 2113 Collective on DM 2114 2115 Input Parameters: 2116 + dm - The DM into which the topology is loaded 2117 - viewer - The PetscViewer for the saved topology 2118 2119 Output Parameters: 2120 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2121 2122 Level: advanced 2123 2124 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2125 @*/ 2126 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) { 2127 PetscBool ishdf5; 2128 2129 PetscFunctionBegin; 2130 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2131 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2132 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2133 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2134 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2135 if (ishdf5) { 2136 #if defined(PETSC_HAVE_HDF5) 2137 PetscViewerFormat format; 2138 PetscCall(PetscViewerGetFormat(viewer, &format)); 2139 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2140 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2141 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2142 #else 2143 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2144 #endif 2145 } 2146 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad, viewer, 0, 0, 0)); 2147 PetscFunctionReturn(0); 2148 } 2149 2150 /*@ 2151 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2152 2153 Collective on DM 2154 2155 Input Parameters: 2156 + dm - The DM into which the coordinates are loaded 2157 . viewer - The PetscViewer for the saved coordinates 2158 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2159 2160 Level: advanced 2161 2162 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2163 @*/ 2164 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2165 PetscBool ishdf5; 2166 2167 PetscFunctionBegin; 2168 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2169 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2170 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2171 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2172 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2173 if (ishdf5) { 2174 #if defined(PETSC_HAVE_HDF5) 2175 PetscViewerFormat format; 2176 PetscCall(PetscViewerGetFormat(viewer, &format)); 2177 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2178 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2179 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2180 #else 2181 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2182 #endif 2183 } 2184 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad, viewer, 0, 0, 0)); 2185 PetscFunctionReturn(0); 2186 } 2187 2188 /*@ 2189 DMPlexLabelsLoad - Loads labels into a DMPlex 2190 2191 Collective on DM 2192 2193 Input Parameters: 2194 + dm - The DM into which the labels are loaded 2195 . viewer - The PetscViewer for the saved labels 2196 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2197 2198 Level: advanced 2199 2200 Notes: 2201 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2202 2203 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2204 @*/ 2205 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) { 2206 PetscBool ishdf5; 2207 2208 PetscFunctionBegin; 2209 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2210 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2211 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2212 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2213 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2214 if (ishdf5) { 2215 #if defined(PETSC_HAVE_HDF5) 2216 PetscViewerFormat format; 2217 2218 PetscCall(PetscViewerGetFormat(viewer, &format)); 2219 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2220 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2221 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2222 #else 2223 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2224 #endif 2225 } 2226 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad, viewer, 0, 0, 0)); 2227 PetscFunctionReturn(0); 2228 } 2229 2230 /*@ 2231 DMPlexSectionLoad - Loads section into a DMPlex 2232 2233 Collective on DM 2234 2235 Input Parameters: 2236 + dm - The DM that represents the topology 2237 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2238 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2239 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2240 2241 Output Parameters 2242 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2243 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2244 2245 Level: advanced 2246 2247 Notes: 2248 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2249 2250 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2251 2252 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2253 2254 Example using 2 processes: 2255 $ NX (number of points on dm): 4 2256 $ sectionA : the on-disk section 2257 $ vecA : a vector associated with sectionA 2258 $ sectionB : sectiondm's local section constructed in this function 2259 $ vecB (local) : a vector associated with sectiondm's local section 2260 $ vecB (global) : a vector associated with sectiondm's global section 2261 $ 2262 $ rank 0 rank 1 2263 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2264 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2265 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2266 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2267 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2268 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2269 $ sectionB->atlasDof : 1 0 1 | 1 3 2270 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2271 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2272 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2273 $ 2274 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2275 2276 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2277 @*/ 2278 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) { 2279 PetscBool ishdf5; 2280 2281 PetscFunctionBegin; 2282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2283 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2284 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2285 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2286 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2287 if (localDofSF) PetscValidPointer(localDofSF, 6); 2288 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2289 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2290 if (ishdf5) { 2291 #if defined(PETSC_HAVE_HDF5) 2292 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2293 #else 2294 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2295 #endif 2296 } 2297 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad, viewer, 0, 0, 0)); 2298 PetscFunctionReturn(0); 2299 } 2300 2301 /*@ 2302 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2303 2304 Collective on DM 2305 2306 Input Parameters: 2307 + dm - The DM that represents the topology 2308 . viewer - The PetscViewer that represents the on-disk vector data 2309 . sectiondm - The DM that contains the global section on which vec is defined 2310 . sf - The SF that migrates the on-disk vector data into vec 2311 - vec - The global vector to set values of 2312 2313 Level: advanced 2314 2315 Notes: 2316 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2317 2318 Typical calling sequence 2319 $ DMCreate(PETSC_COMM_WORLD, &dm); 2320 $ DMSetType(dm, DMPLEX); 2321 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2322 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2323 $ DMClone(dm, §iondm); 2324 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2325 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2326 $ DMGetGlobalVector(sectiondm, &vec); 2327 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2328 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2329 $ DMRestoreGlobalVector(sectiondm, &vec); 2330 $ PetscSFDestroy(&gsf); 2331 $ PetscSFDestroy(&sfX); 2332 $ DMDestroy(§iondm); 2333 $ DMDestroy(&dm); 2334 2335 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2336 @*/ 2337 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2338 PetscBool ishdf5; 2339 2340 PetscFunctionBegin; 2341 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2342 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2343 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2344 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2345 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2346 /* Check consistency */ 2347 { 2348 PetscSection section; 2349 PetscBool includesConstraints; 2350 PetscInt m, m1; 2351 2352 PetscCall(VecGetLocalSize(vec, &m1)); 2353 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2354 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2355 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2356 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2357 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2358 } 2359 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2360 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2361 if (ishdf5) { 2362 #if defined(PETSC_HAVE_HDF5) 2363 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2364 #else 2365 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2366 #endif 2367 } 2368 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad, viewer, 0, 0, 0)); 2369 PetscFunctionReturn(0); 2370 } 2371 2372 /*@ 2373 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2374 2375 Collective on DM 2376 2377 Input Parameters: 2378 + dm - The DM that represents the topology 2379 . viewer - The PetscViewer that represents the on-disk vector data 2380 . sectiondm - The DM that contains the local section on which vec is defined 2381 . sf - The SF that migrates the on-disk vector data into vec 2382 - vec - The local vector to set values of 2383 2384 Level: advanced 2385 2386 Notes: 2387 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2388 2389 Typical calling sequence 2390 $ DMCreate(PETSC_COMM_WORLD, &dm); 2391 $ DMSetType(dm, DMPLEX); 2392 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2393 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2394 $ DMClone(dm, §iondm); 2395 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2396 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2397 $ DMGetLocalVector(sectiondm, &vec); 2398 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2399 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2400 $ DMRestoreLocalVector(sectiondm, &vec); 2401 $ PetscSFDestroy(&lsf); 2402 $ PetscSFDestroy(&sfX); 2403 $ DMDestroy(§iondm); 2404 $ DMDestroy(&dm); 2405 2406 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2407 @*/ 2408 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) { 2409 PetscBool ishdf5; 2410 2411 PetscFunctionBegin; 2412 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2413 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2414 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2415 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2416 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2417 /* Check consistency */ 2418 { 2419 PetscSection section; 2420 PetscBool includesConstraints; 2421 PetscInt m, m1; 2422 2423 PetscCall(VecGetLocalSize(vec, &m1)); 2424 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2425 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2426 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2427 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2428 PetscCheck(m1 == m, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2429 } 2430 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2431 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2432 if (ishdf5) { 2433 #if defined(PETSC_HAVE_HDF5) 2434 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2435 #else 2436 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2437 #endif 2438 } 2439 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad, viewer, 0, 0, 0)); 2440 PetscFunctionReturn(0); 2441 } 2442 2443 PetscErrorCode DMDestroy_Plex(DM dm) { 2444 DM_Plex *mesh = (DM_Plex *)dm->data; 2445 2446 PetscFunctionBegin; 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMInterpolateSolution_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2452 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2453 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeGetDefault_C", NULL)); 2454 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexDistributeSetDefault_C", NULL)); 2455 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL)); 2456 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderGetDefault_C", NULL)); 2457 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexReorderSetDefault_C", NULL)); 2458 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL)); 2459 PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexSetOverlap_C", NULL)); 2460 if (--mesh->refct > 0) PetscFunctionReturn(0); 2461 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2462 PetscCall(PetscFree(mesh->cones)); 2463 PetscCall(PetscFree(mesh->coneOrientations)); 2464 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2465 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2466 PetscCall(PetscFree(mesh->supports)); 2467 PetscCall(PetscFree(mesh->facesTmp)); 2468 PetscCall(PetscFree(mesh->tetgenOpts)); 2469 PetscCall(PetscFree(mesh->triangleOpts)); 2470 PetscCall(PetscFree(mesh->transformType)); 2471 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2472 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2473 PetscCall(ISDestroy(&mesh->subpointIS)); 2474 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2475 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2476 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2477 PetscCall(ISDestroy(&mesh->anchorIS)); 2478 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2479 PetscCall(PetscFree(mesh->parents)); 2480 PetscCall(PetscFree(mesh->childIDs)); 2481 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2482 PetscCall(PetscFree(mesh->children)); 2483 PetscCall(DMDestroy(&mesh->referenceTree)); 2484 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2485 PetscCall(PetscFree(mesh->neighbors)); 2486 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2487 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2488 PetscCall(PetscFree(mesh)); 2489 PetscFunctionReturn(0); 2490 } 2491 2492 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) { 2493 PetscSection sectionGlobal; 2494 PetscInt bs = -1, mbs; 2495 PetscInt localSize, localStart = 0; 2496 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2497 MatType mtype; 2498 ISLocalToGlobalMapping ltog; 2499 2500 PetscFunctionBegin; 2501 PetscCall(MatInitializePackage()); 2502 mtype = dm->mattype; 2503 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2504 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2505 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2506 PetscCallMPI(MPI_Exscan(&localSize, &localStart, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)dm))); 2507 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2508 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2509 PetscCall(MatSetType(*J, mtype)); 2510 PetscCall(MatSetFromOptions(*J)); 2511 PetscCall(MatGetBlockSize(*J, &mbs)); 2512 if (mbs > 1) bs = mbs; 2513 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2514 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2515 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2516 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2517 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2518 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2519 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2520 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2521 if (!isShell) { 2522 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2523 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *pblocks; 2524 PetscInt pStart, pEnd, p, dof, cdof; 2525 2526 PetscCall(DMGetLocalToGlobalMapping(dm, <og)); 2527 2528 PetscCall(PetscCalloc1(localSize, &pblocks)); 2529 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2530 for (p = pStart; p < pEnd; ++p) { 2531 PetscInt bdof, offset; 2532 2533 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2534 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &offset)); 2535 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2536 for (PetscInt i = 0; i < dof - cdof; i++) pblocks[offset - localStart + i] = dof - cdof; 2537 dof = dof < 0 ? -(dof + 1) : dof; 2538 bdof = cdof && (dof - cdof) ? 1 : dof; 2539 if (dof) { 2540 if (bs < 0) { 2541 bs = bdof; 2542 } else if (bs != bdof) { 2543 bs = 1; 2544 } 2545 } 2546 } 2547 /* Must have same blocksize on all procs (some might have no points) */ 2548 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2549 bsLocal[1] = bs; 2550 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 2551 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2552 else bs = bsMinMax[0]; 2553 bs = PetscMax(1, bs); 2554 PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog)); 2555 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2556 PetscCall(MatSetBlockSize(*J, bs)); 2557 PetscCall(MatSetUp(*J)); 2558 } else { 2559 PetscCall(PetscCalloc4(localSize / bs, &dnz, localSize / bs, &onz, localSize / bs, &dnzu, localSize / bs, &onzu)); 2560 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2561 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2562 } 2563 { // Consolidate blocks 2564 PetscInt nblocks = 0; 2565 for (PetscInt i = 0; i < localSize; i += PetscMax(1, pblocks[i])) { 2566 if (pblocks[i] == 0) continue; 2567 pblocks[nblocks++] = pblocks[i]; // nblocks always <= i 2568 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]); } 2569 } 2570 PetscCall(MatSetVariableBlockSizes(*J, nblocks, pblocks)); 2571 } 2572 PetscCall(PetscFree(pblocks)); 2573 } 2574 PetscCall(MatSetDM(*J, dm)); 2575 PetscFunctionReturn(0); 2576 } 2577 2578 /*@ 2579 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2580 2581 Not collective 2582 2583 Input Parameter: 2584 . mesh - The DMPlex 2585 2586 Output Parameters: 2587 . subsection - The subdomain section 2588 2589 Level: developer 2590 2591 .seealso: 2592 @*/ 2593 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) { 2594 DM_Plex *mesh = (DM_Plex *)dm->data; 2595 2596 PetscFunctionBegin; 2597 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2598 if (!mesh->subdomainSection) { 2599 PetscSection section; 2600 PetscSF sf; 2601 2602 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 2603 PetscCall(DMGetLocalSection(dm, §ion)); 2604 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_TRUE, &mesh->subdomainSection)); 2605 PetscCall(PetscSFDestroy(&sf)); 2606 } 2607 *subsection = mesh->subdomainSection; 2608 PetscFunctionReturn(0); 2609 } 2610 2611 /*@ 2612 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2613 2614 Not collective 2615 2616 Input Parameter: 2617 . mesh - The DMPlex 2618 2619 Output Parameters: 2620 + pStart - The first mesh point 2621 - pEnd - The upper bound for mesh points 2622 2623 Level: beginner 2624 2625 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2626 @*/ 2627 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) { 2628 DM_Plex *mesh = (DM_Plex *)dm->data; 2629 2630 PetscFunctionBegin; 2631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2632 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2633 PetscFunctionReturn(0); 2634 } 2635 2636 /*@ 2637 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2638 2639 Not collective 2640 2641 Input Parameters: 2642 + mesh - The DMPlex 2643 . pStart - The first mesh point 2644 - pEnd - The upper bound for mesh points 2645 2646 Output Parameters: 2647 2648 Level: beginner 2649 2650 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2651 @*/ 2652 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) { 2653 DM_Plex *mesh = (DM_Plex *)dm->data; 2654 2655 PetscFunctionBegin; 2656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2657 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2658 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2659 PetscFunctionReturn(0); 2660 } 2661 2662 /*@ 2663 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2664 2665 Not collective 2666 2667 Input Parameters: 2668 + mesh - The DMPlex 2669 - p - The point, which must lie in the chart set with DMPlexSetChart() 2670 2671 Output Parameter: 2672 . size - The cone size for point p 2673 2674 Level: beginner 2675 2676 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2677 @*/ 2678 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) { 2679 DM_Plex *mesh = (DM_Plex *)dm->data; 2680 2681 PetscFunctionBegin; 2682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2683 PetscValidIntPointer(size, 3); 2684 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2685 PetscFunctionReturn(0); 2686 } 2687 2688 /*@ 2689 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2690 2691 Not collective 2692 2693 Input Parameters: 2694 + mesh - The DMPlex 2695 . p - The point, which must lie in the chart set with DMPlexSetChart() 2696 - size - The cone size for point p 2697 2698 Output Parameter: 2699 2700 Note: 2701 This should be called after DMPlexSetChart(). 2702 2703 Level: beginner 2704 2705 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2706 @*/ 2707 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) { 2708 DM_Plex *mesh = (DM_Plex *)dm->data; 2709 2710 PetscFunctionBegin; 2711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2712 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2713 PetscFunctionReturn(0); 2714 } 2715 2716 /*@ 2717 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2718 2719 Not collective 2720 2721 Input Parameters: 2722 + mesh - The DMPlex 2723 . p - The point, which must lie in the chart set with DMPlexSetChart() 2724 - size - The additional cone size for point p 2725 2726 Output Parameter: 2727 2728 Note: 2729 This should be called after DMPlexSetChart(). 2730 2731 Level: beginner 2732 2733 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2734 @*/ 2735 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) { 2736 DM_Plex *mesh = (DM_Plex *)dm->data; 2737 PetscFunctionBegin; 2738 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2739 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2740 PetscFunctionReturn(0); 2741 } 2742 2743 /*@C 2744 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2745 2746 Not collective 2747 2748 Input Parameters: 2749 + dm - The DMPlex 2750 - p - The point, which must lie in the chart set with DMPlexSetChart() 2751 2752 Output Parameter: 2753 . cone - An array of points which are on the in-edges for point p 2754 2755 Level: beginner 2756 2757 Fortran Notes: 2758 Since it returns an array, this routine is only available in Fortran 90, and you must 2759 include petsc.h90 in your code. 2760 You must also call DMPlexRestoreCone() after you finish using the returned array. 2761 DMPlexRestoreCone() is not needed/available in C. 2762 2763 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2764 @*/ 2765 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) { 2766 DM_Plex *mesh = (DM_Plex *)dm->data; 2767 PetscInt off; 2768 2769 PetscFunctionBegin; 2770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2771 PetscValidPointer(cone, 3); 2772 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2773 *cone = &mesh->cones[off]; 2774 PetscFunctionReturn(0); 2775 } 2776 2777 /*@C 2778 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2779 2780 Not collective 2781 2782 Input Parameters: 2783 + dm - The DMPlex 2784 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2785 2786 Output Parameters: 2787 + pConesSection - PetscSection describing the layout of pCones 2788 - pCones - An array of points which are on the in-edges for the point set p 2789 2790 Level: intermediate 2791 2792 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2793 @*/ 2794 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) { 2795 PetscSection cs, newcs; 2796 PetscInt *cones; 2797 PetscInt *newarr = NULL; 2798 PetscInt n; 2799 2800 PetscFunctionBegin; 2801 PetscCall(DMPlexGetCones(dm, &cones)); 2802 PetscCall(DMPlexGetConeSection(dm, &cs)); 2803 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void **)&newarr) : NULL)); 2804 if (pConesSection) *pConesSection = newcs; 2805 if (pCones) { 2806 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2807 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2808 } 2809 PetscFunctionReturn(0); 2810 } 2811 2812 /*@ 2813 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2814 2815 Not collective 2816 2817 Input Parameters: 2818 + dm - The DMPlex 2819 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2820 2821 Output Parameter: 2822 . expandedPoints - An array of vertices recursively expanded from input points 2823 2824 Level: advanced 2825 2826 Notes: 2827 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2828 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2829 2830 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2831 @*/ 2832 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) { 2833 IS *expandedPointsAll; 2834 PetscInt depth; 2835 2836 PetscFunctionBegin; 2837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2838 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2839 PetscValidPointer(expandedPoints, 3); 2840 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2841 *expandedPoints = expandedPointsAll[0]; 2842 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2843 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2844 PetscFunctionReturn(0); 2845 } 2846 2847 /*@ 2848 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). 2849 2850 Not collective 2851 2852 Input Parameters: 2853 + dm - The DMPlex 2854 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2855 2856 Output Parameters: 2857 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2858 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2859 - sections - (optional) An array of sections which describe mappings from points to their cone points 2860 2861 Level: advanced 2862 2863 Notes: 2864 Like DMPlexGetConeTuple() but recursive. 2865 2866 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. 2867 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2868 2869 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: 2870 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2871 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2872 2873 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2874 @*/ 2875 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2876 const PetscInt *arr0 = NULL, *cone = NULL; 2877 PetscInt *arr = NULL, *newarr = NULL; 2878 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2879 IS *expandedPoints_; 2880 PetscSection *sections_; 2881 2882 PetscFunctionBegin; 2883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2884 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2885 if (depth) PetscValidIntPointer(depth, 3); 2886 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2887 if (sections) PetscValidPointer(sections, 5); 2888 PetscCall(ISGetLocalSize(points, &n)); 2889 PetscCall(ISGetIndices(points, &arr0)); 2890 PetscCall(DMPlexGetDepth(dm, &depth_)); 2891 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2892 PetscCall(PetscCalloc1(depth_, §ions_)); 2893 arr = (PetscInt *)arr0; /* this is ok because first generation of arr is not modified */ 2894 for (d = depth_ - 1; d >= 0; d--) { 2895 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2896 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2897 for (i = 0; i < n; i++) { 2898 PetscCall(DMPlexGetDepthStratum(dm, d + 1, &start, &end)); 2899 if (arr[i] >= start && arr[i] < end) { 2900 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2901 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2902 } else { 2903 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2904 } 2905 } 2906 PetscCall(PetscSectionSetUp(sections_[d])); 2907 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2908 PetscCall(PetscMalloc1(newn, &newarr)); 2909 for (i = 0; i < n; i++) { 2910 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2911 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2912 if (cn > 1) { 2913 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2914 PetscCall(PetscMemcpy(&newarr[co], cone, cn * sizeof(PetscInt))); 2915 } else { 2916 newarr[co] = arr[i]; 2917 } 2918 } 2919 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2920 arr = newarr; 2921 n = newn; 2922 } 2923 PetscCall(ISRestoreIndices(points, &arr0)); 2924 *depth = depth_; 2925 if (expandedPoints) *expandedPoints = expandedPoints_; 2926 else { 2927 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2928 PetscCall(PetscFree(expandedPoints_)); 2929 } 2930 if (sections) *sections = sections_; 2931 else { 2932 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2933 PetscCall(PetscFree(sections_)); 2934 } 2935 PetscFunctionReturn(0); 2936 } 2937 2938 /*@ 2939 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2940 2941 Not collective 2942 2943 Input Parameters: 2944 + dm - The DMPlex 2945 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2946 2947 Output Parameters: 2948 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2949 . expandedPoints - (optional) An array of recursively expanded cones 2950 - sections - (optional) An array of sections which describe mappings from points to their cone points 2951 2952 Level: advanced 2953 2954 Notes: 2955 See DMPlexGetConeRecursive() for details. 2956 2957 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2958 @*/ 2959 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) { 2960 PetscInt d, depth_; 2961 2962 PetscFunctionBegin; 2963 PetscCall(DMPlexGetDepth(dm, &depth_)); 2964 PetscCheck(!depth || *depth == depth_, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2965 if (depth) *depth = 0; 2966 if (expandedPoints) { 2967 for (d = 0; d < depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2968 PetscCall(PetscFree(*expandedPoints)); 2969 } 2970 if (sections) { 2971 for (d = 0; d < depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2972 PetscCall(PetscFree(*sections)); 2973 } 2974 PetscFunctionReturn(0); 2975 } 2976 2977 /*@ 2978 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 2979 2980 Not collective 2981 2982 Input Parameters: 2983 + mesh - The DMPlex 2984 . p - The point, which must lie in the chart set with DMPlexSetChart() 2985 - cone - An array of points which are on the in-edges for point p 2986 2987 Output Parameter: 2988 2989 Note: 2990 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2991 2992 Level: beginner 2993 2994 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2995 @*/ 2996 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) { 2997 DM_Plex *mesh = (DM_Plex *)dm->data; 2998 PetscInt pStart, pEnd; 2999 PetscInt dof, off, c; 3000 3001 PetscFunctionBegin; 3002 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3003 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3004 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3005 if (dof) PetscValidIntPointer(cone, 3); 3006 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3007 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); 3008 for (c = 0; c < dof; ++c) { 3009 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); 3010 mesh->cones[off + c] = cone[c]; 3011 } 3012 PetscFunctionReturn(0); 3013 } 3014 3015 /*@C 3016 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3017 3018 Not collective 3019 3020 Input Parameters: 3021 + mesh - The DMPlex 3022 - p - The point, which must lie in the chart set with DMPlexSetChart() 3023 3024 Output Parameter: 3025 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3026 integer giving the prescription for cone traversal. 3027 3028 Level: beginner 3029 3030 Notes: 3031 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3032 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3033 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3034 with the identity. 3035 3036 Fortran Notes: 3037 Since it returns an array, this routine is only available in Fortran 90, and you must 3038 include petsc.h90 in your code. 3039 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3040 DMPlexRestoreConeOrientation() is not needed/available in C. 3041 3042 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3043 @*/ 3044 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) { 3045 DM_Plex *mesh = (DM_Plex *)dm->data; 3046 PetscInt off; 3047 3048 PetscFunctionBegin; 3049 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3050 if (PetscDefined(USE_DEBUG)) { 3051 PetscInt dof; 3052 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3053 if (dof) PetscValidPointer(coneOrientation, 3); 3054 } 3055 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3056 3057 *coneOrientation = &mesh->coneOrientations[off]; 3058 PetscFunctionReturn(0); 3059 } 3060 3061 /*@ 3062 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3063 3064 Not collective 3065 3066 Input Parameters: 3067 + mesh - The DMPlex 3068 . p - The point, which must lie in the chart set with DMPlexSetChart() 3069 - coneOrientation - An array of orientations 3070 Output Parameter: 3071 3072 Notes: 3073 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3074 3075 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3076 3077 Level: beginner 3078 3079 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3080 @*/ 3081 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) { 3082 DM_Plex *mesh = (DM_Plex *)dm->data; 3083 PetscInt pStart, pEnd; 3084 PetscInt dof, off, c; 3085 3086 PetscFunctionBegin; 3087 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3088 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3089 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3090 if (dof) PetscValidIntPointer(coneOrientation, 3); 3091 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3092 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); 3093 for (c = 0; c < dof; ++c) { 3094 PetscInt cdof, o = coneOrientation[c]; 3095 3096 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off + c], &cdof)); 3097 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); 3098 mesh->coneOrientations[off + c] = o; 3099 } 3100 PetscFunctionReturn(0); 3101 } 3102 3103 /*@ 3104 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3105 3106 Not collective 3107 3108 Input Parameters: 3109 + mesh - The DMPlex 3110 . p - The point, which must lie in the chart set with DMPlexSetChart() 3111 . conePos - The local index in the cone where the point should be put 3112 - conePoint - The mesh point to insert 3113 3114 Level: beginner 3115 3116 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3117 @*/ 3118 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) { 3119 DM_Plex *mesh = (DM_Plex *)dm->data; 3120 PetscInt pStart, pEnd; 3121 PetscInt dof, off; 3122 3123 PetscFunctionBegin; 3124 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3125 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3126 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); 3127 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); 3128 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3129 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3130 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); 3131 mesh->cones[off + conePos] = conePoint; 3132 PetscFunctionReturn(0); 3133 } 3134 3135 /*@ 3136 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3137 3138 Not collective 3139 3140 Input Parameters: 3141 + mesh - The DMPlex 3142 . p - The point, which must lie in the chart set with DMPlexSetChart() 3143 . conePos - The local index in the cone where the point should be put 3144 - coneOrientation - The point orientation to insert 3145 3146 Level: beginner 3147 3148 Notes: 3149 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3150 3151 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3152 @*/ 3153 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) { 3154 DM_Plex *mesh = (DM_Plex *)dm->data; 3155 PetscInt pStart, pEnd; 3156 PetscInt dof, off; 3157 3158 PetscFunctionBegin; 3159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3160 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3161 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); 3162 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3163 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3164 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); 3165 mesh->coneOrientations[off + conePos] = coneOrientation; 3166 PetscFunctionReturn(0); 3167 } 3168 3169 /*@ 3170 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3171 3172 Not collective 3173 3174 Input Parameters: 3175 + mesh - The DMPlex 3176 - p - The point, which must lie in the chart set with DMPlexSetChart() 3177 3178 Output Parameter: 3179 . size - The support size for point p 3180 3181 Level: beginner 3182 3183 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3184 @*/ 3185 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) { 3186 DM_Plex *mesh = (DM_Plex *)dm->data; 3187 3188 PetscFunctionBegin; 3189 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3190 PetscValidIntPointer(size, 3); 3191 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3192 PetscFunctionReturn(0); 3193 } 3194 3195 /*@ 3196 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3197 3198 Not collective 3199 3200 Input Parameters: 3201 + mesh - The DMPlex 3202 . p - The point, which must lie in the chart set with DMPlexSetChart() 3203 - size - The support size for point p 3204 3205 Output Parameter: 3206 3207 Note: 3208 This should be called after DMPlexSetChart(). 3209 3210 Level: beginner 3211 3212 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3213 @*/ 3214 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) { 3215 DM_Plex *mesh = (DM_Plex *)dm->data; 3216 3217 PetscFunctionBegin; 3218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3219 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3220 PetscFunctionReturn(0); 3221 } 3222 3223 /*@C 3224 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3225 3226 Not collective 3227 3228 Input Parameters: 3229 + mesh - The DMPlex 3230 - p - The point, which must lie in the chart set with DMPlexSetChart() 3231 3232 Output Parameter: 3233 . support - An array of points which are on the out-edges for point p 3234 3235 Level: beginner 3236 3237 Fortran Notes: 3238 Since it returns an array, this routine is only available in Fortran 90, and you must 3239 include petsc.h90 in your code. 3240 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3241 DMPlexRestoreSupport() is not needed/available in C. 3242 3243 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3244 @*/ 3245 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) { 3246 DM_Plex *mesh = (DM_Plex *)dm->data; 3247 PetscInt off; 3248 3249 PetscFunctionBegin; 3250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3251 PetscValidPointer(support, 3); 3252 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3253 *support = &mesh->supports[off]; 3254 PetscFunctionReturn(0); 3255 } 3256 3257 /*@ 3258 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3259 3260 Not collective 3261 3262 Input Parameters: 3263 + mesh - The DMPlex 3264 . p - The point, which must lie in the chart set with DMPlexSetChart() 3265 - support - An array of points which are on the out-edges for point p 3266 3267 Output Parameter: 3268 3269 Note: 3270 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3271 3272 Level: beginner 3273 3274 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3275 @*/ 3276 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) { 3277 DM_Plex *mesh = (DM_Plex *)dm->data; 3278 PetscInt pStart, pEnd; 3279 PetscInt dof, off, c; 3280 3281 PetscFunctionBegin; 3282 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3283 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3284 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3285 if (dof) PetscValidIntPointer(support, 3); 3286 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3287 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); 3288 for (c = 0; c < dof; ++c) { 3289 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); 3290 mesh->supports[off + c] = support[c]; 3291 } 3292 PetscFunctionReturn(0); 3293 } 3294 3295 /*@ 3296 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3297 3298 Not collective 3299 3300 Input Parameters: 3301 + mesh - The DMPlex 3302 . p - The point, which must lie in the chart set with DMPlexSetChart() 3303 . supportPos - The local index in the cone where the point should be put 3304 - supportPoint - The mesh point to insert 3305 3306 Level: beginner 3307 3308 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3309 @*/ 3310 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) { 3311 DM_Plex *mesh = (DM_Plex *)dm->data; 3312 PetscInt pStart, pEnd; 3313 PetscInt dof, off; 3314 3315 PetscFunctionBegin; 3316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3317 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3318 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3319 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3320 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); 3321 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); 3322 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); 3323 mesh->supports[off + supportPos] = supportPoint; 3324 PetscFunctionReturn(0); 3325 } 3326 3327 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3328 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3329 switch (ct) { 3330 case DM_POLYTOPE_SEGMENT: 3331 if (o == -1) return -2; 3332 break; 3333 case DM_POLYTOPE_TRIANGLE: 3334 if (o == -3) return -1; 3335 if (o == -2) return -3; 3336 if (o == -1) return -2; 3337 break; 3338 case DM_POLYTOPE_QUADRILATERAL: 3339 if (o == -4) return -2; 3340 if (o == -3) return -1; 3341 if (o == -2) return -4; 3342 if (o == -1) return -3; 3343 break; 3344 default: return o; 3345 } 3346 return o; 3347 } 3348 3349 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3350 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) { 3351 switch (ct) { 3352 case DM_POLYTOPE_SEGMENT: 3353 if ((o == -2) || (o == 1)) return -1; 3354 if (o == -1) return 0; 3355 break; 3356 case DM_POLYTOPE_TRIANGLE: 3357 if (o == -3) return -2; 3358 if (o == -2) return -1; 3359 if (o == -1) return -3; 3360 break; 3361 case DM_POLYTOPE_QUADRILATERAL: 3362 if (o == -4) return -2; 3363 if (o == -3) return -1; 3364 if (o == -2) return -4; 3365 if (o == -1) return -3; 3366 break; 3367 default: return o; 3368 } 3369 return o; 3370 } 3371 3372 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3373 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) { 3374 PetscInt pStart, pEnd, p; 3375 3376 PetscFunctionBegin; 3377 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3378 for (p = pStart; p < pEnd; ++p) { 3379 const PetscInt *cone, *ornt; 3380 PetscInt coneSize, c; 3381 3382 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3383 PetscCall(DMPlexGetCone(dm, p, &cone)); 3384 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3385 for (c = 0; c < coneSize; ++c) { 3386 DMPolytopeType ct; 3387 const PetscInt o = ornt[c]; 3388 3389 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3390 switch (ct) { 3391 case DM_POLYTOPE_SEGMENT: 3392 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3393 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3394 break; 3395 case DM_POLYTOPE_TRIANGLE: 3396 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3397 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3398 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3399 break; 3400 case DM_POLYTOPE_QUADRILATERAL: 3401 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3402 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3403 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3404 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3405 break; 3406 default: break; 3407 } 3408 } 3409 } 3410 PetscFunctionReturn(0); 3411 } 3412 3413 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3414 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3415 PetscInt *closure; 3416 const PetscInt *tmp = NULL, *tmpO = NULL; 3417 PetscInt off = 0, tmpSize, t; 3418 3419 PetscFunctionBeginHot; 3420 if (ornt) { 3421 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3422 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3423 } 3424 if (*points) { 3425 closure = *points; 3426 } else { 3427 PetscInt maxConeSize, maxSupportSize; 3428 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3429 PetscCall(DMGetWorkArray(dm, 2 * (PetscMax(maxConeSize, maxSupportSize) + 1), MPIU_INT, &closure)); 3430 } 3431 if (useCone) { 3432 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3433 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3434 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3435 } else { 3436 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3437 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3438 } 3439 if (ct == DM_POLYTOPE_UNKNOWN) { 3440 closure[off++] = p; 3441 closure[off++] = 0; 3442 for (t = 0; t < tmpSize; ++t) { 3443 closure[off++] = tmp[t]; 3444 closure[off++] = tmpO ? tmpO[t] : 0; 3445 } 3446 } else { 3447 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3448 3449 /* We assume that cells with a valid type have faces with a valid type */ 3450 closure[off++] = p; 3451 closure[off++] = ornt; 3452 for (t = 0; t < tmpSize; ++t) { 3453 DMPolytopeType ft; 3454 3455 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3456 closure[off++] = tmp[arr[t]]; 3457 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3458 } 3459 } 3460 if (numPoints) *numPoints = tmpSize + 1; 3461 if (points) *points = closure; 3462 PetscFunctionReturn(0); 3463 } 3464 3465 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3466 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) { 3467 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3468 const PetscInt *cone, *ornt; 3469 PetscInt *pts, *closure = NULL; 3470 DMPolytopeType ft; 3471 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3472 PetscInt dim, coneSize, c, d, clSize, cl; 3473 3474 PetscFunctionBeginHot; 3475 PetscCall(DMGetDimension(dm, &dim)); 3476 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3477 PetscCall(DMPlexGetCone(dm, point, &cone)); 3478 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3479 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3480 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim + 1) - 1) / (maxConeSize - 1)) : dim + 1; 3481 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim + 1) - 1) / (maxSupportSize - 1)) : dim + 1; 3482 maxSize = PetscMax(coneSeries, supportSeries); 3483 if (*points) { 3484 pts = *points; 3485 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &pts)); 3486 c = 0; 3487 pts[c++] = point; 3488 pts[c++] = o; 3489 PetscCall(DMPlexGetCellType(dm, cone[arr[0 * 2 + 0]], &ft)); 3490 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[0 * 2 + 1], ornt[0]), useCone, &clSize, &closure)); 3491 for (cl = 0; cl < clSize * 2; cl += 2) { 3492 pts[c++] = closure[cl]; 3493 pts[c++] = closure[cl + 1]; 3494 } 3495 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1 * 2 + 0]], DMPolytopeTypeComposeOrientation(ft, arr[1 * 2 + 1], ornt[1]), useCone, &clSize, &closure)); 3496 for (cl = 0; cl < clSize * 2; cl += 2) { 3497 pts[c++] = closure[cl]; 3498 pts[c++] = closure[cl + 1]; 3499 } 3500 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3501 for (d = 2; d < coneSize; ++d) { 3502 PetscCall(DMPlexGetCellType(dm, cone[arr[d * 2 + 0]], &ft)); 3503 pts[c++] = cone[arr[d * 2 + 0]]; 3504 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d]); 3505 } 3506 if (dim >= 3) { 3507 for (d = 2; d < coneSize; ++d) { 3508 const PetscInt fpoint = cone[arr[d * 2 + 0]]; 3509 const PetscInt *fcone, *fornt; 3510 PetscInt fconeSize, fc, i; 3511 3512 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3513 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d * 2 + 1], ornt[d])); 3514 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3515 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3516 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3517 for (fc = 0; fc < fconeSize; ++fc) { 3518 const PetscInt cp = fcone[farr[fc * 2 + 0]]; 3519 const PetscInt co = farr[fc * 2 + 1]; 3520 3521 for (i = 0; i < c; i += 2) 3522 if (pts[i] == cp) break; 3523 if (i == c) { 3524 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3525 pts[c++] = cp; 3526 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc * 2 + 0]]); 3527 } 3528 } 3529 } 3530 } 3531 *numPoints = c / 2; 3532 *points = pts; 3533 PetscFunctionReturn(0); 3534 } 3535 3536 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3537 DMPolytopeType ct; 3538 PetscInt *closure, *fifo; 3539 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3540 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3541 PetscInt depth, maxSize; 3542 3543 PetscFunctionBeginHot; 3544 PetscCall(DMPlexGetDepth(dm, &depth)); 3545 if (depth == 1) { 3546 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3547 PetscFunctionReturn(0); 3548 } 3549 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3550 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3551 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3552 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3553 PetscFunctionReturn(0); 3554 } 3555 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3556 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth + 1) - 1) / (maxConeSize - 1)) : depth + 1; 3557 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth + 1) - 1) / (maxSupportSize - 1)) : depth + 1; 3558 maxSize = PetscMax(coneSeries, supportSeries); 3559 PetscCall(DMGetWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3560 if (*points) { 3561 closure = *points; 3562 } else PetscCall(DMGetWorkArray(dm, 2 * maxSize, MPIU_INT, &closure)); 3563 closure[closureSize++] = p; 3564 closure[closureSize++] = ornt; 3565 fifo[fifoSize++] = p; 3566 fifo[fifoSize++] = ornt; 3567 fifo[fifoSize++] = ct; 3568 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3569 while (fifoSize - fifoStart) { 3570 const PetscInt q = fifo[fifoStart++]; 3571 const PetscInt o = fifo[fifoStart++]; 3572 const DMPolytopeType qt = (DMPolytopeType)fifo[fifoStart++]; 3573 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3574 const PetscInt *tmp, *tmpO; 3575 PetscInt tmpSize, t; 3576 3577 if (PetscDefined(USE_DEBUG)) { 3578 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt) / 2; 3579 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); 3580 } 3581 if (useCone) { 3582 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3583 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3584 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3585 } else { 3586 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3587 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3588 tmpO = NULL; 3589 } 3590 for (t = 0; t < tmpSize; ++t) { 3591 const PetscInt ip = useCone && qarr ? qarr[t * 2] : t; 3592 const PetscInt io = useCone && qarr ? qarr[t * 2 + 1] : 0; 3593 const PetscInt cp = tmp[ip]; 3594 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3595 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3596 PetscInt c; 3597 3598 /* Check for duplicate */ 3599 for (c = 0; c < closureSize; c += 2) { 3600 if (closure[c] == cp) break; 3601 } 3602 if (c == closureSize) { 3603 closure[closureSize++] = cp; 3604 closure[closureSize++] = co; 3605 fifo[fifoSize++] = cp; 3606 fifo[fifoSize++] = co; 3607 fifo[fifoSize++] = ct; 3608 } 3609 } 3610 } 3611 PetscCall(DMRestoreWorkArray(dm, 3 * maxSize, MPIU_INT, &fifo)); 3612 if (numPoints) *numPoints = closureSize / 2; 3613 if (points) *points = closure; 3614 PetscFunctionReturn(0); 3615 } 3616 3617 /*@C 3618 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3619 3620 Not collective 3621 3622 Input Parameters: 3623 + dm - The DMPlex 3624 . p - The mesh point 3625 - useCone - PETSC_TRUE for the closure, otherwise return the star 3626 3627 Input/Output Parameter: 3628 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3629 if NULL on input, internal storage will be returned, otherwise the provided array is used 3630 3631 Output Parameter: 3632 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3633 3634 Note: 3635 If using internal storage (points is NULL on input), each call overwrites the last output. 3636 3637 Fortran Note: 3638 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3639 3640 Level: beginner 3641 3642 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3643 @*/ 3644 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3645 PetscFunctionBeginHot; 3646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3647 if (numPoints) PetscValidIntPointer(numPoints, 4); 3648 if (points) PetscValidPointer(points, 5); 3649 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3650 PetscFunctionReturn(0); 3651 } 3652 3653 /*@C 3654 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3655 3656 Not collective 3657 3658 Input Parameters: 3659 + dm - The DMPlex 3660 . p - The mesh point 3661 . useCone - PETSC_TRUE for the closure, otherwise return the star 3662 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3663 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3664 3665 Note: 3666 If not using internal storage (points is not NULL on input), this call is unnecessary 3667 3668 Level: beginner 3669 3670 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3671 @*/ 3672 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) { 3673 PetscFunctionBeginHot; 3674 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3675 if (numPoints) *numPoints = 0; 3676 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3677 PetscFunctionReturn(0); 3678 } 3679 3680 /*@ 3681 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3682 3683 Not collective 3684 3685 Input Parameter: 3686 . mesh - The DMPlex 3687 3688 Output Parameters: 3689 + maxConeSize - The maximum number of in-edges 3690 - maxSupportSize - The maximum number of out-edges 3691 3692 Level: beginner 3693 3694 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3695 @*/ 3696 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) { 3697 DM_Plex *mesh = (DM_Plex *)dm->data; 3698 3699 PetscFunctionBegin; 3700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3701 if (maxConeSize) PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3702 if (maxSupportSize) PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3703 PetscFunctionReturn(0); 3704 } 3705 3706 PetscErrorCode DMSetUp_Plex(DM dm) { 3707 DM_Plex *mesh = (DM_Plex *)dm->data; 3708 PetscInt size, maxSupportSize; 3709 3710 PetscFunctionBegin; 3711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3712 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3713 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3714 PetscCall(PetscMalloc1(size, &mesh->cones)); 3715 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3716 PetscCall(PetscLogObjectMemory((PetscObject)dm, size * 2 * sizeof(PetscInt))); 3717 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3718 if (maxSupportSize) { 3719 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3720 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3721 PetscCall(PetscMalloc1(size, &mesh->supports)); 3722 PetscCall(PetscLogObjectMemory((PetscObject)dm, size * sizeof(PetscInt))); 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) { 6432 PetscFunctionBegin; 6433 if (label) { 6434 PetscBool contains; 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(1); 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 6472 if (!fieldActive[f]) { 6473 for (p = 0; p < numPoints * 2; p += 2) { 6474 PetscInt fdof; 6475 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6476 offset += fdof; 6477 } 6478 continue; 6479 } 6480 PetscCall(PetscSectionGetFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6481 switch (mode) { 6482 case INSERT_VALUES: 6483 for (p = 0; p < numPoints; p++) { 6484 const PetscInt point = points[2 * p]; 6485 const PetscInt *perm = perms ? perms[p] : NULL; 6486 const PetscScalar *flip = flips ? flips[p] : NULL; 6487 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6488 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6489 } 6490 break; 6491 case INSERT_ALL_VALUES: 6492 for (p = 0; p < numPoints; p++) { 6493 const PetscInt point = points[2 * p]; 6494 const PetscInt *perm = perms ? perms[p] : NULL; 6495 const PetscScalar *flip = flips ? flips[p] : NULL; 6496 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6497 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6498 } 6499 break; 6500 case INSERT_BC_VALUES: 6501 for (p = 0; p < numPoints; p++) { 6502 const PetscInt point = points[2 * p]; 6503 const PetscInt *perm = perms ? perms[p] : NULL; 6504 const PetscScalar *flip = flips ? flips[p] : NULL; 6505 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6506 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6507 } 6508 break; 6509 case ADD_VALUES: 6510 for (p = 0; p < numPoints; p++) { 6511 const PetscInt point = points[2 * p]; 6512 const PetscInt *perm = perms ? perms[p] : NULL; 6513 const PetscScalar *flip = flips ? flips[p] : NULL; 6514 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6515 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6516 } 6517 break; 6518 case ADD_ALL_VALUES: 6519 for (p = 0; p < numPoints; p++) { 6520 const PetscInt point = points[2 * p]; 6521 const PetscInt *perm = perms ? perms[p] : NULL; 6522 const PetscScalar *flip = flips ? flips[p] : NULL; 6523 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6524 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6525 } 6526 break; 6527 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6528 } 6529 PetscCall(PetscSectionRestoreFieldPointSyms(section, f, numPoints, points, &perms, &flips)); 6530 } 6531 /* Cleanup points */ 6532 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &numPoints, &points, &clSection, &clPoints, &clp)); 6533 /* Cleanup array */ 6534 PetscCall(VecRestoreArray(v, &array)); 6535 PetscFunctionReturn(0); 6536 } 6537 6538 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) { 6539 PetscMPIInt rank; 6540 PetscInt i, j; 6541 6542 PetscFunctionBegin; 6543 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6544 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6545 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6546 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6547 numCIndices = numCIndices ? numCIndices : numRIndices; 6548 if (!values) PetscFunctionReturn(0); 6549 for (i = 0; i < numRIndices; i++) { 6550 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6551 for (j = 0; j < numCIndices; j++) { 6552 #if defined(PETSC_USE_COMPLEX) 6553 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i * numCIndices + j]), (double)PetscImaginaryPart(values[i * numCIndices + j]))); 6554 #else 6555 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i * numCIndices + j])); 6556 #endif 6557 } 6558 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6559 } 6560 PetscFunctionReturn(0); 6561 } 6562 6563 /* 6564 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6565 6566 Input Parameters: 6567 + section - The section for this data layout 6568 . islocal - Is the section (and thus indices being requested) local or global? 6569 . point - The point contributing dofs with these indices 6570 . off - The global offset of this point 6571 . loff - The local offset of each field 6572 . setBC - The flag determining whether to include indices of boundary values 6573 . perm - A permutation of the dofs on this point, or NULL 6574 - indperm - A permutation of the entire indices array, or NULL 6575 6576 Output Parameter: 6577 . indices - Indices for dofs on this point 6578 6579 Level: developer 6580 6581 Note: The indices could be local or global, depending on the value of 'off'. 6582 */ 6583 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) { 6584 PetscInt dof; /* The number of unknowns on this point */ 6585 PetscInt cdof; /* The number of constraints on this point */ 6586 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6587 PetscInt cind = 0, k; 6588 6589 PetscFunctionBegin; 6590 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6591 PetscCall(PetscSectionGetDof(section, point, &dof)); 6592 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6593 if (!cdof || setBC) { 6594 for (k = 0; k < dof; ++k) { 6595 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6596 const PetscInt ind = indperm ? indperm[preind] : preind; 6597 6598 indices[ind] = off + k; 6599 } 6600 } else { 6601 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6602 for (k = 0; k < dof; ++k) { 6603 const PetscInt preind = perm ? *loff + perm[k] : *loff + k; 6604 const PetscInt ind = indperm ? indperm[preind] : preind; 6605 6606 if ((cind < cdof) && (k == cdofs[cind])) { 6607 /* Insert check for returning constrained indices */ 6608 indices[ind] = -(off + k + 1); 6609 ++cind; 6610 } else { 6611 indices[ind] = off + k - (islocal ? 0 : cind); 6612 } 6613 } 6614 } 6615 *loff += dof; 6616 PetscFunctionReturn(0); 6617 } 6618 6619 /* 6620 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6621 6622 Input Parameters: 6623 + section - a section (global or local) 6624 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6625 . point - point within section 6626 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6627 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6628 . setBC - identify constrained (boundary condition) points via involution. 6629 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6630 . permsoff - offset 6631 - indperm - index permutation 6632 6633 Output Parameter: 6634 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6635 . indices - array to hold indices (as defined by section) of each dof associated with point 6636 6637 Notes: 6638 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6639 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6640 in the local vector. 6641 6642 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6643 significant). It is invalid to call with a global section and setBC=true. 6644 6645 Developer Note: 6646 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6647 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6648 offset could be obtained from the section instead of passing it explicitly as we do now. 6649 6650 Example: 6651 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6652 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6653 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6654 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. 6655 6656 Level: developer 6657 */ 6658 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[]) { 6659 PetscInt numFields, foff, f; 6660 6661 PetscFunctionBegin; 6662 PetscCheck(islocal || !setBC, PetscObjectComm((PetscObject)section), PETSC_ERR_ARG_INCOMP, "setBC incompatible with global indices; use a local section or disable setBC"); 6663 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6664 for (f = 0, foff = 0; f < numFields; ++f) { 6665 PetscInt fdof, cfdof; 6666 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6667 PetscInt cind = 0, b; 6668 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6669 6670 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6671 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6672 if (!cfdof || setBC) { 6673 for (b = 0; b < fdof; ++b) { 6674 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6675 const PetscInt ind = indperm ? indperm[preind] : preind; 6676 6677 indices[ind] = off + foff + b; 6678 } 6679 } else { 6680 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6681 for (b = 0; b < fdof; ++b) { 6682 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6683 const PetscInt ind = indperm ? indperm[preind] : preind; 6684 6685 if ((cind < cfdof) && (b == fcdofs[cind])) { 6686 indices[ind] = -(off + foff + b + 1); 6687 ++cind; 6688 } else { 6689 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6690 } 6691 } 6692 } 6693 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6694 foffs[f] += fdof; 6695 } 6696 PetscFunctionReturn(0); 6697 } 6698 6699 /* 6700 This version believes the globalSection offsets for each field, rather than just the point offset 6701 6702 . foffs - The offset into 'indices' for each field, since it is segregated by field 6703 6704 Notes: 6705 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6706 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6707 */ 6708 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) { 6709 PetscInt numFields, foff, f; 6710 6711 PetscFunctionBegin; 6712 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6713 for (f = 0; f < numFields; ++f) { 6714 PetscInt fdof, cfdof; 6715 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6716 PetscInt cind = 0, b; 6717 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6718 6719 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6720 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6721 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6722 if (!cfdof) { 6723 for (b = 0; b < fdof; ++b) { 6724 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6725 const PetscInt ind = indperm ? indperm[preind] : preind; 6726 6727 indices[ind] = foff + b; 6728 } 6729 } else { 6730 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6731 for (b = 0; b < fdof; ++b) { 6732 const PetscInt preind = perm ? foffs[f] + perm[b] : foffs[f] + b; 6733 const PetscInt ind = indperm ? indperm[preind] : preind; 6734 6735 if ((cind < cfdof) && (b == fcdofs[cind])) { 6736 indices[ind] = -(foff + b + 1); 6737 ++cind; 6738 } else { 6739 indices[ind] = foff + b - cind; 6740 } 6741 } 6742 } 6743 foffs[f] += fdof; 6744 } 6745 PetscFunctionReturn(0); 6746 } 6747 6748 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) { 6749 Mat cMat; 6750 PetscSection aSec, cSec; 6751 IS aIS; 6752 PetscInt aStart = -1, aEnd = -1; 6753 const PetscInt *anchors; 6754 PetscInt numFields, f, p, q, newP = 0; 6755 PetscInt newNumPoints = 0, newNumIndices = 0; 6756 PetscInt *newPoints, *indices, *newIndices; 6757 PetscInt maxAnchor, maxDof; 6758 PetscInt newOffsets[32]; 6759 PetscInt *pointMatOffsets[32]; 6760 PetscInt *newPointOffsets[32]; 6761 PetscScalar *pointMat[32]; 6762 PetscScalar *newValues = NULL, *tmpValues; 6763 PetscBool anyConstrained = PETSC_FALSE; 6764 6765 PetscFunctionBegin; 6766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6767 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6768 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6769 6770 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 6771 /* if there are point-to-point constraints */ 6772 if (aSec) { 6773 PetscCall(PetscArrayzero(newOffsets, 32)); 6774 PetscCall(ISGetIndices(aIS, &anchors)); 6775 PetscCall(PetscSectionGetChart(aSec, &aStart, &aEnd)); 6776 /* figure out how many points are going to be in the new element matrix 6777 * (we allow double counting, because it's all just going to be summed 6778 * into the global matrix anyway) */ 6779 for (p = 0; p < 2 * numPoints; p += 2) { 6780 PetscInt b = points[p]; 6781 PetscInt bDof = 0, bSecDof; 6782 6783 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6784 if (!bSecDof) { continue; } 6785 if (b >= aStart && b < aEnd) { PetscCall(PetscSectionGetDof(aSec, b, &bDof)); } 6786 if (bDof) { 6787 /* this point is constrained */ 6788 /* it is going to be replaced by its anchors */ 6789 PetscInt bOff, q; 6790 6791 anyConstrained = PETSC_TRUE; 6792 newNumPoints += bDof; 6793 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6794 for (q = 0; q < bDof; q++) { 6795 PetscInt a = anchors[bOff + q]; 6796 PetscInt aDof; 6797 6798 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6799 newNumIndices += aDof; 6800 for (f = 0; f < numFields; ++f) { 6801 PetscInt fDof; 6802 6803 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6804 newOffsets[f + 1] += fDof; 6805 } 6806 } 6807 } else { 6808 /* this point is not constrained */ 6809 newNumPoints++; 6810 newNumIndices += bSecDof; 6811 for (f = 0; f < numFields; ++f) { 6812 PetscInt fDof; 6813 6814 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6815 newOffsets[f + 1] += fDof; 6816 } 6817 } 6818 } 6819 } 6820 if (!anyConstrained) { 6821 if (outNumPoints) *outNumPoints = 0; 6822 if (outNumIndices) *outNumIndices = 0; 6823 if (outPoints) *outPoints = NULL; 6824 if (outValues) *outValues = NULL; 6825 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6826 PetscFunctionReturn(0); 6827 } 6828 6829 if (outNumPoints) *outNumPoints = newNumPoints; 6830 if (outNumIndices) *outNumIndices = newNumIndices; 6831 6832 for (f = 0; f < numFields; ++f) newOffsets[f + 1] += newOffsets[f]; 6833 6834 if (!outPoints && !outValues) { 6835 if (offsets) { 6836 for (f = 0; f <= numFields; f++) { offsets[f] = newOffsets[f]; } 6837 } 6838 if (aSec) PetscCall(ISRestoreIndices(aIS, &anchors)); 6839 PetscFunctionReturn(0); 6840 } 6841 6842 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6843 6844 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6845 6846 /* workspaces */ 6847 if (numFields) { 6848 for (f = 0; f < numFields; f++) { 6849 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 6850 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 6851 } 6852 } else { 6853 PetscCall(DMGetWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 6854 PetscCall(DMGetWorkArray(dm, numPoints, MPIU_INT, &newPointOffsets[0])); 6855 } 6856 6857 /* get workspaces for the point-to-point matrices */ 6858 if (numFields) { 6859 PetscInt totalOffset, totalMatOffset; 6860 6861 for (p = 0; p < numPoints; p++) { 6862 PetscInt b = points[2 * p]; 6863 PetscInt bDof = 0, bSecDof; 6864 6865 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6866 if (!bSecDof) { 6867 for (f = 0; f < numFields; f++) { 6868 newPointOffsets[f][p + 1] = 0; 6869 pointMatOffsets[f][p + 1] = 0; 6870 } 6871 continue; 6872 } 6873 if (b >= aStart && b < aEnd) { PetscCall(PetscSectionGetDof(aSec, b, &bDof)); } 6874 if (bDof) { 6875 for (f = 0; f < numFields; f++) { 6876 PetscInt fDof, q, bOff, allFDof = 0; 6877 6878 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6879 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6880 for (q = 0; q < bDof; q++) { 6881 PetscInt a = anchors[bOff + q]; 6882 PetscInt aFDof; 6883 6884 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6885 allFDof += aFDof; 6886 } 6887 newPointOffsets[f][p + 1] = allFDof; 6888 pointMatOffsets[f][p + 1] = fDof * allFDof; 6889 } 6890 } else { 6891 for (f = 0; f < numFields; f++) { 6892 PetscInt fDof; 6893 6894 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6895 newPointOffsets[f][p + 1] = fDof; 6896 pointMatOffsets[f][p + 1] = 0; 6897 } 6898 } 6899 } 6900 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6901 newPointOffsets[f][0] = totalOffset; 6902 pointMatOffsets[f][0] = totalMatOffset; 6903 for (p = 0; p < numPoints; p++) { 6904 newPointOffsets[f][p + 1] += newPointOffsets[f][p]; 6905 pointMatOffsets[f][p + 1] += pointMatOffsets[f][p]; 6906 } 6907 totalOffset = newPointOffsets[f][numPoints]; 6908 totalMatOffset = pointMatOffsets[f][numPoints]; 6909 PetscCall(DMGetWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 6910 } 6911 } else { 6912 for (p = 0; p < numPoints; p++) { 6913 PetscInt b = points[2 * p]; 6914 PetscInt bDof = 0, bSecDof; 6915 6916 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6917 if (!bSecDof) { 6918 newPointOffsets[0][p + 1] = 0; 6919 pointMatOffsets[0][p + 1] = 0; 6920 continue; 6921 } 6922 if (b >= aStart && b < aEnd) { PetscCall(PetscSectionGetDof(aSec, b, &bDof)); } 6923 if (bDof) { 6924 PetscInt bOff, q, allDof = 0; 6925 6926 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6927 for (q = 0; q < bDof; q++) { 6928 PetscInt a = anchors[bOff + q], aDof; 6929 6930 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6931 allDof += aDof; 6932 } 6933 newPointOffsets[0][p + 1] = allDof; 6934 pointMatOffsets[0][p + 1] = bSecDof * allDof; 6935 } else { 6936 newPointOffsets[0][p + 1] = bSecDof; 6937 pointMatOffsets[0][p + 1] = 0; 6938 } 6939 } 6940 newPointOffsets[0][0] = 0; 6941 pointMatOffsets[0][0] = 0; 6942 for (p = 0; p < numPoints; p++) { 6943 newPointOffsets[0][p + 1] += newPointOffsets[0][p]; 6944 pointMatOffsets[0][p + 1] += pointMatOffsets[0][p]; 6945 } 6946 PetscCall(DMGetWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 6947 } 6948 6949 /* output arrays */ 6950 PetscCall(DMGetWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 6951 6952 /* get the point-to-point matrices; construct newPoints */ 6953 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6954 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6955 PetscCall(DMGetWorkArray(dm, maxDof, MPIU_INT, &indices)); 6956 PetscCall(DMGetWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 6957 if (numFields) { 6958 for (p = 0, newP = 0; p < numPoints; p++) { 6959 PetscInt b = points[2 * p]; 6960 PetscInt o = points[2 * p + 1]; 6961 PetscInt bDof = 0, bSecDof; 6962 6963 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6964 if (!bSecDof) { continue; } 6965 if (b >= aStart && b < aEnd) { PetscCall(PetscSectionGetDof(aSec, b, &bDof)); } 6966 if (bDof) { 6967 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6968 6969 fStart[0] = 0; 6970 fEnd[0] = 0; 6971 for (f = 0; f < numFields; f++) { 6972 PetscInt fDof; 6973 6974 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6975 fStart[f + 1] = fStart[f] + fDof; 6976 fEnd[f + 1] = fStart[f + 1]; 6977 } 6978 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6979 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6980 6981 fAnchorStart[0] = 0; 6982 fAnchorEnd[0] = 0; 6983 for (f = 0; f < numFields; f++) { 6984 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6985 6986 fAnchorStart[f + 1] = fAnchorStart[f] + fDof; 6987 fAnchorEnd[f + 1] = fAnchorStart[f + 1]; 6988 } 6989 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6990 for (q = 0; q < bDof; q++) { 6991 PetscInt a = anchors[bOff + q], aOff; 6992 6993 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6994 newPoints[2 * (newP + q)] = a; 6995 newPoints[2 * (newP + q) + 1] = 0; 6996 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 6997 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 6998 } 6999 newP += bDof; 7000 7001 if (outValues) { 7002 /* get the point-to-point submatrix */ 7003 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])); } 7004 } 7005 } else { 7006 newPoints[2 * newP] = b; 7007 newPoints[2 * newP + 1] = o; 7008 newP++; 7009 } 7010 } 7011 } else { 7012 for (p = 0; p < numPoints; p++) { 7013 PetscInt b = points[2 * p]; 7014 PetscInt o = points[2 * p + 1]; 7015 PetscInt bDof = 0, bSecDof; 7016 7017 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7018 if (!bSecDof) { continue; } 7019 if (b >= aStart && b < aEnd) { PetscCall(PetscSectionGetDof(aSec, b, &bDof)); } 7020 if (bDof) { 7021 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7022 7023 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7024 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7025 7026 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 7027 for (q = 0; q < bDof; q++) { 7028 PetscInt a = anchors[bOff + q], aOff; 7029 7030 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7031 7032 newPoints[2 * (newP + q)] = a; 7033 newPoints[2 * (newP + q) + 1] = 0; 7034 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7035 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7036 } 7037 newP += bDof; 7038 7039 /* get the point-to-point submatrix */ 7040 if (outValues) { PetscCall(MatGetValues(cMat, bEnd, indices, bAnchorEnd, newIndices, pointMat[0] + pointMatOffsets[0][p])); } 7041 } else { 7042 newPoints[2 * newP] = b; 7043 newPoints[2 * newP + 1] = o; 7044 newP++; 7045 } 7046 } 7047 } 7048 7049 if (outValues) { 7050 PetscCall(DMGetWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7051 PetscCall(PetscArrayzero(tmpValues, newNumIndices * numIndices)); 7052 /* multiply constraints on the right */ 7053 if (numFields) { 7054 for (f = 0; f < numFields; f++) { 7055 PetscInt oldOff = offsets[f]; 7056 7057 for (p = 0; p < numPoints; p++) { 7058 PetscInt cStart = newPointOffsets[f][p]; 7059 PetscInt b = points[2 * p]; 7060 PetscInt c, r, k; 7061 PetscInt dof; 7062 7063 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7064 if (!dof) { continue; } 7065 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7066 PetscInt nCols = newPointOffsets[f][p + 1] - cStart; 7067 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7068 7069 for (r = 0; r < numIndices; r++) { 7070 for (c = 0; c < nCols; c++) { 7071 for (k = 0; k < dof; k++) { tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; } 7072 } 7073 } 7074 } else { 7075 /* copy this column as is */ 7076 for (r = 0; r < numIndices; r++) { 7077 for (c = 0; c < dof; c++) { tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; } 7078 } 7079 } 7080 oldOff += dof; 7081 } 7082 } 7083 } else { 7084 PetscInt oldOff = 0; 7085 for (p = 0; p < numPoints; p++) { 7086 PetscInt cStart = newPointOffsets[0][p]; 7087 PetscInt b = points[2 * p]; 7088 PetscInt c, r, k; 7089 PetscInt dof; 7090 7091 PetscCall(PetscSectionGetDof(section, b, &dof)); 7092 if (!dof) { continue; } 7093 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7094 PetscInt nCols = newPointOffsets[0][p + 1] - cStart; 7095 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7096 7097 for (r = 0; r < numIndices; r++) { 7098 for (c = 0; c < nCols; c++) { 7099 for (k = 0; k < dof; k++) { tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; } 7100 } 7101 } 7102 } else { 7103 /* copy this column as is */ 7104 for (r = 0; r < numIndices; r++) { 7105 for (c = 0; c < dof; c++) { tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; } 7106 } 7107 } 7108 oldOff += dof; 7109 } 7110 } 7111 7112 if (multiplyLeft) { 7113 PetscCall(DMGetWorkArray(dm, newNumIndices * newNumIndices, MPIU_SCALAR, &newValues)); 7114 PetscCall(PetscArrayzero(newValues, newNumIndices * newNumIndices)); 7115 /* multiply constraints transpose on the left */ 7116 if (numFields) { 7117 for (f = 0; f < numFields; f++) { 7118 PetscInt oldOff = offsets[f]; 7119 7120 for (p = 0; p < numPoints; p++) { 7121 PetscInt rStart = newPointOffsets[f][p]; 7122 PetscInt b = points[2 * p]; 7123 PetscInt c, r, k; 7124 PetscInt dof; 7125 7126 PetscCall(PetscSectionGetFieldDof(section, b, f, &dof)); 7127 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7128 PetscInt nRows = newPointOffsets[f][p + 1] - rStart; 7129 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7130 7131 for (r = 0; r < nRows; r++) { 7132 for (c = 0; c < newNumIndices; c++) { 7133 for (k = 0; k < dof; k++) { newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; } 7134 } 7135 } 7136 } else { 7137 /* copy this row as is */ 7138 for (r = 0; r < dof; r++) { 7139 for (c = 0; c < newNumIndices; c++) { newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; } 7140 } 7141 } 7142 oldOff += dof; 7143 } 7144 } 7145 } else { 7146 PetscInt oldOff = 0; 7147 7148 for (p = 0; p < numPoints; p++) { 7149 PetscInt rStart = newPointOffsets[0][p]; 7150 PetscInt b = points[2 * p]; 7151 PetscInt c, r, k; 7152 PetscInt dof; 7153 7154 PetscCall(PetscSectionGetDof(section, b, &dof)); 7155 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7156 PetscInt nRows = newPointOffsets[0][p + 1] - rStart; 7157 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7158 7159 for (r = 0; r < nRows; r++) { 7160 for (c = 0; c < newNumIndices; c++) { 7161 for (k = 0; k < dof; k++) { newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; } 7162 } 7163 } 7164 } else { 7165 /* copy this row as is */ 7166 for (r = 0; r < dof; r++) { 7167 for (c = 0; c < newNumIndices; c++) { newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; } 7168 } 7169 } 7170 oldOff += dof; 7171 } 7172 } 7173 7174 PetscCall(DMRestoreWorkArray(dm, newNumIndices * numIndices, MPIU_SCALAR, &tmpValues)); 7175 } else { 7176 newValues = tmpValues; 7177 } 7178 } 7179 7180 /* clean up */ 7181 PetscCall(DMRestoreWorkArray(dm, maxDof, MPIU_INT, &indices)); 7182 PetscCall(DMRestoreWorkArray(dm, maxAnchor * maxDof, MPIU_INT, &newIndices)); 7183 7184 if (numFields) { 7185 for (f = 0; f < numFields; f++) { 7186 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[f][numPoints], MPIU_SCALAR, &pointMat[f])); 7187 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[f])); 7188 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[f])); 7189 } 7190 } else { 7191 PetscCall(DMRestoreWorkArray(dm, pointMatOffsets[0][numPoints], MPIU_SCALAR, &pointMat[0])); 7192 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &pointMatOffsets[0])); 7193 PetscCall(DMRestoreWorkArray(dm, numPoints + 1, MPIU_INT, &newPointOffsets[0])); 7194 } 7195 PetscCall(ISRestoreIndices(aIS, &anchors)); 7196 7197 /* output */ 7198 if (outPoints) { 7199 *outPoints = newPoints; 7200 } else { 7201 PetscCall(DMRestoreWorkArray(dm, 2 * newNumPoints, MPIU_INT, &newPoints)); 7202 } 7203 if (outValues) { *outValues = newValues; } 7204 for (f = 0; f <= numFields; f++) { offsets[f] = newOffsets[f]; } 7205 PetscFunctionReturn(0); 7206 } 7207 7208 /*@C 7209 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7210 7211 Not collective 7212 7213 Input Parameters: 7214 + dm - The DM 7215 . section - The PetscSection describing the points (a local section) 7216 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7217 . point - The point defining the closure 7218 - useClPerm - Use the closure point permutation if available 7219 7220 Output Parameters: 7221 + numIndices - The number of dof indices in the closure of point with the input sections 7222 . indices - The dof indices 7223 . outOffsets - Array to write the field offsets into, or NULL 7224 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7225 7226 Notes: 7227 Must call DMPlexRestoreClosureIndices() to free allocated memory 7228 7229 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7230 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7231 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7232 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7233 indices (with the above semantics) are implied. 7234 7235 Level: advanced 7236 7237 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7238 @*/ 7239 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7240 /* Closure ordering */ 7241 PetscSection clSection; 7242 IS clPoints; 7243 const PetscInt *clp; 7244 PetscInt *points; 7245 const PetscInt *clperm = NULL; 7246 /* Dof permutation and sign flips */ 7247 const PetscInt **perms[32] = {NULL}; 7248 const PetscScalar **flips[32] = {NULL}; 7249 PetscScalar *valCopy = NULL; 7250 /* Hanging node constraints */ 7251 PetscInt *pointsC = NULL; 7252 PetscScalar *valuesC = NULL; 7253 PetscInt NclC, NiC; 7254 7255 PetscInt *idx; 7256 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7257 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7258 7259 PetscFunctionBeginHot; 7260 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7261 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7262 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7263 if (numIndices) PetscValidIntPointer(numIndices, 6); 7264 if (indices) PetscValidPointer(indices, 7); 7265 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7266 if (values) PetscValidPointer(values, 9); 7267 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7268 PetscCheck(Nf <= 31, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7269 PetscCall(PetscArrayzero(offsets, 32)); 7270 /* 1) Get points in closure */ 7271 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7272 if (useClPerm) { 7273 PetscInt depth, clsize; 7274 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7275 for (clsize = 0, p = 0; p < Ncl; p++) { 7276 PetscInt dof; 7277 PetscCall(PetscSectionGetDof(section, points[2 * p], &dof)); 7278 clsize += dof; 7279 } 7280 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject)dm, depth, clsize, &clperm)); 7281 } 7282 /* 2) Get number of indices on these points and field offsets from section */ 7283 for (p = 0; p < Ncl * 2; p += 2) { 7284 PetscInt dof, fdof; 7285 7286 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7287 for (f = 0; f < Nf; ++f) { 7288 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7289 offsets[f + 1] += fdof; 7290 } 7291 Ni += dof; 7292 } 7293 for (f = 1; f < Nf; ++f) offsets[f + 1] += offsets[f]; 7294 PetscCheck(!Nf || offsets[Nf] == Ni, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7295 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7296 for (f = 0; f < PetscMax(1, Nf); ++f) { 7297 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7298 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7299 /* may need to apply sign changes to the element matrix */ 7300 if (values && flips[f]) { 7301 PetscInt foffset = offsets[f]; 7302 7303 for (p = 0; p < Ncl; ++p) { 7304 PetscInt pnt = points[2 * p], fdof; 7305 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7306 7307 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7308 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7309 if (flip) { 7310 PetscInt i, j, k; 7311 7312 if (!valCopy) { 7313 PetscCall(DMGetWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7314 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7315 *values = valCopy; 7316 } 7317 for (i = 0; i < fdof; ++i) { 7318 PetscScalar fval = flip[i]; 7319 7320 for (k = 0; k < Ni; ++k) { 7321 valCopy[Ni * (foffset + i) + k] *= fval; 7322 valCopy[Ni * k + (foffset + i)] *= fval; 7323 } 7324 } 7325 } 7326 foffset += fdof; 7327 } 7328 } 7329 } 7330 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7331 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7332 if (NclC) { 7333 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni * Ni, MPIU_SCALAR, &valCopy)); 7334 for (f = 0; f < PetscMax(1, Nf); ++f) { 7335 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7336 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7337 } 7338 for (f = 0; f < PetscMax(1, Nf); ++f) { 7339 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7340 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7341 } 7342 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7343 Ncl = NclC; 7344 Ni = NiC; 7345 points = pointsC; 7346 if (values) *values = valuesC; 7347 } 7348 /* 5) Calculate indices */ 7349 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7350 if (Nf) { 7351 PetscInt idxOff; 7352 PetscBool useFieldOffsets; 7353 7354 if (outOffsets) { 7355 for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f]; 7356 } 7357 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7358 if (useFieldOffsets) { 7359 for (p = 0; p < Ncl; ++p) { 7360 const PetscInt pnt = points[p * 2]; 7361 7362 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7363 } 7364 } else { 7365 for (p = 0; p < Ncl; ++p) { 7366 const PetscInt pnt = points[p * 2]; 7367 7368 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7369 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7370 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7371 * global section. */ 7372 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7373 } 7374 } 7375 } else { 7376 PetscInt off = 0, idxOff; 7377 7378 for (p = 0; p < Ncl; ++p) { 7379 const PetscInt pnt = points[p * 2]; 7380 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7381 7382 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7383 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7384 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7385 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff + 1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7386 } 7387 } 7388 /* 6) Cleanup */ 7389 for (f = 0; f < PetscMax(1, Nf); ++f) { 7390 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7391 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7392 } 7393 if (NclC) { 7394 PetscCall(DMRestoreWorkArray(dm, NclC * 2, MPIU_INT, &pointsC)); 7395 } else { 7396 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7397 } 7398 7399 if (numIndices) *numIndices = Ni; 7400 if (indices) *indices = idx; 7401 PetscFunctionReturn(0); 7402 } 7403 7404 /*@C 7405 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7406 7407 Not collective 7408 7409 Input Parameters: 7410 + dm - The DM 7411 . section - The PetscSection describing the points (a local section) 7412 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7413 . point - The point defining the closure 7414 - useClPerm - Use the closure point permutation if available 7415 7416 Output Parameters: 7417 + numIndices - The number of dof indices in the closure of point with the input sections 7418 . indices - The dof indices 7419 . outOffsets - Array to write the field offsets into, or NULL 7420 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7421 7422 Notes: 7423 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7424 7425 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7426 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7427 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7428 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7429 indices (with the above semantics) are implied. 7430 7431 Level: advanced 7432 7433 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7434 @*/ 7435 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) { 7436 PetscFunctionBegin; 7437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7438 PetscValidPointer(indices, 7); 7439 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7440 PetscFunctionReturn(0); 7441 } 7442 7443 /*@C 7444 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7445 7446 Not collective 7447 7448 Input Parameters: 7449 + dm - The DM 7450 . section - The section describing the layout in v, or NULL to use the default section 7451 . globalSection - The section describing the layout in v, or NULL to use the default global section 7452 . A - The matrix 7453 . point - The point in the DM 7454 . values - The array of values 7455 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7456 7457 Fortran Notes: 7458 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7459 7460 Level: intermediate 7461 7462 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7463 @*/ 7464 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7465 DM_Plex *mesh = (DM_Plex *)dm->data; 7466 PetscInt *indices; 7467 PetscInt numIndices; 7468 const PetscScalar *valuesOrig = values; 7469 PetscErrorCode ierr; 7470 7471 PetscFunctionBegin; 7472 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7473 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7474 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7475 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7476 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7477 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7478 7479 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7480 7481 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7482 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7483 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7484 if (ierr) { 7485 PetscMPIInt rank; 7486 7487 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7488 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7489 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7490 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7491 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7492 SETERRQ(PetscObjectComm((PetscObject)dm), ierr, "Not possible to set matrix values"); 7493 } 7494 if (mesh->printFEM > 1) { 7495 PetscInt i; 7496 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7497 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7498 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7499 } 7500 7501 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **)&values)); 7502 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7503 PetscFunctionReturn(0); 7504 } 7505 7506 /*@C 7507 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7508 7509 Not collective 7510 7511 Input Parameters: 7512 + dmRow - The DM for the row fields 7513 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7514 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7515 . dmCol - The DM for the column fields 7516 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7517 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7518 . A - The matrix 7519 . point - The point in the DMs 7520 . values - The array of values 7521 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7522 7523 Level: intermediate 7524 7525 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7526 @*/ 7527 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7528 DM_Plex *mesh = (DM_Plex *)dmRow->data; 7529 PetscInt *indicesRow, *indicesCol; 7530 PetscInt numIndicesRow, numIndicesCol; 7531 const PetscScalar *valuesOrig = values; 7532 PetscErrorCode ierr; 7533 7534 PetscFunctionBegin; 7535 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7536 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7537 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7538 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7539 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7540 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7541 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7542 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7543 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7544 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7545 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7546 7547 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7548 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7549 7550 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7551 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7552 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7553 if (ierr) { 7554 PetscMPIInt rank; 7555 7556 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7557 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7558 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7559 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7560 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **)&values)); 7561 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7562 } 7563 7564 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **)&values)); 7565 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **)&values)); 7566 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7567 PetscFunctionReturn(0); 7568 } 7569 7570 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) { 7571 DM_Plex *mesh = (DM_Plex *)dmf->data; 7572 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7573 PetscInt *cpoints = NULL; 7574 PetscInt *findices, *cindices; 7575 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7576 PetscInt foffsets[32], coffsets[32]; 7577 DMPolytopeType ct; 7578 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7579 PetscErrorCode ierr; 7580 7581 PetscFunctionBegin; 7582 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7583 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7584 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7585 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7586 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7587 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7588 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7589 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7590 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7591 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7592 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7593 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7594 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7595 PetscCall(PetscArrayzero(foffsets, 32)); 7596 PetscCall(PetscArrayzero(coffsets, 32)); 7597 /* Column indices */ 7598 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7599 maxFPoints = numCPoints; 7600 /* Compress out points not in the section */ 7601 /* TODO: Squeeze out points with 0 dof as well */ 7602 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7603 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7604 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7605 cpoints[q * 2] = cpoints[p]; 7606 cpoints[q * 2 + 1] = cpoints[p + 1]; 7607 ++q; 7608 } 7609 } 7610 numCPoints = q; 7611 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7612 PetscInt fdof; 7613 7614 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7615 if (!dof) continue; 7616 for (f = 0; f < numFields; ++f) { 7617 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7618 coffsets[f + 1] += fdof; 7619 } 7620 numCIndices += dof; 7621 } 7622 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7623 /* Row indices */ 7624 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7625 { 7626 DMPlexTransform tr; 7627 DMPolytopeType *rct; 7628 PetscInt *rsize, *rcone, *rornt, Nt; 7629 7630 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7631 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7632 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7633 numSubcells = rsize[Nt - 1]; 7634 PetscCall(DMPlexTransformDestroy(&tr)); 7635 } 7636 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7637 for (r = 0, q = 0; r < numSubcells; ++r) { 7638 /* TODO Map from coarse to fine cells */ 7639 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7640 /* Compress out points not in the section */ 7641 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7642 for (p = 0; p < numFPoints * 2; p += 2) { 7643 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7644 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7645 if (!dof) continue; 7646 for (s = 0; s < q; ++s) 7647 if (fpoints[p] == ftotpoints[s * 2]) break; 7648 if (s < q) continue; 7649 ftotpoints[q * 2] = fpoints[p]; 7650 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7651 ++q; 7652 } 7653 } 7654 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7655 } 7656 numFPoints = q; 7657 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7658 PetscInt fdof; 7659 7660 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7661 if (!dof) continue; 7662 for (f = 0; f < numFields; ++f) { 7663 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7664 foffsets[f + 1] += fdof; 7665 } 7666 numFIndices += dof; 7667 } 7668 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7669 7670 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7671 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7672 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7673 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7674 if (numFields) { 7675 const PetscInt **permsF[32] = {NULL}; 7676 const PetscInt **permsC[32] = {NULL}; 7677 7678 for (f = 0; f < numFields; f++) { 7679 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7680 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7681 } 7682 for (p = 0; p < numFPoints; p++) { 7683 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7684 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7685 } 7686 for (p = 0; p < numCPoints; p++) { 7687 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7688 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7689 } 7690 for (f = 0; f < numFields; f++) { 7691 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7692 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7693 } 7694 } else { 7695 const PetscInt **permsF = NULL; 7696 const PetscInt **permsC = NULL; 7697 7698 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7699 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7700 for (p = 0, off = 0; p < numFPoints; p++) { 7701 const PetscInt *perm = permsF ? permsF[p] : NULL; 7702 7703 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7704 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7705 } 7706 for (p = 0, off = 0; p < numCPoints; p++) { 7707 const PetscInt *perm = permsC ? permsC[p] : NULL; 7708 7709 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7710 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7711 } 7712 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7713 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7714 } 7715 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7716 /* TODO: flips */ 7717 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7718 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7719 if (ierr) { 7720 PetscMPIInt rank; 7721 7722 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7723 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7724 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7725 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7726 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7727 } 7728 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7729 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7730 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7731 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7732 PetscFunctionReturn(0); 7733 } 7734 7735 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) { 7736 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7737 PetscInt *cpoints = NULL; 7738 PetscInt foffsets[32], coffsets[32]; 7739 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7740 DMPolytopeType ct; 7741 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7742 7743 PetscFunctionBegin; 7744 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7745 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7746 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7747 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7748 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7749 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7750 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7751 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7752 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7753 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7754 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7755 PetscCheck(numFields <= 31, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7756 PetscCall(PetscArrayzero(foffsets, 32)); 7757 PetscCall(PetscArrayzero(coffsets, 32)); 7758 /* Column indices */ 7759 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7760 maxFPoints = numCPoints; 7761 /* Compress out points not in the section */ 7762 /* TODO: Squeeze out points with 0 dof as well */ 7763 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7764 for (p = 0, q = 0; p < numCPoints * 2; p += 2) { 7765 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7766 cpoints[q * 2] = cpoints[p]; 7767 cpoints[q * 2 + 1] = cpoints[p + 1]; 7768 ++q; 7769 } 7770 } 7771 numCPoints = q; 7772 for (p = 0, numCIndices = 0; p < numCPoints * 2; p += 2) { 7773 PetscInt fdof; 7774 7775 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7776 if (!dof) continue; 7777 for (f = 0; f < numFields; ++f) { 7778 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7779 coffsets[f + 1] += fdof; 7780 } 7781 numCIndices += dof; 7782 } 7783 for (f = 1; f < numFields; ++f) coffsets[f + 1] += coffsets[f]; 7784 /* Row indices */ 7785 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7786 { 7787 DMPlexTransform tr; 7788 DMPolytopeType *rct; 7789 PetscInt *rsize, *rcone, *rornt, Nt; 7790 7791 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7792 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7793 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7794 numSubcells = rsize[Nt - 1]; 7795 PetscCall(DMPlexTransformDestroy(&tr)); 7796 } 7797 PetscCall(DMGetWorkArray(dmf, maxFPoints * 2 * numSubcells, MPIU_INT, &ftotpoints)); 7798 for (r = 0, q = 0; r < numSubcells; ++r) { 7799 /* TODO Map from coarse to fine cells */ 7800 PetscCall(DMPlexGetTransitiveClosure(dmf, point * numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7801 /* Compress out points not in the section */ 7802 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7803 for (p = 0; p < numFPoints * 2; p += 2) { 7804 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7805 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7806 if (!dof) continue; 7807 for (s = 0; s < q; ++s) 7808 if (fpoints[p] == ftotpoints[s * 2]) break; 7809 if (s < q) continue; 7810 ftotpoints[q * 2] = fpoints[p]; 7811 ftotpoints[q * 2 + 1] = fpoints[p + 1]; 7812 ++q; 7813 } 7814 } 7815 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7816 } 7817 numFPoints = q; 7818 for (p = 0, numFIndices = 0; p < numFPoints * 2; p += 2) { 7819 PetscInt fdof; 7820 7821 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7822 if (!dof) continue; 7823 for (f = 0; f < numFields; ++f) { 7824 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7825 foffsets[f + 1] += fdof; 7826 } 7827 numFIndices += dof; 7828 } 7829 for (f = 1; f < numFields; ++f) foffsets[f + 1] += foffsets[f]; 7830 7831 PetscCheck(!numFields || foffsets[numFields] == numFIndices, PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7832 PetscCheck(!numFields || coffsets[numFields] == numCIndices, PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7833 if (numFields) { 7834 const PetscInt **permsF[32] = {NULL}; 7835 const PetscInt **permsC[32] = {NULL}; 7836 7837 for (f = 0; f < numFields; f++) { 7838 PetscCall(PetscSectionGetFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7839 PetscCall(PetscSectionGetFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7840 } 7841 for (p = 0; p < numFPoints; p++) { 7842 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7843 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7844 } 7845 for (p = 0; p < numCPoints; p++) { 7846 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7847 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7848 } 7849 for (f = 0; f < numFields; f++) { 7850 PetscCall(PetscSectionRestoreFieldPointSyms(fsection, f, numFPoints, ftotpoints, &permsF[f], NULL)); 7851 PetscCall(PetscSectionRestoreFieldPointSyms(csection, f, numCPoints, cpoints, &permsC[f], NULL)); 7852 } 7853 } else { 7854 const PetscInt **permsF = NULL; 7855 const PetscInt **permsC = NULL; 7856 7857 PetscCall(PetscSectionGetPointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7858 PetscCall(PetscSectionGetPointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7859 for (p = 0, off = 0; p < numFPoints; p++) { 7860 const PetscInt *perm = permsF ? permsF[p] : NULL; 7861 7862 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2 * p], &globalOff)); 7863 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7864 } 7865 for (p = 0, off = 0; p < numCPoints; p++) { 7866 const PetscInt *perm = permsC ? permsC[p] : NULL; 7867 7868 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2 * p], &globalOff)); 7869 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2 * p], globalOff < 0 ? -(globalOff + 1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7870 } 7871 PetscCall(PetscSectionRestorePointSyms(fsection, numFPoints, ftotpoints, &permsF, NULL)); 7872 PetscCall(PetscSectionRestorePointSyms(csection, numCPoints, cpoints, &permsC, NULL)); 7873 } 7874 PetscCall(DMRestoreWorkArray(dmf, numCPoints * 2 * 4, MPIU_INT, &ftotpoints)); 7875 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7876 PetscFunctionReturn(0); 7877 } 7878 7879 /*@C 7880 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7881 7882 Input Parameter: 7883 . dm - The DMPlex object 7884 7885 Output Parameter: 7886 . cellHeight - The height of a cell 7887 7888 Level: developer 7889 7890 .seealso `DMPlexSetVTKCellHeight()` 7891 @*/ 7892 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) { 7893 DM_Plex *mesh = (DM_Plex *)dm->data; 7894 7895 PetscFunctionBegin; 7896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7897 PetscValidIntPointer(cellHeight, 2); 7898 *cellHeight = mesh->vtkCellHeight; 7899 PetscFunctionReturn(0); 7900 } 7901 7902 /*@C 7903 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7904 7905 Input Parameters: 7906 + dm - The DMPlex object 7907 - cellHeight - The height of a cell 7908 7909 Level: developer 7910 7911 .seealso `DMPlexGetVTKCellHeight()` 7912 @*/ 7913 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) { 7914 DM_Plex *mesh = (DM_Plex *)dm->data; 7915 7916 PetscFunctionBegin; 7917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7918 mesh->vtkCellHeight = cellHeight; 7919 PetscFunctionReturn(0); 7920 } 7921 7922 /*@ 7923 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7924 7925 Input Parameter: 7926 . dm - The DMPlex object 7927 7928 Output Parameters: 7929 + gcStart - The first ghost cell, or NULL 7930 - gcEnd - The upper bound on ghost cells, or NULL 7931 7932 Level: advanced 7933 7934 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7935 @*/ 7936 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) { 7937 DMLabel ctLabel; 7938 7939 PetscFunctionBegin; 7940 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7941 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7942 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7943 // Reset label for fast lookup 7944 PetscCall(DMLabelMakeAllInvalid_Internal(ctLabel)); 7945 PetscFunctionReturn(0); 7946 } 7947 7948 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) { 7949 PetscSection section, globalSection; 7950 PetscInt *numbers, p; 7951 7952 PetscFunctionBegin; 7953 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 7954 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 7955 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 7956 for (p = pStart; p < pEnd; ++p) { PetscCall(PetscSectionSetDof(section, p, 1)); } 7957 PetscCall(PetscSectionSetUp(section)); 7958 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 7959 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 7960 for (p = pStart; p < pEnd; ++p) { 7961 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p - pStart])); 7962 if (numbers[p - pStart] < 0) numbers[p - pStart] -= shift; 7963 else numbers[p - pStart] += shift; 7964 } 7965 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 7966 if (globalSize) { 7967 PetscLayout layout; 7968 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject)dm), globalSection, &layout)); 7969 PetscCall(PetscLayoutGetSize(layout, globalSize)); 7970 PetscCall(PetscLayoutDestroy(&layout)); 7971 } 7972 PetscCall(PetscSectionDestroy(§ion)); 7973 PetscCall(PetscSectionDestroy(&globalSection)); 7974 PetscFunctionReturn(0); 7975 } 7976 7977 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) { 7978 PetscInt cellHeight, cStart, cEnd; 7979 7980 PetscFunctionBegin; 7981 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 7982 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 7983 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 7984 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 7985 PetscFunctionReturn(0); 7986 } 7987 7988 /*@ 7989 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 7990 7991 Input Parameter: 7992 . dm - The DMPlex object 7993 7994 Output Parameter: 7995 . globalCellNumbers - Global cell numbers for all cells on this process 7996 7997 Level: developer 7998 7999 .seealso `DMPlexGetVertexNumbering()` 8000 @*/ 8001 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) { 8002 DM_Plex *mesh = (DM_Plex *)dm->data; 8003 8004 PetscFunctionBegin; 8005 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8006 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8007 *globalCellNumbers = mesh->globalCellNumbers; 8008 PetscFunctionReturn(0); 8009 } 8010 8011 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) { 8012 PetscInt vStart, vEnd; 8013 8014 PetscFunctionBegin; 8015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8016 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8017 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8018 PetscFunctionReturn(0); 8019 } 8020 8021 /*@ 8022 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8023 8024 Input Parameter: 8025 . dm - The DMPlex object 8026 8027 Output Parameter: 8028 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8029 8030 Level: developer 8031 8032 .seealso `DMPlexGetCellNumbering()` 8033 @*/ 8034 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) { 8035 DM_Plex *mesh = (DM_Plex *)dm->data; 8036 8037 PetscFunctionBegin; 8038 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8039 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8040 *globalVertexNumbers = mesh->globalVertexNumbers; 8041 PetscFunctionReturn(0); 8042 } 8043 8044 /*@ 8045 DMPlexCreatePointNumbering - Create a global numbering for all points. 8046 8047 Collective on dm 8048 8049 Input Parameter: 8050 . dm - The DMPlex object 8051 8052 Output Parameter: 8053 . globalPointNumbers - Global numbers for all points on this process 8054 8055 Notes: 8056 8057 The point numbering IS is parallel, with local portion indexed by local points (see `DMGetLocalSection()`). The global 8058 points are taken as stratified, with each MPI rank owning a contiguous subset of each stratum. In the IS, owned points 8059 will have their non-negative value while points owned by different ranks will be involuted -(idx+1). As an example, 8060 consider a parallel mesh in which the first two elements and first two vertices are owned by rank 0. 8061 8062 The partitioned mesh is 8063 ``` 8064 (2)--0--(3)--1--(4) (1)--0--(2) 8065 ``` 8066 and its global numbering is 8067 ``` 8068 (3)--0--(4)--1--(5)--2--(6) 8069 ``` 8070 Then the global numbering is provided as 8071 ``` 8072 [0] Number of indices in set 5 8073 [0] 0 0 8074 [0] 1 1 8075 [0] 2 3 8076 [0] 3 4 8077 [0] 4 -6 8078 [1] Number of indices in set 3 8079 [1] 0 2 8080 [1] 1 5 8081 [1] 2 6 8082 ``` 8083 8084 Level: developer 8085 8086 .seealso `DMPlexGetCellNumbering()` 8087 @*/ 8088 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) { 8089 IS nums[4]; 8090 PetscInt depths[4], gdepths[4], starts[4]; 8091 PetscInt depth, d, shift = 0; 8092 8093 PetscFunctionBegin; 8094 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8095 PetscCall(DMPlexGetDepth(dm, &depth)); 8096 /* For unstratified meshes use dim instead of depth */ 8097 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8098 for (d = 0; d <= depth; ++d) { 8099 PetscInt end; 8100 8101 depths[d] = depth - d; 8102 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8103 if (!(starts[d] - end)) { starts[d] = depths[d] = -1; } 8104 } 8105 PetscCall(PetscSortIntWithArray(depth + 1, starts, depths)); 8106 PetscCall(MPIU_Allreduce(depths, gdepths, depth + 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 8107 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]); } 8108 for (d = 0; d <= depth; ++d) { 8109 PetscInt pStart, pEnd, gsize; 8110 8111 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8112 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8113 shift += gsize; 8114 } 8115 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)dm), depth + 1, nums, globalPointNumbers)); 8116 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8117 PetscFunctionReturn(0); 8118 } 8119 8120 /*@ 8121 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8122 8123 Input Parameter: 8124 . dm - The DMPlex object 8125 8126 Output Parameter: 8127 . ranks - The rank field 8128 8129 Options Database Keys: 8130 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8131 8132 Level: intermediate 8133 8134 .seealso: `DMView()` 8135 @*/ 8136 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) { 8137 DM rdm; 8138 PetscFE fe; 8139 PetscScalar *r; 8140 PetscMPIInt rank; 8141 DMPolytopeType ct; 8142 PetscInt dim, cStart, cEnd, c; 8143 PetscBool simplex; 8144 8145 PetscFunctionBeginUser; 8146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8147 PetscValidPointer(ranks, 2); 8148 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 8149 PetscCall(DMClone(dm, &rdm)); 8150 PetscCall(DMGetDimension(rdm, &dim)); 8151 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8152 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8153 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8154 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8155 PetscCall(PetscObjectSetName((PetscObject)fe, "rank")); 8156 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8157 PetscCall(PetscFEDestroy(&fe)); 8158 PetscCall(DMCreateDS(rdm)); 8159 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8160 PetscCall(PetscObjectSetName((PetscObject)*ranks, "partition")); 8161 PetscCall(VecGetArray(*ranks, &r)); 8162 for (c = cStart; c < cEnd; ++c) { 8163 PetscScalar *lr; 8164 8165 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8166 if (lr) *lr = rank; 8167 } 8168 PetscCall(VecRestoreArray(*ranks, &r)); 8169 PetscCall(DMDestroy(&rdm)); 8170 PetscFunctionReturn(0); 8171 } 8172 8173 /*@ 8174 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8175 8176 Input Parameters: 8177 + dm - The DMPlex 8178 - label - The DMLabel 8179 8180 Output Parameter: 8181 . val - The label value field 8182 8183 Options Database Keys: 8184 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8185 8186 Level: intermediate 8187 8188 .seealso: `DMView()` 8189 @*/ 8190 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) { 8191 DM rdm; 8192 PetscFE fe; 8193 PetscScalar *v; 8194 PetscInt dim, cStart, cEnd, c; 8195 8196 PetscFunctionBeginUser; 8197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8198 PetscValidPointer(label, 2); 8199 PetscValidPointer(val, 3); 8200 PetscCall(DMClone(dm, &rdm)); 8201 PetscCall(DMGetDimension(rdm, &dim)); 8202 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject)rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8203 PetscCall(PetscObjectSetName((PetscObject)fe, "label_value")); 8204 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject)fe)); 8205 PetscCall(PetscFEDestroy(&fe)); 8206 PetscCall(DMCreateDS(rdm)); 8207 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8208 PetscCall(DMCreateGlobalVector(rdm, val)); 8209 PetscCall(PetscObjectSetName((PetscObject)*val, "label_value")); 8210 PetscCall(VecGetArray(*val, &v)); 8211 for (c = cStart; c < cEnd; ++c) { 8212 PetscScalar *lv; 8213 PetscInt cval; 8214 8215 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8216 PetscCall(DMLabelGetValue(label, c, &cval)); 8217 *lv = cval; 8218 } 8219 PetscCall(VecRestoreArray(*val, &v)); 8220 PetscCall(DMDestroy(&rdm)); 8221 PetscFunctionReturn(0); 8222 } 8223 8224 /*@ 8225 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8226 8227 Input Parameter: 8228 . dm - The DMPlex object 8229 8230 Notes: 8231 This is a useful diagnostic when creating meshes programmatically. 8232 8233 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8234 8235 Level: developer 8236 8237 .seealso: `DMCreate()`, `DMSetFromOptions()` 8238 @*/ 8239 PetscErrorCode DMPlexCheckSymmetry(DM dm) { 8240 PetscSection coneSection, supportSection; 8241 const PetscInt *cone, *support; 8242 PetscInt coneSize, c, supportSize, s; 8243 PetscInt pStart, pEnd, p, pp, csize, ssize; 8244 PetscBool storagecheck = PETSC_TRUE; 8245 8246 PetscFunctionBegin; 8247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8248 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8249 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8250 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8251 /* Check that point p is found in the support of its cone points, and vice versa */ 8252 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8253 for (p = pStart; p < pEnd; ++p) { 8254 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8255 PetscCall(DMPlexGetCone(dm, p, &cone)); 8256 for (c = 0; c < coneSize; ++c) { 8257 PetscBool dup = PETSC_FALSE; 8258 PetscInt d; 8259 for (d = c - 1; d >= 0; --d) { 8260 if (cone[c] == cone[d]) { 8261 dup = PETSC_TRUE; 8262 break; 8263 } 8264 } 8265 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8266 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8267 for (s = 0; s < supportSize; ++s) { 8268 if (support[s] == p) break; 8269 } 8270 if ((s >= supportSize) || (dup && (support[s + 1] != p))) { 8271 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8272 for (s = 0; s < coneSize; ++s) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); } 8273 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8274 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8275 for (s = 0; s < supportSize; ++s) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); } 8276 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8277 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]); 8278 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8279 } 8280 } 8281 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8282 if (p != pp) { 8283 storagecheck = PETSC_FALSE; 8284 continue; 8285 } 8286 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8287 PetscCall(DMPlexGetSupport(dm, p, &support)); 8288 for (s = 0; s < supportSize; ++s) { 8289 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8290 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8291 for (c = 0; c < coneSize; ++c) { 8292 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8293 if (cone[c] != pp) { 8294 c = 0; 8295 break; 8296 } 8297 if (cone[c] == p) break; 8298 } 8299 if (c >= coneSize) { 8300 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8301 for (c = 0; c < supportSize; ++c) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); } 8302 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8303 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8304 for (c = 0; c < coneSize; ++c) { PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); } 8305 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8306 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8307 } 8308 } 8309 } 8310 if (storagecheck) { 8311 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8312 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8313 PetscCheck(csize == ssize, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8314 } 8315 PetscFunctionReturn(0); 8316 } 8317 8318 /* 8319 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. 8320 */ 8321 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) { 8322 DMPolytopeType cct; 8323 PetscInt ptpoints[4]; 8324 const PetscInt *cone, *ccone, *ptcone; 8325 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8326 8327 PetscFunctionBegin; 8328 *unsplit = 0; 8329 switch (ct) { 8330 case DM_POLYTOPE_POINT_PRISM_TENSOR: ptpoints[npt++] = c; break; 8331 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8332 PetscCall(DMPlexGetCone(dm, c, &cone)); 8333 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8334 for (cp = 0; cp < coneSize; ++cp) { 8335 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8336 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8337 } 8338 break; 8339 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8340 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8341 PetscCall(DMPlexGetCone(dm, c, &cone)); 8342 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8343 for (cp = 0; cp < coneSize; ++cp) { 8344 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8345 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8346 for (ccp = 0; ccp < cconeSize; ++ccp) { 8347 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8348 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8349 PetscInt p; 8350 for (p = 0; p < npt; ++p) 8351 if (ptpoints[p] == ccone[ccp]) break; 8352 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8353 } 8354 } 8355 } 8356 break; 8357 default: break; 8358 } 8359 for (pt = 0; pt < npt; ++pt) { 8360 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8361 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8362 } 8363 PetscFunctionReturn(0); 8364 } 8365 8366 /*@ 8367 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8368 8369 Input Parameters: 8370 + dm - The DMPlex object 8371 - cellHeight - Normally 0 8372 8373 Notes: 8374 This is a useful diagnostic when creating meshes programmatically. 8375 Currently applicable only to homogeneous simplex or tensor meshes. 8376 8377 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8378 8379 Level: developer 8380 8381 .seealso: `DMCreate()`, `DMSetFromOptions()` 8382 @*/ 8383 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) { 8384 DMPlexInterpolatedFlag interp; 8385 DMPolytopeType ct; 8386 PetscInt vStart, vEnd, cStart, cEnd, c; 8387 8388 PetscFunctionBegin; 8389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8390 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8391 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8392 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8393 for (c = cStart; c < cEnd; ++c) { 8394 PetscInt *closure = NULL; 8395 PetscInt coneSize, closureSize, cl, Nv = 0; 8396 8397 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8398 PetscCheck((PetscInt)ct >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8399 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8400 if (interp == DMPLEX_INTERPOLATED_FULL) { 8401 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8402 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)); 8403 } 8404 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8405 for (cl = 0; cl < closureSize * 2; cl += 2) { 8406 const PetscInt p = closure[cl]; 8407 if ((p >= vStart) && (p < vEnd)) ++Nv; 8408 } 8409 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8410 /* Special Case: Tensor faces with identified vertices */ 8411 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8412 PetscInt unsplit; 8413 8414 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8415 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8416 } 8417 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)); 8418 } 8419 PetscFunctionReturn(0); 8420 } 8421 8422 /*@ 8423 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8424 8425 Collective 8426 8427 Input Parameters: 8428 + dm - The DMPlex object 8429 - cellHeight - Normally 0 8430 8431 Notes: 8432 This is a useful diagnostic when creating meshes programmatically. 8433 This routine is only relevant for meshes that are fully interpolated across all ranks. 8434 It will error out if a partially interpolated mesh is given on some rank. 8435 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8436 8437 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8438 8439 Level: developer 8440 8441 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8442 @*/ 8443 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) { 8444 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8445 DMPlexInterpolatedFlag interpEnum; 8446 8447 PetscFunctionBegin; 8448 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8449 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8450 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8451 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8452 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8453 PetscFunctionReturn(0); 8454 } 8455 8456 PetscCall(DMGetDimension(dm, &dim)); 8457 PetscCall(DMPlexGetDepth(dm, &depth)); 8458 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8459 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8460 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8461 for (c = cStart; c < cEnd; ++c) { 8462 const PetscInt *cone, *ornt, *faceSizes, *faces; 8463 const DMPolytopeType *faceTypes; 8464 DMPolytopeType ct; 8465 PetscInt numFaces, coneSize, f; 8466 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8467 8468 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8469 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8470 if (unsplit) continue; 8471 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8472 PetscCall(DMPlexGetCone(dm, c, &cone)); 8473 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8474 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8475 for (cl = 0; cl < closureSize * 2; cl += 2) { 8476 const PetscInt p = closure[cl]; 8477 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8478 } 8479 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8480 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); 8481 for (f = 0; f < numFaces; ++f) { 8482 DMPolytopeType fct; 8483 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8484 8485 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8486 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8487 for (cl = 0; cl < fclosureSize * 2; cl += 2) { 8488 const PetscInt p = fclosure[cl]; 8489 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8490 } 8491 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]); 8492 for (v = 0; v < fnumCorners; ++v) { 8493 if (fclosure[v] != faces[fOff + v]) { 8494 PetscInt v1; 8495 8496 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8497 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8498 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8499 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff + v1])); 8500 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8501 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]); 8502 } 8503 } 8504 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8505 fOff += faceSizes[f]; 8506 } 8507 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8508 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8509 } 8510 } 8511 PetscFunctionReturn(0); 8512 } 8513 8514 /*@ 8515 DMPlexCheckGeometry - Check the geometry of mesh cells 8516 8517 Input Parameter: 8518 . dm - The DMPlex object 8519 8520 Notes: 8521 This is a useful diagnostic when creating meshes programmatically. 8522 8523 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8524 8525 Level: developer 8526 8527 .seealso: `DMCreate()`, `DMSetFromOptions()` 8528 @*/ 8529 PetscErrorCode DMPlexCheckGeometry(DM dm) { 8530 Vec coordinates; 8531 PetscReal detJ, J[9], refVol = 1.0; 8532 PetscReal vol; 8533 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8534 8535 PetscFunctionBegin; 8536 PetscCall(DMGetDimension(dm, &dim)); 8537 PetscCall(DMGetCoordinateDim(dm, &dE)); 8538 if (dim != dE) PetscFunctionReturn(0); 8539 PetscCall(DMPlexGetDepth(dm, &depth)); 8540 for (d = 0; d < dim; ++d) refVol *= 2.0; 8541 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8542 /* Make sure local coordinates are created, because that step is collective */ 8543 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8544 for (c = cStart; c < cEnd; ++c) { 8545 DMPolytopeType ct; 8546 PetscInt unsplit; 8547 PetscBool ignoreZeroVol = PETSC_FALSE; 8548 8549 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8550 switch (ct) { 8551 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8552 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8553 case DM_POLYTOPE_QUAD_PRISM_TENSOR: ignoreZeroVol = PETSC_TRUE; break; 8554 default: break; 8555 } 8556 switch (ct) { 8557 case DM_POLYTOPE_TRI_PRISM: 8558 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8559 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8560 case DM_POLYTOPE_PYRAMID: continue; 8561 default: break; 8562 } 8563 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8564 if (unsplit) continue; 8565 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8566 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); 8567 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ * refVol))); 8568 /* This should work with periodicity since DG coordinates should be used */ 8569 if (depth > 1) { 8570 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8571 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); 8572 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double)vol)); 8573 } 8574 } 8575 PetscFunctionReturn(0); 8576 } 8577 8578 /*@ 8579 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8580 8581 Collective 8582 8583 Input Parameters: 8584 + dm - The DMPlex object 8585 - pointSF - The Point SF, or NULL for Point SF attached to DM 8586 8587 Notes: 8588 This is mainly intended for debugging/testing purposes. 8589 8590 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8591 8592 Level: developer 8593 8594 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8595 @*/ 8596 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) { 8597 PetscInt l, nleaves, nroots, overlap; 8598 const PetscInt *locals; 8599 const PetscSFNode *remotes; 8600 PetscBool distributed; 8601 MPI_Comm comm; 8602 PetscMPIInt rank; 8603 8604 PetscFunctionBegin; 8605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8606 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8607 else pointSF = dm->sf; 8608 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8609 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8610 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8611 { 8612 PetscMPIInt mpiFlag; 8613 8614 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF), &mpiFlag)); 8615 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)", mpiFlag); 8616 } 8617 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8618 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8619 if (!distributed) { 8620 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); 8621 PetscFunctionReturn(0); 8622 } 8623 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); 8624 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8625 8626 /* Check SF graph is compatible with DMPlex chart */ 8627 { 8628 PetscInt pStart, pEnd, maxLeaf; 8629 8630 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8631 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8632 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd - pStart, nroots); 8633 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8634 } 8635 8636 /* Check Point SF has no local points referenced */ 8637 for (l = 0; l < nleaves; l++) { 8638 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); 8639 } 8640 8641 /* Check there are no cells in interface */ 8642 if (!overlap) { 8643 PetscInt cellHeight, cStart, cEnd; 8644 8645 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8646 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8647 for (l = 0; l < nleaves; ++l) { 8648 const PetscInt point = locals ? locals[l] : l; 8649 8650 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8651 } 8652 } 8653 8654 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8655 { 8656 const PetscInt *rootdegree; 8657 8658 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8659 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8660 for (l = 0; l < nleaves; ++l) { 8661 const PetscInt point = locals ? locals[l] : l; 8662 const PetscInt *cone; 8663 PetscInt coneSize, c, idx; 8664 8665 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8666 PetscCall(DMPlexGetCone(dm, point, &cone)); 8667 for (c = 0; c < coneSize; ++c) { 8668 if (!rootdegree[cone[c]]) { 8669 if (locals) { 8670 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8671 } else { 8672 idx = (cone[c] < nleaves) ? cone[c] : -1; 8673 } 8674 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8675 } 8676 } 8677 } 8678 } 8679 PetscFunctionReturn(0); 8680 } 8681 8682 /*@ 8683 DMPlexCheck - Perform various checks of Plex sanity 8684 8685 Input Parameter: 8686 . dm - The DMPlex object 8687 8688 Notes: 8689 This is a useful diagnostic when creating meshes programmatically. 8690 8691 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8692 8693 Currently does not include DMPlexCheckCellShape(). 8694 8695 Level: developer 8696 8697 .seealso: DMCreate(), DMSetFromOptions() 8698 @*/ 8699 PetscErrorCode DMPlexCheck(DM dm) { 8700 PetscInt cellHeight; 8701 8702 PetscFunctionBegin; 8703 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8704 PetscCall(DMPlexCheckSymmetry(dm)); 8705 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8706 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8707 PetscCall(DMPlexCheckGeometry(dm)); 8708 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8709 PetscCall(DMPlexCheckInterfaceCones(dm)); 8710 PetscFunctionReturn(0); 8711 } 8712 8713 typedef struct cell_stats { 8714 PetscReal min, max, sum, squaresum; 8715 PetscInt count; 8716 } cell_stats_t; 8717 8718 static void MPIAPI cell_stats_reduce(void *a, void *b, int *len, MPI_Datatype *datatype) { 8719 PetscInt i, N = *len; 8720 8721 for (i = 0; i < N; i++) { 8722 cell_stats_t *A = (cell_stats_t *)a; 8723 cell_stats_t *B = (cell_stats_t *)b; 8724 8725 B->min = PetscMin(A->min, B->min); 8726 B->max = PetscMax(A->max, B->max); 8727 B->sum += A->sum; 8728 B->squaresum += A->squaresum; 8729 B->count += A->count; 8730 } 8731 } 8732 8733 /*@ 8734 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8735 8736 Collective on dm 8737 8738 Input Parameters: 8739 + dm - The DMPlex object 8740 . output - If true, statistics will be displayed on stdout 8741 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8742 8743 Notes: 8744 This is mainly intended for debugging/testing purposes. 8745 8746 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8747 8748 Level: developer 8749 8750 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8751 @*/ 8752 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) { 8753 DM dmCoarse; 8754 cell_stats_t stats, globalStats; 8755 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8756 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8757 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8758 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8759 PetscMPIInt rank, size; 8760 8761 PetscFunctionBegin; 8762 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8763 stats.min = PETSC_MAX_REAL; 8764 stats.max = PETSC_MIN_REAL; 8765 stats.sum = stats.squaresum = 0.; 8766 stats.count = 0; 8767 8768 PetscCallMPI(MPI_Comm_size(comm, &size)); 8769 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8770 PetscCall(DMGetCoordinateDim(dm, &cdim)); 8771 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8772 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 8773 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 8774 for (c = cStart; c < cEnd; c++) { 8775 PetscInt i; 8776 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8777 8778 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, c, NULL, J, invJ, &detJ)); 8779 PetscCheck(detJ >= 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8780 for (i = 0; i < PetscSqr(cdim); ++i) { 8781 frobJ += J[i] * J[i]; 8782 frobInvJ += invJ[i] * invJ[i]; 8783 } 8784 cond2 = frobJ * frobInvJ; 8785 cond = PetscSqrtReal(cond2); 8786 8787 stats.min = PetscMin(stats.min, cond); 8788 stats.max = PetscMax(stats.max, cond); 8789 stats.sum += cond; 8790 stats.squaresum += cond2; 8791 stats.count++; 8792 if (output && cond > limit) { 8793 PetscSection coordSection; 8794 Vec coordsLocal; 8795 PetscScalar *coords = NULL; 8796 PetscInt Nv, d, clSize, cl, *closure = NULL; 8797 8798 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8799 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8800 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8801 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double)cond)); 8802 for (i = 0; i < Nv / cdim; ++i) { 8803 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8804 for (d = 0; d < cdim; ++d) { 8805 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8806 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double)PetscRealPart(coords[i * cdim + d]))); 8807 } 8808 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8809 } 8810 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8811 for (cl = 0; cl < clSize * 2; cl += 2) { 8812 const PetscInt edge = closure[cl]; 8813 8814 if ((edge >= eStart) && (edge < eEnd)) { 8815 PetscReal len; 8816 8817 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8818 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double)len)); 8819 } 8820 } 8821 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8822 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8823 } 8824 } 8825 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8826 8827 if (size > 1) { 8828 PetscMPIInt blockLengths[2] = {4, 1}; 8829 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t, min), offsetof(cell_stats_t, count)}; 8830 MPI_Datatype blockTypes[2] = {MPIU_REAL, MPIU_INT}, statType; 8831 MPI_Op statReduce; 8832 8833 PetscCallMPI(MPI_Type_create_struct(2, blockLengths, blockOffsets, blockTypes, &statType)); 8834 PetscCallMPI(MPI_Type_commit(&statType)); 8835 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8836 PetscCallMPI(MPI_Reduce(&stats, &globalStats, 1, statType, statReduce, 0, comm)); 8837 PetscCallMPI(MPI_Op_free(&statReduce)); 8838 PetscCallMPI(MPI_Type_free(&statType)); 8839 } else { 8840 PetscCall(PetscArraycpy(&globalStats, &stats, 1)); 8841 } 8842 if (rank == 0) { 8843 count = globalStats.count; 8844 min = globalStats.min; 8845 max = globalStats.max; 8846 mean = globalStats.sum / globalStats.count; 8847 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1), 0)) : 0.0; 8848 } 8849 8850 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)); } 8851 PetscCall(PetscFree2(J, invJ)); 8852 8853 PetscCall(DMGetCoarseDM(dm, &dmCoarse)); 8854 if (dmCoarse) { 8855 PetscBool isplex; 8856 8857 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse, DMPLEX, &isplex)); 8858 if (isplex) PetscCall(DMPlexCheckCellShape(dmCoarse, output, condLimit)); 8859 } 8860 PetscFunctionReturn(0); 8861 } 8862 8863 /*@ 8864 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8865 orthogonal quality below given tolerance. 8866 8867 Collective on dm 8868 8869 Input Parameters: 8870 + dm - The DMPlex object 8871 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8872 - atol - [0, 1] Absolute tolerance for tagging cells. 8873 8874 Output Parameters: 8875 + OrthQual - Vec containing orthogonal quality per cell 8876 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8877 8878 Options Database Keys: 8879 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8880 supported. 8881 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8882 8883 Notes: 8884 Orthogonal quality is given by the following formula: 8885 8886 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8887 8888 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 8889 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8890 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8891 calculating the cosine of the angle between these vectors. 8892 8893 Orthogonal quality ranges from 1 (best) to 0 (worst). 8894 8895 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8896 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8897 8898 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8899 8900 Level: intermediate 8901 8902 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8903 @*/ 8904 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) { 8905 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8906 PetscInt *idx; 8907 PetscScalar *oqVals; 8908 const PetscScalar *cellGeomArr, *faceGeomArr; 8909 PetscReal *ci, *fi, *Ai; 8910 MPI_Comm comm; 8911 Vec cellgeom, facegeom; 8912 DM dmFace, dmCell; 8913 IS glob; 8914 ISLocalToGlobalMapping ltog; 8915 PetscViewer vwr; 8916 8917 PetscFunctionBegin; 8918 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8919 if (fv) { PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); } 8920 PetscValidPointer(OrthQual, 4); 8921 PetscCheck(atol >= 0.0 && atol <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g not in [0,1]", (double)atol); 8922 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8923 PetscCall(DMGetDimension(dm, &nc)); 8924 PetscCheck(nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8925 { 8926 DMPlexInterpolatedFlag interpFlag; 8927 8928 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8929 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8930 PetscMPIInt rank; 8931 8932 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8933 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8934 } 8935 } 8936 if (OrthQualLabel) { 8937 PetscValidPointer(OrthQualLabel, 5); 8938 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8939 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8940 } else { 8941 *OrthQualLabel = NULL; 8942 } 8943 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8944 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8945 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8946 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8947 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8948 PetscCall(VecCreate(comm, OrthQual)); 8949 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8950 PetscCall(VecSetSizes(*OrthQual, cEnd - cStart, PETSC_DETERMINE)); 8951 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8952 PetscCall(VecSetUp(*OrthQual)); 8953 PetscCall(ISDestroy(&glob)); 8954 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8955 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8956 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8957 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8958 PetscCall(VecGetDM(cellgeom, &dmCell)); 8959 PetscCall(VecGetDM(facegeom, &dmFace)); 8960 PetscCall(PetscMalloc5(cEnd - cStart, &idx, cEnd - cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8961 for (cell = cStart; cell < cEnd; cellIter++, cell++) { 8962 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8963 PetscInt cellarr[2], *adj = NULL; 8964 PetscScalar *cArr, *fArr; 8965 PetscReal minvalc = 1.0, minvalf = 1.0; 8966 PetscFVCellGeom *cg; 8967 8968 idx[cellIter] = cell - cStart; 8969 cellarr[0] = cell; 8970 /* Make indexing into cellGeom easier */ 8971 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8972 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8973 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8974 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8975 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++, cellneigh++) { 8976 PetscInt i; 8977 const PetscInt neigh = adj[cellneigh]; 8978 PetscReal normci = 0, normfi = 0, normai = 0; 8979 PetscFVCellGeom *cgneigh; 8980 PetscFVFaceGeom *fg; 8981 8982 /* Don't count ourselves in the neighbor list */ 8983 if (neigh == cell) continue; 8984 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 8985 cellarr[1] = neigh; 8986 { 8987 PetscInt numcovpts; 8988 const PetscInt *covpts; 8989 8990 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8991 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 8992 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8993 } 8994 8995 /* Compute c_i, f_i and their norms */ 8996 for (i = 0; i < nc; i++) { 8997 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 8998 fi[i] = fg->centroid[i] - cg->centroid[i]; 8999 Ai[i] = fg->normal[i]; 9000 normci += PetscPowReal(ci[i], 2); 9001 normfi += PetscPowReal(fi[i], 2); 9002 normai += PetscPowReal(Ai[i], 2); 9003 } 9004 normci = PetscSqrtReal(normci); 9005 normfi = PetscSqrtReal(normfi); 9006 normai = PetscSqrtReal(normai); 9007 9008 /* Normalize and compute for each face-cell-normal pair */ 9009 for (i = 0; i < nc; i++) { 9010 ci[i] = ci[i] / normci; 9011 fi[i] = fi[i] / normfi; 9012 Ai[i] = Ai[i] / normai; 9013 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9014 cArr[cellneighiter] += PetscAbs(Ai[i] * ci[i]); 9015 fArr[cellneighiter] += PetscAbs(Ai[i] * fi[i]); 9016 } 9017 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { minvalc = PetscRealPart(cArr[cellneighiter]); } 9018 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { minvalf = PetscRealPart(fArr[cellneighiter]); } 9019 } 9020 PetscCall(PetscFree(adj)); 9021 PetscCall(PetscFree2(cArr, fArr)); 9022 /* Defer to cell if they're equal */ 9023 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9024 if (OrthQualLabel) { 9025 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9026 } 9027 } 9028 PetscCall(VecSetValuesLocal(*OrthQual, cEnd - cStart, idx, oqVals, INSERT_VALUES)); 9029 PetscCall(VecAssemblyBegin(*OrthQual)); 9030 PetscCall(VecAssemblyEnd(*OrthQual)); 9031 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9032 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9033 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9034 if (OrthQualLabel) { 9035 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9036 } 9037 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9038 PetscCall(PetscViewerDestroy(&vwr)); 9039 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9040 PetscFunctionReturn(0); 9041 } 9042 9043 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9044 * interpolator construction */ 9045 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) { 9046 PetscSection section, newSection, gsection; 9047 PetscSF sf; 9048 PetscBool hasConstraints, ghasConstraints; 9049 9050 PetscFunctionBegin; 9051 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9052 PetscValidPointer(odm, 2); 9053 PetscCall(DMGetLocalSection(dm, §ion)); 9054 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9055 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 9056 if (!ghasConstraints) { 9057 PetscCall(PetscObjectReference((PetscObject)dm)); 9058 *odm = dm; 9059 PetscFunctionReturn(0); 9060 } 9061 PetscCall(DMClone(dm, odm)); 9062 PetscCall(DMCopyFields(dm, *odm)); 9063 PetscCall(DMGetLocalSection(*odm, &newSection)); 9064 PetscCall(DMGetPointSF(*odm, &sf)); 9065 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9066 PetscCall(DMSetGlobalSection(*odm, gsection)); 9067 PetscCall(PetscSectionDestroy(&gsection)); 9068 PetscFunctionReturn(0); 9069 } 9070 9071 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) { 9072 DM dmco, dmfo; 9073 Mat interpo; 9074 Vec rscale; 9075 Vec cglobalo, clocal; 9076 Vec fglobal, fglobalo, flocal; 9077 PetscBool regular; 9078 9079 PetscFunctionBegin; 9080 PetscCall(DMGetFullDM(dmc, &dmco)); 9081 PetscCall(DMGetFullDM(dmf, &dmfo)); 9082 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9083 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9084 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9085 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9086 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9087 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9088 PetscCall(VecSet(cglobalo, 0.)); 9089 PetscCall(VecSet(clocal, 0.)); 9090 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9091 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9092 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9093 PetscCall(VecSet(fglobal, 0.)); 9094 PetscCall(VecSet(fglobalo, 0.)); 9095 PetscCall(VecSet(flocal, 0.)); 9096 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9097 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9098 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9099 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9100 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9101 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9102 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9103 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9104 *shift = fglobal; 9105 PetscCall(VecDestroy(&flocal)); 9106 PetscCall(VecDestroy(&fglobalo)); 9107 PetscCall(VecDestroy(&clocal)); 9108 PetscCall(VecDestroy(&cglobalo)); 9109 PetscCall(VecDestroy(&rscale)); 9110 PetscCall(MatDestroy(&interpo)); 9111 PetscCall(DMDestroy(&dmfo)); 9112 PetscCall(DMDestroy(&dmco)); 9113 PetscFunctionReturn(0); 9114 } 9115 9116 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) { 9117 PetscObject shifto; 9118 Vec shift; 9119 9120 PetscFunctionBegin; 9121 if (!interp) { 9122 Vec rscale; 9123 9124 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9125 PetscCall(VecDestroy(&rscale)); 9126 } else { 9127 PetscCall(PetscObjectReference((PetscObject)interp)); 9128 } 9129 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9130 if (!shifto) { 9131 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9132 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject)shift)); 9133 shifto = (PetscObject)shift; 9134 PetscCall(VecDestroy(&shift)); 9135 } 9136 shift = (Vec)shifto; 9137 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9138 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9139 PetscCall(MatDestroy(&interp)); 9140 PetscFunctionReturn(0); 9141 } 9142 9143 /* Pointwise interpolation 9144 Just code FEM for now 9145 u^f = I u^c 9146 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9147 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9148 I_{ij} = psi^f_i phi^c_j 9149 */ 9150 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) { 9151 PetscSection gsc, gsf; 9152 PetscInt m, n; 9153 void *ctx; 9154 DM cdm; 9155 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9156 9157 PetscFunctionBegin; 9158 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9159 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9160 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9161 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9162 9163 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9164 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), interpolation)); 9165 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9166 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9167 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9168 9169 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9170 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9171 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9172 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9173 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9174 if (scaling) { 9175 /* Use naive scaling */ 9176 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9177 } 9178 PetscFunctionReturn(0); 9179 } 9180 9181 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) { 9182 VecScatter ctx; 9183 9184 PetscFunctionBegin; 9185 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9186 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9187 PetscCall(VecScatterDestroy(&ctx)); 9188 PetscFunctionReturn(0); 9189 } 9190 9191 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[]) { 9192 const PetscInt Nc = uOff[1] - uOff[0]; 9193 PetscInt c; 9194 for (c = 0; c < Nc; ++c) g0[c * Nc + c] = 1.0; 9195 } 9196 9197 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) { 9198 DM dmc; 9199 PetscDS ds; 9200 Vec ones, locmass; 9201 IS cellIS; 9202 PetscFormKey key; 9203 PetscInt depth; 9204 9205 PetscFunctionBegin; 9206 PetscCall(DMClone(dm, &dmc)); 9207 PetscCall(DMCopyDisc(dm, dmc)); 9208 PetscCall(DMGetDS(dmc, &ds)); 9209 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9210 PetscCall(DMCreateGlobalVector(dmc, mass)); 9211 PetscCall(DMGetLocalVector(dmc, &ones)); 9212 PetscCall(DMGetLocalVector(dmc, &locmass)); 9213 PetscCall(DMPlexGetDepth(dmc, &depth)); 9214 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9215 PetscCall(VecSet(locmass, 0.0)); 9216 PetscCall(VecSet(ones, 1.0)); 9217 key.label = NULL; 9218 key.value = 0; 9219 key.field = 0; 9220 key.part = 0; 9221 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9222 PetscCall(ISDestroy(&cellIS)); 9223 PetscCall(VecSet(*mass, 0.0)); 9224 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9225 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9226 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9227 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9228 PetscCall(DMDestroy(&dmc)); 9229 PetscFunctionReturn(0); 9230 } 9231 9232 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) { 9233 PetscSection gsc, gsf; 9234 PetscInt m, n; 9235 void *ctx; 9236 DM cdm; 9237 PetscBool regular; 9238 9239 PetscFunctionBegin; 9240 if (dmFine == dmCoarse) { 9241 DM dmc; 9242 PetscDS ds; 9243 PetscWeakForm wf; 9244 Vec u; 9245 IS cellIS; 9246 PetscFormKey key; 9247 PetscInt depth; 9248 9249 PetscCall(DMClone(dmFine, &dmc)); 9250 PetscCall(DMCopyDisc(dmFine, dmc)); 9251 PetscCall(DMGetDS(dmc, &ds)); 9252 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9253 PetscCall(PetscWeakFormClear(wf)); 9254 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9255 PetscCall(DMCreateMatrix(dmc, mass)); 9256 PetscCall(DMGetLocalVector(dmc, &u)); 9257 PetscCall(DMPlexGetDepth(dmc, &depth)); 9258 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9259 PetscCall(MatZeroEntries(*mass)); 9260 key.label = NULL; 9261 key.value = 0; 9262 key.field = 0; 9263 key.part = 0; 9264 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9265 PetscCall(ISDestroy(&cellIS)); 9266 PetscCall(DMRestoreLocalVector(dmc, &u)); 9267 PetscCall(DMDestroy(&dmc)); 9268 } else { 9269 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9270 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9271 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9272 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9273 9274 PetscCall(MatCreate(PetscObjectComm((PetscObject)dmCoarse), mass)); 9275 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9276 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9277 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9278 9279 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9280 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9281 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9282 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9283 } 9284 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9285 PetscFunctionReturn(0); 9286 } 9287 9288 /*@ 9289 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9290 9291 Input Parameter: 9292 . dm - The DMPlex object 9293 9294 Output Parameter: 9295 . regular - The flag 9296 9297 Level: intermediate 9298 9299 .seealso: `DMPlexSetRegularRefinement()` 9300 @*/ 9301 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) { 9302 PetscFunctionBegin; 9303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9304 PetscValidBoolPointer(regular, 2); 9305 *regular = ((DM_Plex *)dm->data)->regularRefinement; 9306 PetscFunctionReturn(0); 9307 } 9308 9309 /*@ 9310 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9311 9312 Input Parameters: 9313 + dm - The DMPlex object 9314 - regular - The flag 9315 9316 Level: intermediate 9317 9318 .seealso: `DMPlexGetRegularRefinement()` 9319 @*/ 9320 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) { 9321 PetscFunctionBegin; 9322 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9323 ((DM_Plex *)dm->data)->regularRefinement = regular; 9324 PetscFunctionReturn(0); 9325 } 9326 9327 /* anchors */ 9328 /*@ 9329 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9330 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9331 9332 not collective 9333 9334 Input Parameter: 9335 . dm - The DMPlex object 9336 9337 Output Parameters: 9338 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9339 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9340 9341 Level: intermediate 9342 9343 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9344 @*/ 9345 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) { 9346 DM_Plex *plex = (DM_Plex *)dm->data; 9347 9348 PetscFunctionBegin; 9349 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9350 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9351 if (anchorSection) *anchorSection = plex->anchorSection; 9352 if (anchorIS) *anchorIS = plex->anchorIS; 9353 PetscFunctionReturn(0); 9354 } 9355 9356 /*@ 9357 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9358 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9359 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9360 9361 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9362 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9363 9364 collective on dm 9365 9366 Input Parameters: 9367 + dm - The DMPlex object 9368 . 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). 9369 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9370 9371 The reference counts of anchorSection and anchorIS are incremented. 9372 9373 Level: intermediate 9374 9375 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9376 @*/ 9377 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) { 9378 DM_Plex *plex = (DM_Plex *)dm->data; 9379 PetscMPIInt result; 9380 9381 PetscFunctionBegin; 9382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9383 if (anchorSection) { 9384 PetscValidHeaderSpecific(anchorSection, PETSC_SECTION_CLASSID, 2); 9385 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorSection), &result)); 9386 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor section must have local communicator"); 9387 } 9388 if (anchorIS) { 9389 PetscValidHeaderSpecific(anchorIS, IS_CLASSID, 3); 9390 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)anchorIS), &result)); 9391 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "anchor IS must have local communicator"); 9392 } 9393 9394 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9395 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9396 plex->anchorSection = anchorSection; 9397 9398 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9399 PetscCall(ISDestroy(&plex->anchorIS)); 9400 plex->anchorIS = anchorIS; 9401 9402 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9403 PetscInt size, a, pStart, pEnd; 9404 const PetscInt *anchors; 9405 9406 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9407 PetscCall(ISGetLocalSize(anchorIS, &size)); 9408 PetscCall(ISGetIndices(anchorIS, &anchors)); 9409 for (a = 0; a < size; a++) { 9410 PetscInt p; 9411 9412 p = anchors[a]; 9413 if (p >= pStart && p < pEnd) { 9414 PetscInt dof; 9415 9416 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9417 if (dof) { 9418 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9419 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Point %" PetscInt_FMT " cannot be constrained and an anchor", p); 9420 } 9421 } 9422 } 9423 PetscCall(ISRestoreIndices(anchorIS, &anchors)); 9424 } 9425 /* reset the generic constraints */ 9426 PetscCall(DMSetDefaultConstraints(dm, NULL, NULL, NULL)); 9427 PetscFunctionReturn(0); 9428 } 9429 9430 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) { 9431 PetscSection anchorSection; 9432 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9433 9434 PetscFunctionBegin; 9435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9436 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9437 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, cSec)); 9438 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9439 if (numFields) { 9440 PetscInt f; 9441 PetscCall(PetscSectionSetNumFields(*cSec, numFields)); 9442 9443 for (f = 0; f < numFields; f++) { 9444 PetscInt numComp; 9445 9446 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 9447 PetscCall(PetscSectionSetFieldComponents(*cSec, f, numComp)); 9448 } 9449 } 9450 PetscCall(PetscSectionGetChart(anchorSection, &pStart, &pEnd)); 9451 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9452 pStart = PetscMax(pStart, sStart); 9453 pEnd = PetscMin(pEnd, sEnd); 9454 pEnd = PetscMax(pStart, pEnd); 9455 PetscCall(PetscSectionSetChart(*cSec, pStart, pEnd)); 9456 for (p = pStart; p < pEnd; p++) { 9457 PetscCall(PetscSectionGetDof(anchorSection, p, &dof)); 9458 if (dof) { 9459 PetscCall(PetscSectionGetDof(section, p, &dof)); 9460 PetscCall(PetscSectionSetDof(*cSec, p, dof)); 9461 for (f = 0; f < numFields; f++) { 9462 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 9463 PetscCall(PetscSectionSetFieldDof(*cSec, p, f, dof)); 9464 } 9465 } 9466 } 9467 PetscCall(PetscSectionSetUp(*cSec)); 9468 PetscCall(PetscObjectSetName((PetscObject)*cSec, "Constraint Section")); 9469 PetscFunctionReturn(0); 9470 } 9471 9472 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) { 9473 PetscSection aSec; 9474 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9475 const PetscInt *anchors; 9476 PetscInt numFields, f; 9477 IS aIS; 9478 MatType mtype; 9479 PetscBool iscuda, iskokkos; 9480 9481 PetscFunctionBegin; 9482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9483 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9484 PetscCall(PetscSectionGetStorageSize(section, &n)); 9485 PetscCall(MatCreate(PETSC_COMM_SELF, cMat)); 9486 PetscCall(MatSetSizes(*cMat, m, n, m, n)); 9487 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJCUSPARSE, &iscuda)); 9488 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJCUSPARSE, &iscuda)); 9489 PetscCall(PetscStrcmp(dm->mattype, MATSEQAIJKOKKOS, &iskokkos)); 9490 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype, MATMPIAIJKOKKOS, &iskokkos)); 9491 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9492 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9493 else mtype = MATSEQAIJ; 9494 PetscCall(MatSetType(*cMat, mtype)); 9495 PetscCall(DMPlexGetAnchors(dm, &aSec, &aIS)); 9496 PetscCall(ISGetIndices(aIS, &anchors)); 9497 /* cSec will be a subset of aSec and section */ 9498 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 9499 PetscCall(PetscSectionGetChart(section, &sStart, &sEnd)); 9500 PetscCall(PetscMalloc1(m + 1, &i)); 9501 i[0] = 0; 9502 PetscCall(PetscSectionGetNumFields(section, &numFields)); 9503 for (p = pStart; p < pEnd; p++) { 9504 PetscInt rDof, rOff, r; 9505 9506 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9507 if (!rDof) continue; 9508 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9509 if (numFields) { 9510 for (f = 0; f < numFields; f++) { 9511 annz = 0; 9512 for (r = 0; r < rDof; r++) { 9513 a = anchors[rOff + r]; 9514 if (a < sStart || a >= sEnd) continue; 9515 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9516 annz += aDof; 9517 } 9518 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9519 PetscCall(PetscSectionGetFieldOffset(cSec, p, f, &off)); 9520 for (q = 0; q < dof; q++) { i[off + q + 1] = i[off + q] + annz; } 9521 } 9522 } else { 9523 annz = 0; 9524 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9525 for (q = 0; q < dof; q++) { 9526 a = anchors[rOff + q]; 9527 if (a < sStart || a >= sEnd) continue; 9528 PetscCall(PetscSectionGetDof(section, a, &aDof)); 9529 annz += aDof; 9530 } 9531 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 9532 PetscCall(PetscSectionGetOffset(cSec, p, &off)); 9533 for (q = 0; q < dof; q++) { i[off + q + 1] = i[off + q] + annz; } 9534 } 9535 } 9536 nnz = i[m]; 9537 PetscCall(PetscMalloc1(nnz, &j)); 9538 offset = 0; 9539 for (p = pStart; p < pEnd; p++) { 9540 if (numFields) { 9541 for (f = 0; f < numFields; f++) { 9542 PetscCall(PetscSectionGetFieldDof(cSec, p, f, &dof)); 9543 for (q = 0; q < dof; q++) { 9544 PetscInt rDof, rOff, r; 9545 PetscCall(PetscSectionGetDof(aSec, p, &rDof)); 9546 PetscCall(PetscSectionGetOffset(aSec, p, &rOff)); 9547 for (r = 0; r < rDof; r++) { 9548 PetscInt s; 9549 9550 a = anchors[rOff + r]; 9551 if (a < sStart || a >= sEnd) continue; 9552 PetscCall(PetscSectionGetFieldDof(section, a, f, &aDof)); 9553 PetscCall(PetscSectionGetFieldOffset(section, a, f, &aOff)); 9554 for (s = 0; s < aDof; s++) { j[offset++] = aOff + s; } 9555 } 9556 } 9557 } 9558 } else { 9559 PetscCall(PetscSectionGetDof(cSec, p, &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(PetscSectionGetDof(section, a, &aDof)); 9570 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 9571 for (s = 0; s < aDof; s++) { j[offset++] = aOff + s; } 9572 } 9573 } 9574 } 9575 } 9576 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat, i, j, NULL)); 9577 PetscCall(PetscFree(i)); 9578 PetscCall(PetscFree(j)); 9579 PetscCall(ISRestoreIndices(aIS, &anchors)); 9580 PetscFunctionReturn(0); 9581 } 9582 9583 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) { 9584 DM_Plex *plex = (DM_Plex *)dm->data; 9585 PetscSection anchorSection, section, cSec; 9586 Mat cMat; 9587 9588 PetscFunctionBegin; 9589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9590 PetscCall(DMPlexGetAnchors(dm, &anchorSection, NULL)); 9591 if (anchorSection) { 9592 PetscInt Nf; 9593 9594 PetscCall(DMGetLocalSection(dm, §ion)); 9595 PetscCall(DMPlexCreateConstraintSection_Anchors(dm, section, &cSec)); 9596 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm, section, cSec, &cMat)); 9597 PetscCall(DMGetNumFields(dm, &Nf)); 9598 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm, section, cSec, cMat)); 9599 PetscCall(DMSetDefaultConstraints(dm, cSec, cMat, NULL)); 9600 PetscCall(PetscSectionDestroy(&cSec)); 9601 PetscCall(MatDestroy(&cMat)); 9602 } 9603 PetscFunctionReturn(0); 9604 } 9605 9606 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) { 9607 IS subis; 9608 PetscSection section, subsection; 9609 9610 PetscFunctionBegin; 9611 PetscCall(DMGetLocalSection(dm, §ion)); 9612 PetscCheck(section, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9613 PetscCheck(subdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9614 /* Create subdomain */ 9615 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9616 /* Create submodel */ 9617 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9618 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9619 PetscCall(DMSetLocalSection(*subdm, subsection)); 9620 PetscCall(PetscSectionDestroy(&subsection)); 9621 PetscCall(DMCopyDisc(dm, *subdm)); 9622 /* Create map from submodel to global model */ 9623 if (is) { 9624 PetscSection sectionGlobal, subsectionGlobal; 9625 IS spIS; 9626 const PetscInt *spmap; 9627 PetscInt *subIndices; 9628 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9629 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9630 9631 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9632 PetscCall(ISGetIndices(spIS, &spmap)); 9633 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9634 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9635 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9636 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9637 for (p = pStart; p < pEnd; ++p) { 9638 PetscInt gdof, pSubSize = 0; 9639 9640 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9641 if (gdof > 0) { 9642 for (f = 0; f < Nf; ++f) { 9643 PetscInt fdof, fcdof; 9644 9645 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9646 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9647 pSubSize += fdof - fcdof; 9648 } 9649 subSize += pSubSize; 9650 if (pSubSize) { 9651 if (bs < 0) { 9652 bs = pSubSize; 9653 } else if (bs != pSubSize) { 9654 /* Layout does not admit a pointwise block size */ 9655 bs = 1; 9656 } 9657 } 9658 } 9659 } 9660 /* Must have same blocksize on all procs (some might have no points) */ 9661 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 9662 bsLocal[1] = bs; 9663 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 9664 if (bsMinMax[0] != bsMinMax[1]) { 9665 bs = 1; 9666 } else { 9667 bs = bsMinMax[0]; 9668 } 9669 PetscCall(PetscMalloc1(subSize, &subIndices)); 9670 for (p = pStart; p < pEnd; ++p) { 9671 PetscInt gdof, goff; 9672 9673 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9674 if (gdof > 0) { 9675 const PetscInt point = spmap[p]; 9676 9677 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9678 for (f = 0; f < Nf; ++f) { 9679 PetscInt fdof, fcdof, fc, f2, poff = 0; 9680 9681 /* Can get rid of this loop by storing field information in the global section */ 9682 for (f2 = 0; f2 < f; ++f2) { 9683 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9684 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9685 poff += fdof - fcdof; 9686 } 9687 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9688 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9689 for (fc = 0; fc < fdof - fcdof; ++fc, ++subOff) { subIndices[subOff] = goff + poff + fc; } 9690 } 9691 } 9692 } 9693 PetscCall(ISRestoreIndices(spIS, &spmap)); 9694 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9695 if (bs > 1) { 9696 /* We need to check that the block size does not come from non-contiguous fields */ 9697 PetscInt i, j, set = 1; 9698 for (i = 0; i < subSize; i += bs) { 9699 for (j = 0; j < bs; ++j) { 9700 if (subIndices[i + j] != subIndices[i] + j) { 9701 set = 0; 9702 break; 9703 } 9704 } 9705 } 9706 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9707 } 9708 /* Attach nullspace */ 9709 for (f = 0; f < Nf; ++f) { 9710 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9711 if ((*subdm)->nullspaceConstructors[f]) break; 9712 } 9713 if (f < Nf) { 9714 MatNullSpace nullSpace; 9715 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9716 9717 PetscCall(PetscObjectCompose((PetscObject)*is, "nullspace", (PetscObject)nullSpace)); 9718 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9719 } 9720 } 9721 PetscFunctionReturn(0); 9722 } 9723 9724 /*@ 9725 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9726 9727 Input Parameter: 9728 - dm - The DM 9729 9730 Level: developer 9731 9732 Options Database Keys: 9733 . -dm_plex_monitor_throughput - Activate the monitor 9734 9735 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9736 @*/ 9737 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) { 9738 #if defined(PETSC_USE_LOG) 9739 PetscStageLog stageLog; 9740 PetscLogEvent event; 9741 PetscLogStage stage; 9742 PetscEventPerfInfo eventInfo; 9743 PetscReal cellRate, flopRate; 9744 PetscInt cStart, cEnd, Nf, N; 9745 const char *name; 9746 #endif 9747 9748 PetscFunctionBegin; 9749 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9750 #if defined(PETSC_USE_LOG) 9751 PetscCall(PetscObjectGetName((PetscObject)dm, &name)); 9752 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9753 PetscCall(DMGetNumFields(dm, &Nf)); 9754 PetscCall(PetscLogGetStageLog(&stageLog)); 9755 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9756 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9757 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9758 N = (cEnd - cStart) * Nf * eventInfo.count; 9759 flopRate = eventInfo.flops / eventInfo.time; 9760 cellRate = N / eventInfo.time; 9761 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))); 9762 #else 9763 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9764 #endif 9765 PetscFunctionReturn(0); 9766 } 9767